File indexing completed on 2025-02-16 05:12:09
0001 import copy 0002 import os 0003 0004 from conans.client.build.compiler_flags import build_type_define, build_type_flags, format_defines, \ 0005 include_path_option, parallel_compiler_cl_flag, visual_runtime 0006 from conans.client.build.cppstd_flags import cppstd_from_settings, \ 0007 cppstd_flag_new as cppstd_flag 0008 from conans.client.tools.files import VALID_LIB_EXTENSIONS 0009 0010 0011 class VisualStudioBuildEnvironment(object): 0012 """ 0013 - LIB: library paths with semicolon separator 0014 - CL: /I (include paths) 0015 - _LINK_: linker options and libraries 0016 - UseEnv: True https://github.com/conan-io/conan/pull/4583 0017 0018 https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx 0019 https://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx 0020 https://msdn.microsoft.com/en-us/library/9s7c9wdw.aspx 0021 https://msdn.microsoft.com/en-us/library/6y6t9esh.aspx 0022 0023 """ 0024 def __init__(self, conanfile, with_build_type_flags=True): 0025 """ 0026 :param conanfile: ConanFile instance 0027 """ 0028 self._with_build_type_flags = with_build_type_flags 0029 0030 self._conanfile = conanfile 0031 self._settings = conanfile.settings 0032 self._deps_cpp_info = conanfile.deps_cpp_info 0033 self._runtime = self._settings.get_safe("compiler.runtime") 0034 0035 self.include_paths = conanfile.deps_cpp_info.include_paths 0036 self.lib_paths = conanfile.deps_cpp_info.lib_paths 0037 self.defines = copy.copy(conanfile.deps_cpp_info.defines) 0038 self.flags = self._configure_flags() 0039 self.cxx_flags = copy.copy(self._deps_cpp_info.cxxflags) 0040 self.link_flags = self._configure_link_flags() 0041 self.libs = conanfile.deps_cpp_info.libs 0042 self.std = self._std_cpp() 0043 self.parallel = False 0044 0045 def _configure_link_flags(self): 0046 ret = copy.copy(self._deps_cpp_info.exelinkflags) 0047 ret.extend(self._deps_cpp_info.sharedlinkflags) 0048 return ret 0049 0050 def _configure_flags(self): 0051 ret = copy.copy(self._deps_cpp_info.cflags) 0052 ret.extend(vs_build_type_flags(self._settings, with_flags=self._with_build_type_flags)) 0053 return ret 0054 0055 def _get_cl_list(self, quotes=True): 0056 # FIXME: It should be managed with the compiler_flags module 0057 # But need further investigation about the quotes and so on, so better to not break anything 0058 if quotes: 0059 ret = ['%s"%s"' % (include_path_option, lib) for lib in self.include_paths] 0060 else: 0061 ret = ['%s%s' % (include_path_option, lib) for lib in self.include_paths] 0062 0063 runtime = visual_runtime(self._runtime) 0064 if runtime: 0065 ret.append(runtime) 0066 0067 ret.extend(format_defines(self.defines)) 0068 ret.extend(self.flags) 0069 ret.extend(self.cxx_flags) 0070 0071 if self.parallel: # Build source in parallel 0072 ret.append(parallel_compiler_cl_flag(output=self._conanfile.output)) 0073 0074 if self.std: 0075 ret.append(self.std) 0076 0077 return ret 0078 0079 def _get_link_list(self): 0080 # FIXME: Conan 2.0. The libs are being added twice to visual_studio 0081 # one in the conanbuildinfo.props, and the other in the env-vars 0082 def format_lib(lib): 0083 ext = os.path.splitext(lib)[1] 0084 return lib if ext in VALID_LIB_EXTENSIONS else '%s.lib' % lib 0085 0086 ret = [flag for flag in self.link_flags] # copy 0087 ret.extend([format_lib(lib) for lib in self.libs]) 0088 0089 return ret 0090 0091 @property 0092 def vars(self): 0093 """Used in conanfile with environment_append""" 0094 flags = self._get_cl_list() 0095 link_flags = self._get_link_list() 0096 0097 cl_args = " ".join(flags) + _environ_value_prefix("CL") 0098 link_args = " ".join(link_flags) 0099 lib_paths = (";".join(['%s' % lib for lib in self.lib_paths]) + 0100 _environ_value_prefix("LIB", ";")) 0101 return {"CL": cl_args, 0102 "LIB": lib_paths, 0103 "_LINK_": link_args, 0104 "UseEnv": "True"} 0105 0106 @property 0107 def vars_dict(self): 0108 """Used in virtualbuildenvironment""" 0109 # Here we do not quote the include paths, it's going to be used by virtual environment 0110 cl = self._get_cl_list(quotes=False) 0111 link = self._get_link_list() 0112 0113 lib = [lib for lib in self.lib_paths] # copy 0114 0115 if os.environ.get("CL", None): 0116 cl.append(os.environ.get("CL")) 0117 0118 if os.environ.get("LIB", None): 0119 lib.append(os.environ.get("LIB")) 0120 0121 if os.environ.get("_LINK_", None): 0122 link.append(os.environ.get("_LINK_")) 0123 0124 ret = {"CL": cl, 0125 "LIB": lib, 0126 "_LINK_": link, 0127 "UseEnv": "True"} 0128 return ret 0129 0130 def _std_cpp(self): 0131 return vs_std_cpp(self._settings) 0132 0133 0134 def vs_build_type_flags(settings, with_flags=True): 0135 build_type = settings.get_safe("build_type") 0136 ret = [] 0137 btd = build_type_define(build_type=build_type) 0138 if btd: 0139 ret.extend(format_defines([btd])) 0140 if with_flags: 0141 # When using to build a vs project we don't want to adjust these flags 0142 btfs = build_type_flags(settings) 0143 if btfs: 0144 ret.extend(btfs) 0145 0146 return ret 0147 0148 0149 def vs_std_cpp(settings): 0150 cppstd = cppstd_from_settings(settings) 0151 if settings.get_safe("compiler") == "Visual Studio" and cppstd: 0152 flag = cppstd_flag(settings) 0153 return flag 0154 return None 0155 0156 0157 def _environ_value_prefix(var_name, prefix=" "): 0158 if os.environ.get(var_name, ""): 0159 return "%s%s" % (prefix, os.environ.get(var_name, "")) 0160 else: 0161 return ""