diff options
author | James <james@conan.io> | 2021-09-29 12:16:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-29 12:16:16 +0200 |
commit | f3a6e13f0b73392117af866ec619f531d1a9b0f2 (patch) | |
tree | 0d82b6e8810f090669c7c1b17d96539614fb0737 | |
parent | 7532ccc7bb2968b47310fc7a183d809cc70f7f07 (diff) |
MSBuildDeps handle build_requires executables (#9686)
* MSBuildDeps handle build_requires executables
* fix py27 error
* review
* removed unused file
-rw-r--r-- | conan/tools/cmake/cmakedeps/cmakedeps.py | 5 | ||||
-rw-r--r-- | conan/tools/microsoft/msbuilddeps.py | 77 | ||||
-rw-r--r-- | conans/test/functional/toolchains/microsoft/test_msbuilddeps.py | 129 | ||||
-rw-r--r-- | origin) | 0 |
4 files changed, 190 insertions, 21 deletions
diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py index 2e26b657..80c0bff4 100644 --- a/conan/tools/cmake/cmakedeps/cmakedeps.py +++ b/conan/tools/cmake/cmakedeps/cmakedeps.py @@ -1,5 +1,4 @@ import os -from fnmatch import fnmatch from conan.tools._check_build_profile import check_using_build_profile from conan.tools.cmake.cmakedeps.templates.config import ConfigTemplate @@ -17,6 +16,7 @@ FIND_MODE_CONFIG = "config" FIND_MODE_NONE = "none" FIND_MODE_BOTH = "both" + class CMakeDeps(object): def __init__(self, conanfile): @@ -81,7 +81,8 @@ class CMakeDeps(object): if dep.is_build_context and dep.ref.name not in self.build_context_activated: continue - cmake_find_mode = dep.new_cpp_info.get_property("cmake_find_mode", "CMakeDeps") or FIND_MODE_CONFIG + cmake_find_mode = dep.new_cpp_info.get_property("cmake_find_mode", "CMakeDeps") + cmake_find_mode = cmake_find_mode or FIND_MODE_CONFIG cmake_find_mode = cmake_find_mode.lower() # Skip from the requirement if cmake_find_mode == FIND_MODE_NONE: diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py index 9b986851..5cc1f6a4 100644 --- a/conan/tools/microsoft/msbuilddeps.py +++ b/conan/tools/microsoft/msbuilddeps.py @@ -7,7 +7,6 @@ from jinja2 import Template from conan.tools._check_build_profile import check_using_build_profile from conans.errors import ConanException -from conans.model.build_info import DepCppInfo from conans.util.files import load, save VALID_LIB_EXTENSIONS = (".so", ".lib", ".a", ".dylib", ".bc") @@ -20,16 +19,18 @@ class MSBuildDeps(object): <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup Label="ConanVariables"> <Conan{{name}}RootFolder>{{root_folder}}</Conan{{name}}RootFolder> + <Conan{{name}}BinaryDirectories>{{bin_dirs}}</Conan{{name}}BinaryDirectories> + <Conan{{name}}Dependencies>{{dependencies}}</Conan{{name}}Dependencies> + {% if host_context %} <Conan{{name}}CompilerFlags>{{compiler_flags}}</Conan{{name}}CompilerFlags> <Conan{{name}}LinkerFlags>{{linker_flags}}</Conan{{name}}LinkerFlags> <Conan{{name}}PreprocessorDefinitions>{{definitions}}</Conan{{name}}PreprocessorDefinitions> <Conan{{name}}IncludeDirectories>{{include_dirs}}</Conan{{name}}IncludeDirectories> <Conan{{name}}ResourceDirectories>{{res_dirs}}</Conan{{name}}ResourceDirectories> <Conan{{name}}LibraryDirectories>{{lib_dirs}}</Conan{{name}}LibraryDirectories> - <Conan{{name}}BinaryDirectories>{{bin_dirs}}</Conan{{name}}BinaryDirectories> <Conan{{name}}Libraries>{{libs}}</Conan{{name}}Libraries> <Conan{{name}}SystemLibs>{{system_libs}}</Conan{{name}}SystemLibs> - <Conan{{name}}Dependencies>{{dependencies}}</Conan{{name}}Dependencies> + {% endif %} </PropertyGroup> </Project> """) @@ -45,6 +46,7 @@ class MSBuildDeps(object): <ImportGroup Label="PropertySheets"> <Import Project="{{vars_filename}}"/> </ImportGroup> + {% if host_context %} <PropertyGroup> <LocalDebuggerEnvironment>PATH=%PATH%;$(Conan{{name}}BinaryDirectories)$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> @@ -73,6 +75,11 @@ class MSBuildDeps(object): <AdditionalOptions>$(Conan{{name}}CompilerFlags) %(AdditionalOptions)</AdditionalOptions> </ResourceCompile> </ItemDefinitionGroup> + {% else %} + <PropertyGroup> + <ExecutablePath>$(Conan{{name}}BinaryDirectories)$(ExecutablePath)</ExecutablePath> + </PropertyGroup> + {% endif %} </Project> """) @@ -142,7 +149,7 @@ class MSBuildDeps(object): condition = " And ".join("'$(%s)' == '%s'" % (k, v) for k, v in props) return condition - def _vars_props_file(self, name, cpp_info, deps): + def _vars_props_file(self, dep, name, cpp_info, deps, build=False): """ content for conan_vars_poco_x86_release.props, containing the variables """ @@ -151,25 +158,30 @@ class MSBuildDeps(object): ext = os.path.splitext(libname)[1] return '%s;' % libname if ext in VALID_LIB_EXTENSIONS else '%s.lib;' % libname + package_folder = dep.package_folder.replace('\\', '/')\ + .replace('$', '\\$').replace('"', '\\"') + pkg_placeholder = "$(Conan{}RootFolder)/".format(name) fields = { 'name': name, - 'root_folder': cpp_info.rootpath, - 'bin_dirs': "".join("%s;" % p for p in cpp_info.bin_paths), - 'res_dirs': "".join("%s;" % p for p in cpp_info.res_paths), - 'include_dirs': "".join("%s;" % p for p in cpp_info.include_paths), - 'lib_dirs': "".join("%s;" % p for p in cpp_info.lib_paths), + 'root_folder': package_folder, + 'bin_dirs': "".join("%s;" % (pkg_placeholder + p) for p in cpp_info.bindirs), + 'res_dirs': "".join("%s;" % (pkg_placeholder + p) for p in cpp_info.resdirs), + 'include_dirs': "".join("%s;" % (pkg_placeholder + p) for p in cpp_info.includedirs), + 'lib_dirs': "".join("%s;" % (pkg_placeholder + p) for p in cpp_info.libdirs), 'libs': "".join([add_valid_ext(lib) for lib in cpp_info.libs]), 'system_libs': "".join([add_valid_ext(sys_dep) for sys_dep in cpp_info.system_libs]), 'definitions': "".join("%s;" % d for d in cpp_info.defines), 'compiler_flags': " ".join(cpp_info.cxxflags + cpp_info.cflags), 'linker_flags': " ".join(cpp_info.sharedlinkflags), 'exe_flags': " ".join(cpp_info.exelinkflags), - 'dependencies': ";".join(deps) + 'dependencies': ";".join(deps), + 'host_context': not build } - formatted_template = Template(self._vars_props).render(**fields) + formatted_template = Template(self._vars_props, trim_blocks=True, + lstrip_blocks=True).render(**fields) return formatted_template - def _conf_props_file(self, dep_name, vars_props_name, deps): + def _conf_props_file(self, dep_name, vars_props_name, deps, build=False): """ content for conan_poco_x86_release.props, containing the activation """ @@ -185,7 +197,8 @@ class MSBuildDeps(object): ca_exclude = self.exclude_code_analysis template = Template(self._conf_props, trim_blocks=True, lstrip_blocks=True) - content_multi = template.render(name=dep_name, ca_exclude=ca_exclude, + content_multi = template.render(host_context=not build, + name=dep_name, ca_exclude=ca_exclude, vars_filename=vars_props_name, deps=deps) return content_multi @@ -232,8 +245,10 @@ class MSBuildDeps(object): dom = minidom.parseString(content_multi) import_group = dom.getElementsByTagName('ImportGroup')[0] children = import_group.getElementsByTagName("Import") - for dep in deps: + for req, dep in deps.items(): dep_name = dep.ref.name.replace(".", "_") + if req.build: + dep_name += "_build" conf_props_name = "conan_%s.props" % dep_name for node in children: if conf_props_name == node.getAttribute("Project"): @@ -261,21 +276,20 @@ class MSBuildDeps(object): general_name = "conandeps.props" conf_name = self._config_filename() condition = self._condition() - # Include all direct build_requires for host context. This might change - direct_deps = self._conanfile.dependencies.filter({"direct": True, "build": False}) + host_req = list(self._conanfile.dependencies.host.values()) test_req = list(self._conanfile.dependencies.test.values()) - result[general_name] = self._all_props_file(general_name, direct_deps.values()) for dep in host_req + test_req: dep_name = dep.ref.name dep_name = dep_name.replace(".", "_") - cpp_info = DepCppInfo(dep.cpp_info) # To account for automatic component aggregation + cpp_info = dep.new_cpp_info.copy() + cpp_info.aggregate_components() public_deps = [d.ref.name.replace(".", "_") for r, d in dep.dependencies.direct_host.items() if r.visible] # One file per configuration, with just the variables vars_props_name = "conan_%s_vars%s.props" % (dep_name, conf_name) - result[vars_props_name] = self._vars_props_file(dep_name, cpp_info, public_deps) + result[vars_props_name] = self._vars_props_file(dep, dep_name, cpp_info, public_deps) props_name = "conan_%s%s.props" % (dep_name, conf_name) result[props_name] = self._conf_props_file(dep_name, vars_props_name, public_deps) @@ -284,4 +298,29 @@ class MSBuildDeps(object): dep_content = self._dep_props_file(dep_name, file_dep_name, props_name, condition) result[file_dep_name] = dep_content + build_req = list(self._conanfile.dependencies.build.values()) + for dep in build_req: + dep_name = dep.ref.name + dep_name = dep_name.replace(".", "_") + "_build" + cpp_info = dep.new_cpp_info.copy() + cpp_info.aggregate_components() + public_deps = [d.ref.name.replace(".", "_") + for r, d in dep.dependencies.direct_host.items() if r.visible] + # One file per configuration, with just the variables + vars_props_name = "conan_%s_vars%s.props" % (dep_name, conf_name) + result[vars_props_name] = self._vars_props_file(dep, dep_name, cpp_info, public_deps, + build=True) + props_name = "conan_%s%s.props" % (dep_name, conf_name) + result[props_name] = self._conf_props_file(dep_name, vars_props_name, public_deps, + build=True) + + # The entry point for each package, it will have conditionals to the others + file_dep_name = "conan_%s.props" % dep_name + dep_content = self._dep_props_file(dep_name, file_dep_name, props_name, condition) + result[file_dep_name] = dep_content + + # Include all direct build_requires for host context. This might change + direct_deps = self._conanfile.dependencies.filter({"direct": True}) + result[general_name] = self._all_props_file(general_name, direct_deps) + return result diff --git a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py index 81c42016..63b60e1f 100644 --- a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py +++ b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py @@ -857,3 +857,132 @@ def test_private_transitive(): pkg_data_props = client.load("conan_pkg_release_x64.props") assert "conan_dep.props" not in pkg_data_props + + +@pytest.mark.skipif(platform.system() != "Windows", reason="Requires MSBuild") +def test_build_requires(): + # https://github.com/conan-io/conan/issues/9545 + client = TestClient() + package = "self.copy('*', src=str(self.settings.arch), dst='bin')" + dep = GenConanfile().with_exports("*").with_settings("arch").with_package(package) + consumer = textwrap.dedent(""" + from conans import ConanFile + from conan.tools.microsoft import MSBuild + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + build_requires = "dep/0.1" + generators = "MSBuildDeps", "MSBuildToolchain" + def build(self): + msbuild = MSBuild(self) + msbuild.build("hello.sln") + """) + hello_vcxproj = textwrap.dedent( r"""<?xml version="1.0" encoding="utf-8"?> + <Project DefaultTargets="Build" ToolsVersion="15.0" + xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{6F392A05-B151-490C-9505-B2A49720C4D9}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>MyProject</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + + <ImportGroup Label="PropertySheets"> + <Import Project="..\conandeps.props" /> + </ImportGroup> + + <PropertyGroup Label="UserMacros" /> + + <ItemGroup> + <CustomBuild Include="data.proto"> + <FileType>Document</FileType> + <Outputs>data.proto.h</Outputs> + <Command>dep1tool</Command> + </CustomBuild> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> + </Project>""") + + hello_sln = textwrap.dedent(r""" + Microsoft Visual Studio Solution File, Format Version 12.00 + # Visual Studio 15 + VisualStudioVersion = 15.0.28307.757 + MinimumVisualStudioVersion = 10.0.40219.1 + Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "MyProject\MyProject.vcxproj", "{6F392A05-B151-490C-9505-B2A49720C4D9}" + EndProject + Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x64.ActiveCfg = Release|x64 + {6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x64.Build.0 = Release|x64 + {6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x86.ActiveCfg = Release|Win32 + {6F392A05-B151-490C-9505-B2A49720C4D9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE6E462F-E299-4F9C-951A-F9404EB51521} + EndGlobalSection + EndGlobal + """) + client.save({"dep/conanfile.py": dep, + "dep/x86/dep1tool.bat": "@echo Invoking 32bit dep_1 build tool", + "dep/x86_64/dep1tool.bat": "@echo Invoking 64bit dep_1 build tool", + "consumer/conanfile.py": consumer, + "consumer/hello.sln": hello_sln, + "consumer/MyProject/MyProject.vcxproj": hello_vcxproj, + "consumer/MyProject/data.proto": "dataproto"}) + client.run("create dep dep/0.1@ -s arch=x86") + client.run("create dep dep/0.1@ -s arch=x86_64") + with client.chdir("consumer"): + client.run('install . -s compiler="Visual Studio" -s compiler.version=15 ' + " -s arch=x86_64 -s build_type=Release") + assert "dep/0.1:c0519e2d9702ec12d057bb15adb7a02baaf18107 - Cache" in client.out + deps_props = client.load("conandeps.props") + assert "conan_dep_build.props" in deps_props + client.run("build .") + assert "Invoking 64bit dep_1 build tool" in client.out + + client.run('install . -s compiler="Visual Studio" -s compiler.version=15 ' + " -s arch=x86 -s build_type=Release") + client.run("build .") + assert "Invoking 32bit dep_1 build tool" in client.out + + # Make sure it works with 2 profiles too + client.run('install . -s compiler="Visual Studio" -s compiler.version=15 ' + " -s arch=x86_64 -s build_type=Release -s:b os=Windows -s:h os=Windows") + client.run("build .") + assert "Invoking 64bit dep_1 build tool" in client.out diff --git a/origin) b/origin) deleted file mode 100644 index e69de29b..00000000 --- a/origin) +++ /dev/null |