From 4ca09b6c193c5288002a2ed8ef35b0fd6b872b9f Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sat, 1 Apr 2023 09:41:37 -0500 Subject: [PATCH 01/10] Add B2Deps generator for integration with b2 build system. --- conan/tools/b2/__init__.py | 1 + conan/tools/b2/b2deps.py | 329 ++++++++++++++++++ conan/tools/b2/util.py | 145 ++++++++ conans/client/generators/__init__.py | 1 + conans/test/unittests/tools/b2/__init__.py | 0 conans/test/unittests/tools/b2/test_b2deps.py | 57 +++ 6 files changed, 533 insertions(+) create mode 100644 conan/tools/b2/__init__.py create mode 100644 conan/tools/b2/b2deps.py create mode 100644 conan/tools/b2/util.py create mode 100644 conans/test/unittests/tools/b2/__init__.py create mode 100644 conans/test/unittests/tools/b2/test_b2deps.py diff --git a/conan/tools/b2/__init__.py b/conan/tools/b2/__init__.py new file mode 100644 index 00000000000..92de533fd77 --- /dev/null +++ b/conan/tools/b2/__init__.py @@ -0,0 +1 @@ +from conan.tools.b2.b2deps import B2Deps diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py new file mode 100644 index 00000000000..bb67f50a2ce --- /dev/null +++ b/conan/tools/b2/b2deps.py @@ -0,0 +1,329 @@ +from conan.internal import check_duplicated_generator +from conan.tools.b2.util import * +from conans.errors import ConanException +from conans.util.files import save, chdir +from conans.paths import get_conan_user_home +from hashlib import md5 + + +class B2Deps(object): + + def __init__(self, conanfile): + self._conanfile = conanfile + self._conanhome = get_conan_user_home() + + def generate(self): + """ + This method will save the generated files to the conanfile.generators_folder + """ + source_folder = self._conanfile.source_folder + self._conanfile.output.highlight(f"Writing B2Deps to {source_folder}") + with chdir(source_folder): + check_duplicated_generator(self, self._conanfile) + generator_files = self.content + for generator_file, content in generator_files.items(): + save(generator_file, content) + + @property + def content(self): + """ + Generates two content files: conanbuildinfo.jam and + conanbuildinfo-ID.jam which the former defines sub-projects for each + package and loads the other files and the latter define variables and + targets for the packages. + """ + self._content = {} + self._content_conanbuildinfo_jam() + self._content_conanbuildinfo_variation_jam() + for ck in self._content.keys(): + self._content[ck] = self._conanbuildinfo_header_text+"\n"+self._content[ck] + return self._content + + def _content_conanbuildinfo_jam(self): + # Generate the common conanbuildinfo.jam which does four things: + # + # Defines common utility functions to make the rest of the code short + # and includes the conanbuildinfo-*.jam sub-files. + cbi = [self._conanbuildinfo_common_text] + # The combined text. + self._content['conanbuildinfo.jam'] = "\n".join(cbi) + + def _content_conanbuildinfo_variation_jam(self): + # Generate the current build variation conanbuildinfo-/variation/.jam. + for require, dependency in self._conanfile.dependencies.items(): + # Only generate defs for direct dependencies. + if not require.direct: + continue + # The base name of the dependency. + dep_name = dependency.ref.name + # B2 equivalent of the dependency name. We keep all names lower case. + dep_name_b2 = dep_name.lower() + # The dependency cpp_info. We need to consider that there's a + # "_depname" component. Such components are a kludge to appease + # cmake generators and will eventually go away. This special + # component holds the real root definitions of the dependency. + dep_cpp_info = dependency.cpp_info + if '_'+dep_name in dep_cpp_info.components: + dep_cpp_info = dep_cpp_info.components['_'+dep_name] + # The settings the dependency requires, i.e. finds relevant. + dep_settings = dependency.settings + # The variant specific file to add this dependency to. + dep_variant_jam = B2Deps._conanbuildinfo_variation_jam(dep_settings) + if not dep_variant_jam in self._content: + self._content[dep_variant_jam] = "" + # Declare/define the local project for the dependency. + cbiv = [ + f'# {dependency.pref}', + f'pkg-project {dep_name_b2} ;'] + # Declare any system libs that we refer to (in usage requirements). + system_libs = set(dependency.cpp_info.system_libs) + for name, component in dependency.cpp_info.get_sorted_components().items(): + system_libs |= set(component.system_libs) + cbiv += self._content_conanbuildinfo_variation_declare_syslibs( + dep_name_b2, system_libs, settings=dep_settings) + # Declare any package libs for usage requirements. The first one is + # the main/global dependency. + cbiv += self._content_conanbuildinfo_variation_declare_libs( + dep_name_b2, dep_cpp_info, settings=dep_settings) + # Followed by any components of the dependency. But skipping the + # special _depname component. As that is already declare as the + # main/global lib. + for name, component in dependency.cpp_info.get_sorted_components().items(): + if name.lower() == '_'+dep_name_b2: + continue + cbiv += self._content_conanbuildinfo_variation_declare_libs( + dep_name_b2, component, settings=dep_settings) + # Declare the main target of the dependency. This is an alias that + # refers to all the previous targets and adds all the defines, + # flags, etc for consumers. + cbiv += self._content_conanbuildinfo_variation_declare_target( + dep_name_b2, dep_name_b2, + dep_cpp_info, + settings=dep_settings) + # Similarly declare the component targets, if any. + for name, component in dependency.cpp_info.get_sorted_components().items(): + # Again, always skipping the kludge component as it's already + # defined. + if "_"+dep_name_b2 == name.lower(): + continue + cbiv += self._content_conanbuildinfo_variation_declare_target( + dep_name_b2, name.lower(), component, settings=dep_settings) + # Add the combined text. + self._content[dep_variant_jam] += "\n".join(cbiv)+"\n" + + def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, settings=None): + name = name.lower() + cbi_libs = [] + variation = ' '.join(b2_features(B2Deps._b2_variation(settings))) + for lib in cpp_info.libs: + search = ' '.join( + [f'"{b2_path(d.replace(self._conanhome, "$(CONAN_HOME)"))}"' for d in cpp_info.libdirs+cpp_info.bindirs]) + # The lib targets are prefixed with "lib." to distinguish them + # from dependency main targets as it's often the case that the + # dependency has the same name as the library consumers link to. + cbi_libs += [ + f'pkg-lib {name}//lib.{lib} : : {lib}', + f' {variation}', + f' {search} ;'] + return cbi_libs + + def _content_conanbuildinfo_variation_declare_syslibs(self, name, systemlibs, settings=None): + name = name.lower() + cbi_libs = [] + variation = ' '.join(b2_features(self._b2_variation(settings))) + for lib in systemlibs: + # Although system libs won't collide in the names. We still prefix + # the target names with "lib." for consistency and easier reference + # in the main targets. + cbi_libs += [ + f'pkg-lib {name}//lib.{lib} : : {lib}', + f' {variation} ;'] + return cbi_libs + + def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_info, settings=None): + cbi_target = [] + # Target, no sources. The empty target is to catch incompatible build + # requirements matches by falling back to an unbuildable result. + cbi_target += [ + f'pkg-alias {name}//{target} : : no ;', + f'pkg-alias {name}//{target} : :'] + # Requirements: + cbi_target += [ + f' {" ".join(b2_features(self._b2_variation(settings)))}'] + cbi_target += [ + f' lib.{l}' for l in cpp_info.libs+cpp_info.system_libs] + # No default-build: + cbi_target += [" : :"] + # Usage-requirements: + cbi_target += [ + f' "{b2_path(d.replace(self._conanhome, "$(CONAN_HOME)"))}"' for d in cpp_info.includedirs] + cbi_target += [f' "{d}"' for d in cpp_info.defines] + cbi_target += [f' "{f}"' for f in cpp_info.cflags] + cbi_target += [f' "{f}"' for f in cpp_info.cxxflags] + cbi_target += [ + f' SHARED_LIB:"{f}"' for f in cpp_info.sharedlinkflags] + cbi_target += [f' EXE:"{f}"' for f in cpp_info.exelinkflags] + cbi_target += [" ;"] + return cbi_target + + @staticmethod + def _conanbuildinfo_variation_jam(settings): + return 'conanbuildinfo-%s.jam' % B2Deps._b2_variation_key(settings) + + @staticmethod + def _b2_variation_key(settings): + """ + A hashed key of the variation to use a UID for the variation. + """ + return md5(B2Deps._b2_variation_id(settings).encode('utf-8')).hexdigest() + + @staticmethod + def _b2_variation_id(settings): + """ + A compact single comma separated list of the variation where only the + values of the b2 variation are included in sorted by feature name order. + """ + vid = [] + b2_variation = B2Deps._b2_variation(settings) + for k in sorted(b2_variation.keys()): + if b2_variation[k]: + vid += [b2_variation[k]] + return ",".join(vid) + + @staticmethod + def _setting(settings, name, default=None, optional=True): + result = settings.get_safe(name, default) if settings else None + if not result and not optional: + raise ConanException( + "B2Deps needs 'settings.{}', but it is not defined.".format(name)) + return result + + @staticmethod + def _b2_variation(settings): + """ + Returns a map of b2 features & values as translated from conan settings + that can affect the link compatibility of libraries. + """ + _b2_variation_v = { + 'toolset': b2_toolset( + B2Deps._setting(settings, "compiler"), + B2Deps._setting(settings, "compiler.version")), + 'architecture': b2_architecture( + B2Deps._setting(settings, "arch")), + 'instruction-set': b2_instruction_set( + B2Deps._setting(settings, "arch")), + 'address-model': b2_address_model( + B2Deps._setting(settings, "arch")), + 'target-os': b2_os( + B2Deps._setting(settings, "os")), + 'variant': b2_variant( + B2Deps._setting(settings, "build_type")), + 'cxxstd': b2_cxxstd( + B2Deps._setting(settings, "cppstd")), + 'cxxstd:dialect': b2_cxxstd_dialect( + B2Deps._setting(settings, "cppstd")), + } + return _b2_variation_v + + _conanbuildinfo_header_text = """\ +#| + B2 definitions for Conan packages. This is a generated file. + Edit the corresponding conanfile.txt/py instead. +|# +""" + + _conanbuildinfo_common_text = """\ +import path ; +import project ; +import modules ; +import feature ; +import os ; + +rule pkg-project ( id ) +{ + local id-mod = [ project.find $(id:L) : . ] ; + if ! $(id-mode) + { + local parent-prj = [ project.current ] ; + local parent-mod = [ $(parent-prj).project-module ] ; + local id-location = [ path.join + [ project.attribute $(parent-mod) location ] + $(id:L) ] ; + id-mod = [ project.load $(id-location) : synthesize ] ; + project.push-current [ project.current ] ; + project.initialize $(id-mod) : $(id-location) ; + project.pop-current ; + project.inherit-attributes $(id-mod) : $(parent-mod) ; + local attributes = [ project.attributes $(id-mod) ] ; + $(attributes).set parent-module : $(parent-mod) : exact ; + if [ project.is-jamroot-module $(parent-mod) ] + { + use-project /$(id:L) : $(id:L) ; + } + } + return $(id-mod) ; +} + +rule pkg-target ( target : sources * : requirements * : default-build * : usage-requirements * ) +{ + target = [ MATCH "(.*)//(.*)" : $(target) ] ; + local id-mod = [ pkg-project $(target[1]) ] ; + project.push-current [ project.target $(id-mod) ] ; + local bt = [ BACKTRACE 1 ] ; + local rulename = [ MATCH "pkg-(.*)" : $(bt[4]) ] ; + modules.call-in $(id-mod) : + $(rulename) $(target[2]) : $(sources) : $(requirements) : $(default-build) + : $(usage-requirements) ; + project.pop-current ; +} + +IMPORT $(__name__) : pkg-target : $(__name__) : pkg-alias ; +IMPORT $(__name__) : pkg-target : $(__name__) : pkg-lib ; + +rule conan-home ( ) +{ + local conan_home = [ os.environ CONAN_HOME ] ; + if ! $(conan_home) + { + local conanrc = [ path.glob-in-parents [ path.join [ path.pwd ] "_" ] : ".conanrc" ] ; + if $(conanrc) + { + local conanrc_file = [ FILE_OPEN [ path.native $(conanrc) ] : t ] ; + conan_home = [ MATCH "^conan_home=(.*) +" ^conan_home=(.*) : $(conanrc_file) ] ; + conan_home = [ path.make $(conan_home[1]) ] ; + if [ MATCH ^(~/) : $(conan_home) ] + { + local home = [ os.home-directories ] ; + conan_home = [ path.join [ path.make $(home[1]) ] [ MATCH "^~/(.*)" : $(conan_home) ] ] ; + } + else if ! [ path.is-rooted $(conan_home) ] + { + conan_home = [ path.root $(conan_home) $(conanrc:D) ] ; + } + } + } + if ! $(conan_home) + { + local home = [ os.home-directories ] ; + conan_home = [ path.join [ path.make $(home[1]) ] .conan2 ] ; + } + return $(conan_home) ; +} + +path-constant CONAN_HOME : [ conan-home ] ; + +if ! ( relwithdebinfo in [ feature.values variant ] ) +{ + variant relwithdebinfo : : speed on full off ; +} +if ! ( minsizerel in [ feature.values variant ] ) +{ + variant minsizerel : : space off full off ; +} + +for local __cbi__ in [ GLOB $(__file__:D) : conanbuildinfo-*.jam ] +{ + include $(__cbi__) ; +} +""" diff --git a/conan/tools/b2/util.py b/conan/tools/b2/util.py new file mode 100644 index 00000000000..ac09b9bf93d --- /dev/null +++ b/conan/tools/b2/util.py @@ -0,0 +1,145 @@ +__all__ = [ + 'b2_architecture', + 'b2_instruction_set', + 'b2_address_model', + 'b2_os', + 'b2_variant', + 'b2_cxxstd', + 'b2_cxxstd_dialect', + 'b2_toolset', + 'b2_path', + 'b2_features', +] + + +def b2_architecture(conan_arch): + if not conan_arch: + return None + elif conan_arch.startswith('x86'): + return 'x86' + elif conan_arch.startswith('ppc'): + return 'power' + elif conan_arch.startswith('arm'): + return 'arm' + elif conan_arch.startswith('sparc'): + return 'sparc' + elif conan_arch.startswith('mips'): + return conan_arch + else: + return None + + +def b2_instruction_set(conan_arch): + if not conan_arch: + return None + elif conan_arch.startswith('armv6'): + return 'armv6' + elif conan_arch.startswith('armv7'): + return 'armv7' + elif conan_arch.startswith('armv7s'): + return 'armv7s' + elif conan_arch.startswith('sparcv9'): + return 'v9' + else: + return None + + +def b2_address_model(conan_arch): + if not conan_arch: + return None + elif '32' in conan_arch: + return '32' + elif '64' in conan_arch: + return '64' + elif conan_arch in ['x86', 'mips']: + return '32' + elif conan_arch in ['sparcv9']: + return '64' + elif conan_arch.startswith('arm'): + if conan_arch.startswith('armv8'): + return '64' + else: + return '32' + elif conan_arch.startswith('sparc'): + return '32' + else: + return None + + +def b2_os(conan_os): + if not conan_os: + return None + conan_os = conan_os.lower() + if conan_os.startswith('windows'): + return 'windows' + elif conan_os in ['macos', 'ios', 'watchos', 'tvos']: + return 'darwin' + elif conan_os == 'subos': + return 'solaris' + elif conan_os in ['arduino']: + return 'linux' + else: + return conan_os + + +def b2_variant(conan_build_type): + if not conan_build_type: + return None + return conan_build_type.lower() + + +def b2_cxxstd(conan_cppstd): + if not conan_cppstd: + return None + return conan_cppstd.replace('gnu', '') if conan_cppstd else None + + +def b2_cxxstd_dialect(conan_cppstd): + if not conan_cppstd: + return None + if conan_cppstd and 'gnu' in conan_cppstd: + return 'gnu' + else: + return None + + +def b2_toolset(conan_compiler, conan_compiler_version): + if not conan_compiler: + return None + toolset = conan_compiler.lower() + if 'clang' in conan_compiler: + toolset = 'clang' + elif 'sun-cc' == conan_compiler: + toolset = 'sun' + elif 'Visual Studio' == conan_compiler: + toolset = 'msvc' + elif 'intel' in conan_compiler: + toolset = 'intel' + if not conan_compiler_version: + return toolset + version = conan_compiler_version + if toolset == 'msvc': + if conan_compiler_version == '15': + version = '14.1' + else: + version = conan_compiler_version + '.0' + return toolset + '-' + version + + +def b2_path(path): + """ + Adjust a regular path to the form b2 can use in source code. + """ + return path.replace('\\', '/') + + +def b2_features(features): + """ + Generate a b2 requirements list, i.e. value list, from the given + 'features' dict. + """ + result = [] + for k, v in sorted(features.items()): + if v: + result += ['<%s>%s' % (k, v)] + return result diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py index ad9f8b88771..bdec9ccfd51 100644 --- a/conans/client/generators/__init__.py +++ b/conans/client/generators/__init__.py @@ -21,6 +21,7 @@ "IntelCC": "conan.tools.intel", "XcodeDeps": "conan.tools.apple", "XcodeToolchain": "conan.tools.apple", "PremakeDeps": "conan.tools.premake", + "B2Deps": "conan.tools.b2", } diff --git a/conans/test/unittests/tools/b2/__init__.py b/conans/test/unittests/tools/b2/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/conans/test/unittests/tools/b2/test_b2deps.py b/conans/test/unittests/tools/b2/test_b2deps.py new file mode 100644 index 00000000000..8b2c24bfae0 --- /dev/null +++ b/conans/test/unittests/tools/b2/test_b2deps.py @@ -0,0 +1,57 @@ +import mock +from mock import Mock + +from conan.tools.b2 import B2Deps +from conan import ConanFile +from conans.model.build_info import CppInfo +from conans.model.conanfile_interface import ConanFileInterface +from conans.model.dependencies import ConanFileDependencies +from conans.model.recipe_ref import RecipeReference +from conans.model.requires import Requirement +from conans.model.settings import Settings + + +def test_cpp_info_name_b2deps(): + conanfile = ConanFile() + conanfile._conan_node = Mock() + conanfile._conan_node.context = "host" + conanfile.settings = "os", "compiler", "build_type", "arch" + conanfile.settings = Settings({ + "os": ["Windows"], + "compiler": ["gcc"], + "build_type": ["Release"], + "arch": ["x86"]}) + conanfile.settings.build_type = "Release" + conanfile.settings.arch = "x86" + + cpp_info = CppInfo(set_defaults=True) + + conanfile_dep = ConanFile(None) + conanfile_dep.cpp_info = cpp_info + conanfile_dep._conan_node = Mock() + conanfile_dep._conan_node.ref = RecipeReference.loads("OriginalDepName/1.0") + conanfile_dep._conan_node.context = "host" + conanfile_dep.settings = conanfile.settings + conanfile_dep.folders.set_base_package("/path/to/folder_dep") + # necessary, as the interface doesn't do it now automatically + conanfile_dep.cpp_info.set_relative_base_folder("/path/to/folder_dep") + + # FIXME: This will run infinite loop if conanfile.dependencies.host.topological_sort. + # Move to integration test + with mock.patch('conan.ConanFile.dependencies', new_callable=mock.PropertyMock) as mock_deps: + req = Requirement(RecipeReference.loads("OriginalDepName/1.0")) + mock_deps.return_value = ConanFileDependencies({ + req: ConanFileInterface(conanfile_dep)}) + + b2deps = B2Deps(conanfile) + files = b2deps.content + for k in sorted(files.keys()): + print("\n\n{}:\n---\n{}\n---".format(k, files[k])) + variation_filename = B2Deps._conanbuildinfo_variation_jam(conanfile.settings) + assert "conanbuildinfo.jam" in files + assert variation_filename in files + variation_file = files[variation_filename] + assert 'pkg-project originaldepname ;' in variation_file + assert 'pkg-alias originaldepname//originaldepname' in variation_file + assert 'x86' in variation_file + assert 'release' in variation_file From e3f0536381d264337e4a6a35b4c28eea2f7c788e Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sat, 1 Apr 2023 13:56:03 -0500 Subject: [PATCH 02/10] Tweak doc strings for accuracy. --- conan/tools/b2/b2deps.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index bb67f50a2ce..b9a685d6b3b 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -7,6 +7,10 @@ class B2Deps(object): + """ + B2Deps generates files that are automatically loaded by the B2 build system. + The files define localized subprojects and targets for dependencies. + """ def __init__(self, conanfile): self._conanfile = conanfile @@ -14,7 +18,7 @@ def __init__(self, conanfile): def generate(self): """ - This method will save the generated files to the conanfile.generators_folder + This method will save the generated files to the conanfile.source_folder """ source_folder = self._conanfile.source_folder self._conanfile.output.highlight(f"Writing B2Deps to {source_folder}") @@ -28,9 +32,11 @@ def generate(self): def content(self): """ Generates two content files: conanbuildinfo.jam and - conanbuildinfo-ID.jam which the former defines sub-projects for each - package and loads the other files and the latter define variables and - targets for the packages. + conanbuildinfo-ID.jam. The former defines common package definition + function and include the latter conanbuildinfo-ID.jam files. The + conanbuildinfo-IS.jam files define sub-projects and targets for each + settings variation. The generated files have stable names and content. + Hence they can be added to source control. """ self._content = {} self._content_conanbuildinfo_jam() From 02be636c78ef39b1f3739b70f747799945b3a337 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 2 Apr 2023 10:37:05 -0500 Subject: [PATCH 03/10] Fix typo. --- conan/tools/b2/b2deps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index b9a685d6b3b..59fb4728f58 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -34,7 +34,7 @@ def content(self): Generates two content files: conanbuildinfo.jam and conanbuildinfo-ID.jam. The former defines common package definition function and include the latter conanbuildinfo-ID.jam files. The - conanbuildinfo-IS.jam files define sub-projects and targets for each + conanbuildinfo-ID.jam files define sub-projects and targets for each settings variation. The generated files have stable names and content. Hence they can be added to source control. """ From 97efbe6fdcc6e40bc7603fa6498865bae2379d51 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 2 Apr 2023 11:06:34 -0500 Subject: [PATCH 04/10] Generate per-dependency variation jam files. This makes it such that each dependency+variation pair generates an individual conanbuildinfo-X.jam file. This avoids loosing targets when dependencies change for the same variation. --- conan/tools/b2/b2deps.py | 9 ++++++--- conans/test/unittests/tools/b2/test_b2deps.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index 59fb4728f58..5df37153ac3 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -26,6 +26,7 @@ def generate(self): check_duplicated_generator(self, self._conanfile) generator_files = self.content for generator_file, content in generator_files.items(): + self._conanfile.output.info(f"Saved B2Deps file {generator_file}") save(generator_file, content) @property @@ -74,7 +75,8 @@ def _content_conanbuildinfo_variation_jam(self): # The settings the dependency requires, i.e. finds relevant. dep_settings = dependency.settings # The variant specific file to add this dependency to. - dep_variant_jam = B2Deps._conanbuildinfo_variation_jam(dep_settings) + dep_variant_jam = B2Deps._conanbuildinfo_variation_jam( + dep_name_b2, dep_settings) if not dep_variant_jam in self._content: self._content[dep_variant_jam] = "" # Declare/define the local project for the dependency. @@ -173,8 +175,9 @@ def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_inf return cbi_target @staticmethod - def _conanbuildinfo_variation_jam(settings): - return 'conanbuildinfo-%s.jam' % B2Deps._b2_variation_key(settings) + def _conanbuildinfo_variation_jam(name, settings): + return 'conanbuildinfo-{}-{}.jam'.format( + name, B2Deps._b2_variation_key(settings)) @staticmethod def _b2_variation_key(settings): diff --git a/conans/test/unittests/tools/b2/test_b2deps.py b/conans/test/unittests/tools/b2/test_b2deps.py index 8b2c24bfae0..d23b0cbe3e8 100644 --- a/conans/test/unittests/tools/b2/test_b2deps.py +++ b/conans/test/unittests/tools/b2/test_b2deps.py @@ -47,7 +47,7 @@ def test_cpp_info_name_b2deps(): files = b2deps.content for k in sorted(files.keys()): print("\n\n{}:\n---\n{}\n---".format(k, files[k])) - variation_filename = B2Deps._conanbuildinfo_variation_jam(conanfile.settings) + variation_filename = B2Deps._conanbuildinfo_variation_jam("originaldepname", conanfile.settings) assert "conanbuildinfo.jam" in files assert variation_filename in files variation_file = files[variation_filename] From a3ed4f5efacb1eb6eb7d57e63e5e8d0353a60c4e Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 2 Apr 2023 16:24:16 -0500 Subject: [PATCH 05/10] Add additional link relevant properties. This adds some missing features, threadapi, runtime-link, runtime-debugging, and link properties to the variation. --- conan/tools/b2/b2deps.py | 60 ++++++++++++++++++++++------------- conan/tools/b2/util.py | 68 +++++++++++++++++++++++++++++++--------- 2 files changed, 92 insertions(+), 36 deletions(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index 5df37153ac3..4944b1a9ae4 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -72,11 +72,12 @@ def _content_conanbuildinfo_variation_jam(self): dep_cpp_info = dependency.cpp_info if '_'+dep_name in dep_cpp_info.components: dep_cpp_info = dep_cpp_info.components['_'+dep_name] - # The settings the dependency requires, i.e. finds relevant. + # The settings and options the dependency requires, i.e. finds relevant. dep_settings = dependency.settings + dep_options = dependency.options # The variant specific file to add this dependency to. dep_variant_jam = B2Deps._conanbuildinfo_variation_jam( - dep_name_b2, dep_settings) + dep_name_b2, dep_settings, dep_options) if not dep_variant_jam in self._content: self._content[dep_variant_jam] = "" # Declare/define the local project for the dependency. @@ -88,11 +89,11 @@ def _content_conanbuildinfo_variation_jam(self): for name, component in dependency.cpp_info.get_sorted_components().items(): system_libs |= set(component.system_libs) cbiv += self._content_conanbuildinfo_variation_declare_syslibs( - dep_name_b2, system_libs, settings=dep_settings) + dep_name_b2, system_libs, settings=dep_settings, options=dep_options) # Declare any package libs for usage requirements. The first one is # the main/global dependency. cbiv += self._content_conanbuildinfo_variation_declare_libs( - dep_name_b2, dep_cpp_info, settings=dep_settings) + dep_name_b2, dep_cpp_info, settings=dep_settings, options=dep_options) # Followed by any components of the dependency. But skipping the # special _depname component. As that is already declare as the # main/global lib. @@ -100,14 +101,14 @@ def _content_conanbuildinfo_variation_jam(self): if name.lower() == '_'+dep_name_b2: continue cbiv += self._content_conanbuildinfo_variation_declare_libs( - dep_name_b2, component, settings=dep_settings) + dep_name_b2, component, settings=dep_settings, options=dep_options) # Declare the main target of the dependency. This is an alias that # refers to all the previous targets and adds all the defines, # flags, etc for consumers. cbiv += self._content_conanbuildinfo_variation_declare_target( dep_name_b2, dep_name_b2, dep_cpp_info, - settings=dep_settings) + settings=dep_settings, options=dep_options) # Similarly declare the component targets, if any. for name, component in dependency.cpp_info.get_sorted_components().items(): # Again, always skipping the kludge component as it's already @@ -115,14 +116,14 @@ def _content_conanbuildinfo_variation_jam(self): if "_"+dep_name_b2 == name.lower(): continue cbiv += self._content_conanbuildinfo_variation_declare_target( - dep_name_b2, name.lower(), component, settings=dep_settings) + dep_name_b2, name.lower(), component, settings=dep_settings, options=dep_options) # Add the combined text. self._content[dep_variant_jam] += "\n".join(cbiv)+"\n" - def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, settings=None): + def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, settings=None, options=None): name = name.lower() cbi_libs = [] - variation = ' '.join(b2_features(B2Deps._b2_variation(settings))) + variation = ' '.join(b2_features(B2Deps._b2_variation(settings, options))) for lib in cpp_info.libs: search = ' '.join( [f'"{b2_path(d.replace(self._conanhome, "$(CONAN_HOME)"))}"' for d in cpp_info.libdirs+cpp_info.bindirs]) @@ -135,10 +136,10 @@ def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, setting f' {search} ;'] return cbi_libs - def _content_conanbuildinfo_variation_declare_syslibs(self, name, systemlibs, settings=None): + def _content_conanbuildinfo_variation_declare_syslibs(self, name, systemlibs, settings=None, options=None): name = name.lower() cbi_libs = [] - variation = ' '.join(b2_features(self._b2_variation(settings))) + variation = ' '.join(b2_features(B2Deps._b2_variation(settings, options))) for lib in systemlibs: # Although system libs won't collide in the names. We still prefix # the target names with "lib." for consistency and easier reference @@ -148,7 +149,7 @@ def _content_conanbuildinfo_variation_declare_syslibs(self, name, systemlibs, se f' {variation} ;'] return cbi_libs - def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_info, settings=None): + def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_info, settings=None, options=None): cbi_target = [] # Target, no sources. The empty target is to catch incompatible build # requirements matches by falling back to an unbuildable result. @@ -157,7 +158,7 @@ def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_inf f'pkg-alias {name}//{target} : :'] # Requirements: cbi_target += [ - f' {" ".join(b2_features(self._b2_variation(settings)))}'] + f' {" ".join(b2_features(B2Deps._b2_variation(settings, options)))}'] cbi_target += [ f' lib.{l}' for l in cpp_info.libs+cpp_info.system_libs] # No default-build: @@ -175,25 +176,25 @@ def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_inf return cbi_target @staticmethod - def _conanbuildinfo_variation_jam(name, settings): + def _conanbuildinfo_variation_jam(name, settings, options=None): return 'conanbuildinfo-{}-{}.jam'.format( - name, B2Deps._b2_variation_key(settings)) + name, B2Deps._b2_variation_key(settings, options)) @staticmethod - def _b2_variation_key(settings): + def _b2_variation_key(settings, options=None): """ A hashed key of the variation to use a UID for the variation. """ - return md5(B2Deps._b2_variation_id(settings).encode('utf-8')).hexdigest() + return md5(B2Deps._b2_variation_id(settings, options).encode('utf-8')).hexdigest() @staticmethod - def _b2_variation_id(settings): + def _b2_variation_id(settings, options=None): """ A compact single comma separated list of the variation where only the values of the b2 variation are included in sorted by feature name order. """ vid = [] - b2_variation = B2Deps._b2_variation(settings) + b2_variation = B2Deps._b2_variation(settings, options) for k in sorted(b2_variation.keys()): if b2_variation[k]: vid += [b2_variation[k]] @@ -208,7 +209,15 @@ def _setting(settings, name, default=None, optional=True): return result @staticmethod - def _b2_variation(settings): + def _option(options, name, default=None, optional=True): + result = options.get_safe(name, default) if options else None + if not result and not optional: + raise ConanException( + "B2Deps needs 'options.{}', but it is not defined.".format(name)) + return result + + @staticmethod + def _b2_variation(settings, options=None): """ Returns a map of b2 features & values as translated from conan settings that can affect the link compatibility of libraries. @@ -224,13 +233,22 @@ def _b2_variation(settings): 'address-model': b2_address_model( B2Deps._setting(settings, "arch")), 'target-os': b2_os( - B2Deps._setting(settings, "os")), + B2Deps._setting(settings, "os"), + B2Deps._setting(settings, "os.subsystem")), 'variant': b2_variant( B2Deps._setting(settings, "build_type")), 'cxxstd': b2_cxxstd( B2Deps._setting(settings, "cppstd")), 'cxxstd:dialect': b2_cxxstd_dialect( B2Deps._setting(settings, "cppstd")), + 'threadapi': b2_threadapi( + B2Deps._setting(settings, 'compiler.threads')), + 'runtime-link': b2_runtime_link( + B2Deps._setting(settings, 'compiler.runtime')), + 'runtime-debugging': b2_runtime_debugging( + B2Deps._setting(settings, 'compiler.runtime_type')), + 'link': b2_link( + B2Deps._option(options, 'shared')), } return _b2_variation_v diff --git a/conan/tools/b2/util.py b/conan/tools/b2/util.py index ac09b9bf93d..f7248966284 100644 --- a/conan/tools/b2/util.py +++ b/conan/tools/b2/util.py @@ -1,19 +1,23 @@ __all__ = [ + 'b2_address_model', 'b2_architecture', + 'b2_cxxstd_dialect', + 'b2_cxxstd', + 'b2_features', 'b2_instruction_set', - 'b2_address_model', + 'b2_link', 'b2_os', - 'b2_variant', - 'b2_cxxstd', - 'b2_cxxstd_dialect', - 'b2_toolset', 'b2_path', - 'b2_features', + 'b2_runtime_debugging', + 'b2_runtime_link', + 'b2_threadapi', + 'b2_toolset', + 'b2_variant', ] def b2_architecture(conan_arch): - if not conan_arch: + if conan_arch is None: return None elif conan_arch.startswith('x86'): return 'x86' @@ -30,7 +34,7 @@ def b2_architecture(conan_arch): def b2_instruction_set(conan_arch): - if not conan_arch: + if conan_arch is None: return None elif conan_arch.startswith('armv6'): return 'armv6' @@ -45,7 +49,7 @@ def b2_instruction_set(conan_arch): def b2_address_model(conan_arch): - if not conan_arch: + if conan_arch is None: return None elif '32' in conan_arch: return '32' @@ -66,8 +70,8 @@ def b2_address_model(conan_arch): return None -def b2_os(conan_os): - if not conan_os: +def b2_os(conan_os, conan_os_subsystem=None): + if conan_os is None: return None conan_os = conan_os.lower() if conan_os.startswith('windows'): @@ -78,24 +82,26 @@ def b2_os(conan_os): return 'solaris' elif conan_os in ['arduino']: return 'linux' + elif conan_os == 'windows' and conan_os_subsystem == 'cygwin': + return 'cygwin' else: return conan_os def b2_variant(conan_build_type): - if not conan_build_type: + if conan_build_type is None: return None return conan_build_type.lower() def b2_cxxstd(conan_cppstd): - if not conan_cppstd: + if conan_cppstd is None: return None return conan_cppstd.replace('gnu', '') if conan_cppstd else None def b2_cxxstd_dialect(conan_cppstd): - if not conan_cppstd: + if conan_cppstd is None: return None if conan_cppstd and 'gnu' in conan_cppstd: return 'gnu' @@ -104,7 +110,7 @@ def b2_cxxstd_dialect(conan_cppstd): def b2_toolset(conan_compiler, conan_compiler_version): - if not conan_compiler: + if conan_compiler is None: return None toolset = conan_compiler.lower() if 'clang' in conan_compiler: @@ -143,3 +149,35 @@ def b2_features(features): if v: result += ['<%s>%s' % (k, v)] return result + + +def b2_threadapi(conan_compiler_threads): + if conan_compiler_threads is None: + return None + conan_compiler_threads = conan_compiler_threads.lower() + if conan_compiler_threads == 'posix': + return 'pthread' + + +def b2_runtime_link(conan_compiler_runtime): + if conan_compiler_runtime is None: + return None + if conan_compiler_runtime in ['static', 'MT', 'MTd']: + return 'static' + return 'shared' + + +def b2_runtime_debugging(conan_compiler_runtime): + if conan_compiler_runtime is None: + return None + if conan_compiler_runtime in ['Debug', 'MTd', 'MDd']: + return 'on' + return 'off' + + +def b2_link(conan_options_shared): + if conan_options_shared is None: + return None + if conan_options_shared: + return 'shared' + return 'static' From b518e01def6c1ff6bf6f4b25f34a52eed495c2b6 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 2 Apr 2023 17:01:44 -0500 Subject: [PATCH 06/10] Move variation functions to utils.py. --- conan/tools/b2/b2deps.py | 80 ++-------------------------------------- conan/tools/b2/util.py | 79 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 76 deletions(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index 4944b1a9ae4..47a1cffc516 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -123,7 +123,7 @@ def _content_conanbuildinfo_variation_jam(self): def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, settings=None, options=None): name = name.lower() cbi_libs = [] - variation = ' '.join(b2_features(B2Deps._b2_variation(settings, options))) + variation = ' '.join(b2_features(b2_variation(settings, options))) for lib in cpp_info.libs: search = ' '.join( [f'"{b2_path(d.replace(self._conanhome, "$(CONAN_HOME)"))}"' for d in cpp_info.libdirs+cpp_info.bindirs]) @@ -139,7 +139,7 @@ def _content_conanbuildinfo_variation_declare_libs(self, name, cpp_info, setting def _content_conanbuildinfo_variation_declare_syslibs(self, name, systemlibs, settings=None, options=None): name = name.lower() cbi_libs = [] - variation = ' '.join(b2_features(B2Deps._b2_variation(settings, options))) + variation = ' '.join(b2_features(b2_variation(settings, options))) for lib in systemlibs: # Although system libs won't collide in the names. We still prefix # the target names with "lib." for consistency and easier reference @@ -158,7 +158,7 @@ def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_inf f'pkg-alias {name}//{target} : :'] # Requirements: cbi_target += [ - f' {" ".join(b2_features(B2Deps._b2_variation(settings, options)))}'] + f' {" ".join(b2_features(b2_variation(settings, options)))}'] cbi_target += [ f' lib.{l}' for l in cpp_info.libs+cpp_info.system_libs] # No default-build: @@ -178,79 +178,7 @@ def _content_conanbuildinfo_variation_declare_target(self, name, target, cpp_inf @staticmethod def _conanbuildinfo_variation_jam(name, settings, options=None): return 'conanbuildinfo-{}-{}.jam'.format( - name, B2Deps._b2_variation_key(settings, options)) - - @staticmethod - def _b2_variation_key(settings, options=None): - """ - A hashed key of the variation to use a UID for the variation. - """ - return md5(B2Deps._b2_variation_id(settings, options).encode('utf-8')).hexdigest() - - @staticmethod - def _b2_variation_id(settings, options=None): - """ - A compact single comma separated list of the variation where only the - values of the b2 variation are included in sorted by feature name order. - """ - vid = [] - b2_variation = B2Deps._b2_variation(settings, options) - for k in sorted(b2_variation.keys()): - if b2_variation[k]: - vid += [b2_variation[k]] - return ",".join(vid) - - @staticmethod - def _setting(settings, name, default=None, optional=True): - result = settings.get_safe(name, default) if settings else None - if not result and not optional: - raise ConanException( - "B2Deps needs 'settings.{}', but it is not defined.".format(name)) - return result - - @staticmethod - def _option(options, name, default=None, optional=True): - result = options.get_safe(name, default) if options else None - if not result and not optional: - raise ConanException( - "B2Deps needs 'options.{}', but it is not defined.".format(name)) - return result - - @staticmethod - def _b2_variation(settings, options=None): - """ - Returns a map of b2 features & values as translated from conan settings - that can affect the link compatibility of libraries. - """ - _b2_variation_v = { - 'toolset': b2_toolset( - B2Deps._setting(settings, "compiler"), - B2Deps._setting(settings, "compiler.version")), - 'architecture': b2_architecture( - B2Deps._setting(settings, "arch")), - 'instruction-set': b2_instruction_set( - B2Deps._setting(settings, "arch")), - 'address-model': b2_address_model( - B2Deps._setting(settings, "arch")), - 'target-os': b2_os( - B2Deps._setting(settings, "os"), - B2Deps._setting(settings, "os.subsystem")), - 'variant': b2_variant( - B2Deps._setting(settings, "build_type")), - 'cxxstd': b2_cxxstd( - B2Deps._setting(settings, "cppstd")), - 'cxxstd:dialect': b2_cxxstd_dialect( - B2Deps._setting(settings, "cppstd")), - 'threadapi': b2_threadapi( - B2Deps._setting(settings, 'compiler.threads')), - 'runtime-link': b2_runtime_link( - B2Deps._setting(settings, 'compiler.runtime')), - 'runtime-debugging': b2_runtime_debugging( - B2Deps._setting(settings, 'compiler.runtime_type')), - 'link': b2_link( - B2Deps._option(options, 'shared')), - } - return _b2_variation_v + name, b2_variation_key(settings, options)) _conanbuildinfo_header_text = """\ #| diff --git a/conan/tools/b2/util.py b/conan/tools/b2/util.py index f7248966284..9d13569628f 100644 --- a/conan/tools/b2/util.py +++ b/conan/tools/b2/util.py @@ -1,3 +1,7 @@ +from conans.errors import ConanException +from hashlib import md5 +from base64 import b32hexencode + __all__ = [ 'b2_address_model', 'b2_architecture', @@ -13,6 +17,9 @@ 'b2_threadapi', 'b2_toolset', 'b2_variant', + 'b2_variation_id', + 'b2_variation_key', + 'b2_variation', ] @@ -181,3 +188,75 @@ def b2_link(conan_options_shared): if conan_options_shared: return 'shared' return 'static' + + +def _get_setting(settings, name, default=None, optional=True): + result = settings.get_safe(name, default) if settings else None + if not result and not optional: + raise ConanException( + "Need 'settings.{}', but it is not defined.".format(name)) + return result + + +def _get_option(options, name, default=None, optional=True): + result = options.get_safe(name, default) if options else None + if not result and not optional: + raise ConanException( + "Need 'options.{}', but it is not defined.".format(name)) + return result + + +def b2_variation(settings, options=None): + """ + Returns a map of b2 features & values as translated from conan settings + and options that can affect the link compatibility of libraries. + """ + _b2_variation_v = { + 'toolset': b2_toolset( + _get_setting(settings, "compiler"), + _get_setting(settings, "compiler.version")), + 'architecture': b2_architecture( + _get_setting(settings, "arch")), + 'instruction-set': b2_instruction_set( + _get_setting(settings, "arch")), + 'address-model': b2_address_model( + _get_setting(settings, "arch")), + 'target-os': b2_os( + _get_setting(settings, "os"), + _get_setting(settings, "os.subsystem")), + 'variant': b2_variant( + _get_setting(settings, "build_type")), + 'cxxstd': b2_cxxstd( + _get_setting(settings, "cppstd")), + 'cxxstd:dialect': b2_cxxstd_dialect( + _get_setting(settings, "cppstd")), + 'threadapi': b2_threadapi( + _get_setting(settings, 'compiler.threads')), + 'runtime-link': b2_runtime_link( + _get_setting(settings, 'compiler.runtime')), + 'runtime-debugging': b2_runtime_debugging( + _get_setting(settings, 'compiler.runtime_type')), + 'link': b2_link( + _get_option(options, 'shared')), + } + return _b2_variation_v + + +def b2_variation_id(settings, options=None): + """ + A compact single comma separated list of the variation are included in + sorted by feature name order. + """ + vid = [] + _b2_variation = b2_variation(settings, options) + for k in sorted(_b2_variation.keys()): + if _b2_variation[k] is not None: + vid += [k+'='+_b2_variation[k]] + return ",".join(vid) + + +def b2_variation_key(settings, options=None): + """ + A hashed key of the variation to use a UID for the variation. + """ + return b32hexencode(md5(b2_variation_id(settings, options).encode('utf-8')).digest()).decode('utf-8').lower().replace('=', '') From f3fd283932a2e52b67acd58972a78746a8ab4cf1 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 2 Apr 2023 17:35:33 -0500 Subject: [PATCH 07/10] Fix for py36 compat. --- conan/tools/b2/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conan/tools/b2/util.py b/conan/tools/b2/util.py index 9d13569628f..8cc440eeffb 100644 --- a/conan/tools/b2/util.py +++ b/conan/tools/b2/util.py @@ -1,6 +1,6 @@ from conans.errors import ConanException from hashlib import md5 -from base64 import b32hexencode +from base64 import b32encode __all__ = [ 'b2_address_model', @@ -259,4 +259,4 @@ def b2_variation_key(settings, options=None): """ A hashed key of the variation to use a UID for the variation. """ - return b32hexencode(md5(b2_variation_id(settings, options).encode('utf-8')).digest()).decode('utf-8').lower().replace('=', '') + return b32encode(md5(b2_variation_id(settings, options).encode('utf-8')).digest()).decode('utf-8').lower().replace('=', '') From 680645143a2afa11df562aa58a190ffabbd7b8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Ferdinand=20Rivera=20Morell?= Date: Sun, 16 Apr 2023 11:53:59 -0500 Subject: [PATCH 08/10] Fix typo. --- conan/tools/b2/b2deps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index 47a1cffc516..7ccbbfddcbf 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -197,7 +197,7 @@ def _conanbuildinfo_variation_jam(name, settings, options=None): rule pkg-project ( id ) { local id-mod = [ project.find $(id:L) : . ] ; - if ! $(id-mode) + if ! $(id-mod) { local parent-prj = [ project.current ] ; local parent-mod = [ $(parent-prj).project-module ] ; From 6fd4d19605bda4e03cd9ca5f3670219dca8efb07 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Thu, 8 Jun 2023 06:54:14 -0500 Subject: [PATCH 09/10] Add dep info in generated files. To help users figure out which generated files correspond to what they are building, and to tell which generated files they can remove, print out in the generated files the settings and options that match each generated file. --- conan/tools/b2/b2deps.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index 7ccbbfddcbf..adecf2786bc 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -82,7 +82,12 @@ def _content_conanbuildinfo_variation_jam(self): self._content[dep_variant_jam] = "" # Declare/define the local project for the dependency. cbiv = [ - f'# {dependency.pref}', + f'#| {dependency.pref}', + '[settings]', + dep_settings.dumps(), + '[options]', + dep_options.dumps(), + '|#', f'pkg-project {dep_name_b2} ;'] # Declare any system libs that we refer to (in usage requirements). system_libs = set(dependency.cpp_info.system_libs) From e8a6f78c51f550f5e45f29e0c0fdc5aa6e36bf28 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Thu, 8 Jun 2023 07:56:23 -0500 Subject: [PATCH 10/10] Fix to use consumer settings for gened files. The generated files, and targets, used the dependency settings to declare the b2 variants to use. That would cause problems as they don't always match the consumer settings. This fixes that aspect and renames the internal vars to make it clearer what's going on. --- conan/tools/b2/b2deps.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/conan/tools/b2/b2deps.py b/conan/tools/b2/b2deps.py index adecf2786bc..518d9f8bb63 100644 --- a/conan/tools/b2/b2deps.py +++ b/conan/tools/b2/b2deps.py @@ -73,20 +73,21 @@ def _content_conanbuildinfo_variation_jam(self): if '_'+dep_name in dep_cpp_info.components: dep_cpp_info = dep_cpp_info.components['_'+dep_name] # The settings and options the dependency requires, i.e. finds relevant. - dep_settings = dependency.settings - dep_options = dependency.options + variant_settings = self._conanfile.settings + variant_options = dependency.options # The variant specific file to add this dependency to. dep_variant_jam = B2Deps._conanbuildinfo_variation_jam( - dep_name_b2, dep_settings, dep_options) + dep_name_b2, variant_settings, variant_options) if not dep_variant_jam in self._content: self._content[dep_variant_jam] = "" # Declare/define the local project for the dependency. cbiv = [ - f'#| {dependency.pref}', + '#|', + f'{dependency.pref}', '[settings]', - dep_settings.dumps(), + variant_settings.dumps(), '[options]', - dep_options.dumps(), + variant_options.dumps(), '|#', f'pkg-project {dep_name_b2} ;'] # Declare any system libs that we refer to (in usage requirements). @@ -94,11 +95,11 @@ def _content_conanbuildinfo_variation_jam(self): for name, component in dependency.cpp_info.get_sorted_components().items(): system_libs |= set(component.system_libs) cbiv += self._content_conanbuildinfo_variation_declare_syslibs( - dep_name_b2, system_libs, settings=dep_settings, options=dep_options) + dep_name_b2, system_libs, settings=variant_settings, options=variant_options) # Declare any package libs for usage requirements. The first one is # the main/global dependency. cbiv += self._content_conanbuildinfo_variation_declare_libs( - dep_name_b2, dep_cpp_info, settings=dep_settings, options=dep_options) + dep_name_b2, dep_cpp_info, settings=variant_settings, options=variant_options) # Followed by any components of the dependency. But skipping the # special _depname component. As that is already declare as the # main/global lib. @@ -106,14 +107,14 @@ def _content_conanbuildinfo_variation_jam(self): if name.lower() == '_'+dep_name_b2: continue cbiv += self._content_conanbuildinfo_variation_declare_libs( - dep_name_b2, component, settings=dep_settings, options=dep_options) + dep_name_b2, component, settings=variant_settings, options=variant_options) # Declare the main target of the dependency. This is an alias that # refers to all the previous targets and adds all the defines, # flags, etc for consumers. cbiv += self._content_conanbuildinfo_variation_declare_target( dep_name_b2, dep_name_b2, dep_cpp_info, - settings=dep_settings, options=dep_options) + settings=variant_settings, options=variant_options) # Similarly declare the component targets, if any. for name, component in dependency.cpp_info.get_sorted_components().items(): # Again, always skipping the kludge component as it's already @@ -121,7 +122,7 @@ def _content_conanbuildinfo_variation_jam(self): if "_"+dep_name_b2 == name.lower(): continue cbiv += self._content_conanbuildinfo_variation_declare_target( - dep_name_b2, name.lower(), component, settings=dep_settings, options=dep_options) + dep_name_b2, name.lower(), component, settings=variant_settings, options=variant_options) # Add the combined text. self._content[dep_variant_jam] += "\n".join(cbiv)+"\n"