def test_cpp_info_merge_aggregating_components_first(): cppinfo = NewCppInfo() for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: setattr(cppinfo.components["foo"], n, ["var_{}_1".format(n), "var_{}_2".format(n)]) setattr(cppinfo.components["foo2"], n, ["var2_{}_1".format(n), "var2_{}_2".format(n)]) cppinfo.components["foo"].requires = ["foo2"] # Deterministic order other = NewCppInfo() for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: setattr(other.components["boo"], n, ["jar_{}_1".format(n), "jar_{}_2".format(n)]) setattr(other.components["boo2"], n, ["jar2_{}_1".format(n), "jar2_{}_2".format(n)]) other.components["boo"].requires = ["boo2"] # Deterministic order cppinfo.aggregate_components() other.aggregate_components() cppinfo.merge(other) for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: assert getattr(cppinfo, n) == [ "var_{}_1".format(n), "var_{}_2".format(n), "var2_{}_1".format(n), "var2_{}_2".format(n), "jar_{}_1".format(n), "jar_{}_2".format(n), "jar2_{}_1".format(n), "jar2_{}_2".format(n) ]
def _get_cpp_info(self): ret = NewCppInfo() for dep in self.ordered_deps: dep_cppinfo = dep.cpp_info.aggregated_components() # In case we have components, aggregate them, we do not support isolated # "targets" with autotools ret.merge(dep_cppinfo) return ret
def _get_cpp_info(self): ret = NewCppInfo() for dep in self._conanfile.dependencies.host.values(): dep_cppinfo = dep.cpp_info.aggregated_components() # In case we have components, aggregate them, we do not support isolated # "targets" with autotools ret.merge(dep_cppinfo) return ret
def test_components_order(): cppinfo = NewCppInfo() cppinfo.components["c1"].requires = ["c4", "OtherPackage::OtherComponent2"] cppinfo.components["c2"].requires = ["OtherPackage::OtherComponent"] cppinfo.components["c3"].requires = ["c2"] cppinfo.components["c4"].requires = ["c3"] sorted_c = list(cppinfo.get_sorted_components().keys()) assert sorted_c == ["c2", "c3", "c4", "c1"]
class AutotoolsDeps: def __init__(self, conanfile): # Set the generic objects before mapping to env vars to let the user # alter some value self._conanfile = conanfile self._cpp_info = None @property def cpp_info(self): if self._cpp_info is None: self._cpp_info = NewCppInfo() for dep in self._conanfile.dependencies.host.values(): dep_cppinfo = dep.new_cpp_info.copy() dep_cppinfo.set_relative_base_folder(dep.package_folder) # In case we have components, aggregate them, we do not support isolated # "targets" with autotools dep_cppinfo.aggregate_components() self._cpp_info.merge(dep_cppinfo) return self._cpp_info def environment(self): flags = AutoToolsDepsFlags(self._conanfile, self.cpp_info) # cpp_flags cpp_flags = [] cpp_flags.extend(flags.include_paths) cpp_flags.extend(flags.defines) # Ldflags ldflags = flags.sharedlinkflags ldflags.extend(flags.exelinkflags) ldflags.extend(flags.frameworks) ldflags.extend(flags.framework_paths) ldflags.extend(flags.lib_paths) # FIXME: Previously we had an argument "include_rpath_flags" defaulted to False ldflags.extend(flags.rpath_flags) # cflags cflags = flags.cflags cxxflags = flags.cxxflags srf = flags.sysroot if srf: cflags.append(srf) cxxflags.append(srf) ldflags.append(srf) env = Environment() env.append("CPPFLAGS", cpp_flags) env.append("LIBS", flags.libs) env.append("LDFLAGS", ldflags) env.append("CXXFLAGS", cxxflags) env.append("CFLAGS", cflags) return env def generate(self, env=None): env = env or self.environment() env.save_script("conanautotoolsdeps")
def _get_cpp_info(self): ret = NewCppInfo() for dep in self._conanfile.dependencies.host.values(): dep_cppinfo = dep.cpp_info.copy() dep_cppinfo.set_relative_base_folder(dep.package_folder) # In case we have components, aggregate them, we do not support isolated "targets" dep_cppinfo.aggregate_components() ret.merge(dep_cppinfo) return ret
def cpp_info(self): if self._cpp_info is None: self._cpp_info = NewCppInfo() for dep in self._conanfile.dependencies.host.values(): dep_cppinfo = dep.new_cpp_info.copy() dep_cppinfo.set_relative_base_folder(dep.package_folder) # In case we have components, aggregate them, we do not support isolated # "targets" with autotools dep_cppinfo.aggregate_components() self._cpp_info.merge(dep_cppinfo) return self._cpp_info
def test_component_aggregation(): cppinfo = NewCppInfo() cppinfo.includedirs = ["includedir"] cppinfo.libdirs = ["libdir"] cppinfo.srcdirs = ["srcdir"] cppinfo.bindirs = ["bindir"] cppinfo.builddirs = ["builddir"] cppinfo.frameworkdirs = ["frameworkdir"] cppinfo.components["c2"].includedirs = ["includedir_c2"] cppinfo.components["c2"].libdirs = ["libdir_c2"] cppinfo.components["c2"].srcdirs = ["srcdir_c2"] cppinfo.components["c2"].bindirs = ["bindir_c2"] cppinfo.components["c2"].builddirs = ["builddir_c2"] cppinfo.components["c2"].frameworkdirs = ["frameworkdir_c2"] cppinfo.components["c2"].cxxflags = ["cxxflags_c2"] cppinfo.components["c2"].defines = ["defines_c2"] cppinfo.components["c1"].requires = ["c2", "LIB_A::C1"] cppinfo.components["c1"].includedirs = ["includedir_c1"] cppinfo.components["c1"].libdirs = ["libdir_c1"] cppinfo.components["c1"].srcdirs = ["srcdir_c1"] cppinfo.components["c1"].bindirs = ["bindir_c1"] cppinfo.components["c1"].builddirs = ["builddir_c1"] cppinfo.components["c1"].frameworkdirs = ["frameworkdir_c1"] cppinfo.components["c1"].cxxflags = ["cxxflags_c1"] cppinfo.components["c1"].defines = ["defines_c1"] ret = cppinfo.copy() ret.aggregate_components() assert ret.includedirs == ["includedir_c1", "includedir_c2"] assert ret.libdirs == ["libdir_c1", "libdir_c2"] assert ret.srcdirs == ["srcdir_c1", "srcdir_c2"] assert ret.bindirs == ["bindir_c1", "bindir_c2"] assert ret.builddirs == ["builddir_c1", "builddir_c2"] assert ret.frameworkdirs == ["frameworkdir_c1", "frameworkdir_c2"] assert ret.cxxflags == ["cxxflags_c1", "cxxflags_c2"] assert ret.defines == ["defines_c1", "defines_c2"] # If we change the internal graph the order is different cppinfo.components["c1"].requires = [] cppinfo.components["c2"].requires = ["c1"] ret = cppinfo.copy() ret.aggregate_components() assert ret.includedirs == ["includedir_c2", "includedir_c1"] assert ret.libdirs == ["libdir_c2", "libdir_c1"] assert ret.srcdirs == ["srcdir_c2", "srcdir_c1"] assert ret.bindirs == ["bindir_c2", "bindir_c1"] assert ret.builddirs == ["builddir_c2", "builddir_c1"] assert ret.frameworkdirs == ["frameworkdir_c2", "frameworkdir_c1"]
def test_cpp_info_merge_with_components(): """If we try to merge a cpp info with another one and some of them have components, assert""" cppinfo = NewCppInfo() cppinfo.components["foo"].cxxflags = ["var"] other = NewCppInfo() other.components["foo2"].cxxflags = ["var2"] with pytest.raises(ConanException) as exc: cppinfo.merge(other) assert "Cannot aggregate two cppinfo objects with components" in str( exc.value)
def test_pc(self): tmp_dir = temp_folder() filename = os.path.join(tmp_dir, 'libastral.pc') save(filename, libastral_pc) conanfile = ConanFileMock() pkg_config = PkgConfig(conanfile, "libastral", pkg_config_path=tmp_dir) assert pkg_config.provides == "libastral = 6.6.6" assert pkg_config.version == "6.6.6" assert pkg_config.includedirs == ['/usr/local/include/libastral'] assert pkg_config.defines == ['_USE_LIBASTRAL'] assert pkg_config.libs == ['astral', 'm'] assert pkg_config.libdirs == ['/usr/local/lib/libastral'] assert pkg_config.linkflags == ['-Wl,--whole-archive'] assert pkg_config.variables['prefix'] == '/usr/local' cpp_info = NewCppInfo() pkg_config.fill_cpp_info(cpp_info, is_system=False, system_libs=["m"]) assert cpp_info.includedirs == ['/usr/local/include/libastral'] assert cpp_info.defines == ['_USE_LIBASTRAL'] assert cpp_info.libs == ['astral'] assert cpp_info.system_libs == ['m'] assert cpp_info.libdirs == ['/usr/local/lib/libastral'] assert cpp_info.sharedlinkflags == ['-Wl,--whole-archive']
def test_from_old_cppinfo_no_components(): oldcppinfo = CppInfo("ref", "/root/") for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: setattr(oldcppinfo, n, ["var_{}_1".format(n), "var_{}_2".format(n)]) cppinfo = NewCppInfo.from_old_cppinfo(oldcppinfo) assert isinstance(cppinfo, NewCppInfo) for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: assert getattr(cppinfo, n) == ["var_{}_1".format(n), "var_{}_2".format(n)]
def test_fill_old_cppinfo_simple(): """ The previous test but simpler, just with one cppinfo simulating the package layout""" package_info = NewCppInfo() package_info.libs = [] # This is explicit declaration too package_info.includedirs = ["other_include"] old_cpp = CppInfo("lib/1.0", "/root/folder") old_cpp.filter_empty = False old_cpp.libs = ["this_is_discarded"] old_cpp.libdirs = ["package_libdir"] old_cpp.cxxflags = ["package_cxxflags"] old_cpp.cflags = ["package_cflags"] old_cpp.frameworkdirs = ["package_frameworks"] fill_old_cppinfo(package_info, old_cpp) assert [e.replace("\\", "/") for e in old_cpp.lib_paths] == \ ["/root/folder/package_libdir"] assert old_cpp.cxxflags == ["package_cxxflags"] assert old_cpp.cflags == ["package_cflags"] assert old_cpp.frameworkdirs == ["package_frameworks"] assert old_cpp.libs == [] assert old_cpp.includedirs == ["other_include"]
def test_generator_properties_copy(): cppinfo = NewCppInfo() cppinfo.set_property("foo", "foo_value", "generator1") cppinfo.set_property("foo", "var_value", "generator2") cppinfo.set_property("foo2", "foo2_value", "generator1") copied = cppinfo.copy() assert copied.get_property("foo") is None assert copied.get_property("foo", "generator1") == "foo_value" assert copied.get_property("foo", "generator2") == "var_value"
def test_from_old_cppinfo_components(): oldcppinfo = CppInfo("ref", "/root/") for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: setattr(oldcppinfo.components["foo"], n, ["var_{}_1".format(n), "var_{}_2".format(n)]) setattr(oldcppinfo.components["foo2"], n, ["var2_{}_1".format(n), "var2_{}_2".format(n)]) # The names and filenames are not copied to the new model oldcppinfo.components["foo"].names["Gen"] = ["MyName"] oldcppinfo.filenames["Gen"] = ["Myfilename"] cppinfo = NewCppInfo.from_old_cppinfo(oldcppinfo) assert isinstance(cppinfo, NewCppInfo) for n in _DIRS_VAR_NAMES + _FIELD_VAR_NAMES: assert getattr(cppinfo.components["foo"], n) == ["var_{}_1".format(n), "var_{}_2".format(n)] assert getattr(cppinfo.components["foo2"], n) == ["var2_{}_1".format(n), "var2_{}_2".format(n)]
def __init__(self): self.source = NewCppInfo() self.build = NewCppInfo() self.package = NewCppInfo()
def test_cpp_info_sysroot_merge(): # If the value was already set is kept in the merge one = NewCppInfo() one.sysroot = "sys1" two = NewCppInfo() two.sysroot = "sys2" one.merge(two) assert one.sysroot == "sys1" # If the value was not set it is assigned one = NewCppInfo() two = NewCppInfo() two.sysroot = "sys2" one.merge(two) assert one.sysroot == "sys2"
def test_fill_old_cppinfo(): """The source/build have priority unless it is not declared at all""" source = NewCppInfo() source.libdirs = ["source_libdir"] source.cxxflags = ["source_cxxflags"] build = NewCppInfo() build.libdirs = ["build_libdir"] build.frameworkdirs = [ ] # An empty list is an explicit delaration with priority too build.set_property("cmake_build_modules", ["my_cmake.cmake"]) build.builddirs = ["my_build"] old_cpp = CppInfo("lib/1.0", "/root/folder") old_cpp.filter_empty = False old_cpp.libdirs = ["package_libdir"] old_cpp.cxxflags = ["package_cxxflags"] old_cpp.cflags = ["package_cflags"] old_cpp.frameworkdirs = ["package_frameworks"] full_editables = NewCppInfo() full_editables.merge(source) full_editables.merge(build) fill_old_cppinfo(full_editables, old_cpp) assert [e.replace("\\", "/") for e in old_cpp.lib_paths] == \ ["/root/folder/source_libdir", "/root/folder/build_libdir"] assert old_cpp.cxxflags == ["source_cxxflags"] assert old_cpp.cflags == ["package_cflags"] assert old_cpp.frameworkdirs == [] assert old_cpp.get_property("cmake_build_modules") assert old_cpp.builddirs == ["my_build"]
def test_component_aggregation(): cppinfo = NewCppInfo() cppinfo.includedirs = ["includedir"] cppinfo.libdirs = ["libdir"] cppinfo.srcdirs = ["srcdir"] cppinfo.bindirs = ["bindir"] cppinfo.builddirs = ["builddir"] cppinfo.frameworkdirs = ["frameworkdir"] cppinfo.set_property("foo", "bar") cppinfo.components["c2"].includedirs = ["includedir_c2"] cppinfo.components["c2"].libdirs = ["libdir_c2"] cppinfo.components["c2"].srcdirs = ["srcdir_c2"] cppinfo.components["c2"].bindirs = ["bindir_c2"] cppinfo.components["c2"].builddirs = ["builddir_c2"] cppinfo.components["c2"].frameworkdirs = ["frameworkdir_c2"] cppinfo.components["c2"].cxxflags = ["cxxflags_c2"] cppinfo.components["c2"].defines = ["defines_c2"] cppinfo.components["c2"].set_property("my_foo", ["bar", "bar2"]) cppinfo.components["c2"].set_property( "cmake_build_modules", ["build_module_c2", "build_module_c22"]) cppinfo.components["c1"].requires = ["c2", "LIB_A::C1"] cppinfo.components["c1"].includedirs = ["includedir_c1"] cppinfo.components["c1"].libdirs = ["libdir_c1"] cppinfo.components["c1"].srcdirs = ["srcdir_c1"] cppinfo.components["c1"].bindirs = ["bindir_c1"] cppinfo.components["c1"].builddirs = ["builddir_c1"] cppinfo.components["c1"].frameworkdirs = ["frameworkdir_c1"] cppinfo.components["c1"].cxxflags = ["cxxflags_c1"] cppinfo.components["c1"].defines = ["defines_c1"] cppinfo.components["c1"].set_property("my_foo", "jander") cppinfo.components["c1"].set_property("my_foo2", "bar2") ret = cppinfo.aggregated_components() assert ret.get_property("foo") == "bar" assert ret.includedirs == ["includedir_c1", "includedir_c2"] assert ret.libdirs == ["libdir_c1", "libdir_c2"] assert ret.srcdirs == ["srcdir_c1", "srcdir_c2"] assert ret.bindirs == ["bindir_c1", "bindir_c2"] assert ret.builddirs == ["builddir_c1", "builddir_c2"] assert ret.frameworkdirs == ["frameworkdir_c1", "frameworkdir_c2"] assert ret.cxxflags == ["cxxflags_c1", "cxxflags_c2"] assert ret.defines == ["defines_c1", "defines_c2"] # The properties are not aggregated because we cannot generalize the meaning of a property # that belongs to a component, it could make sense to aggregate it or not, "cmake_target_name" # for example, cannot be aggregated. But "cmake_build_modules" is aggregated. assert ret.get_property("my_foo") is None assert ret.get_property("my_foo2") is None assert ret.get_property("cmake_build_modules") == None # If we change the internal graph the order is different cppinfo.components["c1"].requires = [] cppinfo.components["c2"].requires = ["c1"] cppinfo._aggregated = None # Dirty, just to force recomputation ret = cppinfo.aggregated_components() assert ret.includedirs == ["includedir_c2", "includedir_c1"] assert ret.libdirs == ["libdir_c2", "libdir_c1"] assert ret.srcdirs == ["srcdir_c2", "srcdir_c1"] assert ret.bindirs == ["bindir_c2", "bindir_c1"] assert ret.builddirs == ["builddir_c2", "builddir_c1"] assert ret.frameworkdirs == ["frameworkdir_c2", "frameworkdir_c1"]
def _call_package_info(self, conanfile, package_folder, ref, is_editable): conanfile.cpp_info = CppInfo(conanfile.name, package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [ name for name, req in conanfile.requires.items() if not req.private and not req.override ] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts # Minimal pythonpath, not the whole context, make it 50% slower # FIXME Conan 2.0, Remove old ways of reusing python code with pythonpath(conanfile): with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) if hasattr(conanfile, "layout"): # Old cpp info without defaults (the defaults are in the new one) conanfile.cpp_info = CppInfo( conanfile.name, package_folder, default_values=CppInfoDefaultValues()) if not is_editable: conanfile.cpp.package.set_relative_base_folder( conanfile.package_folder) # Copy the infos.package into the old cppinfo fill_old_cppinfo(conanfile.cpp.package, conanfile.cpp_info) else: conanfile.cpp_info.filter_empty = False conanfile.package_info() if hasattr(conanfile, "layout") and is_editable: # Adjust the folders of the layout to consolidate the rootfolder of the # cppinfos inside # convert directory entries to be relative to the declared folders.build conanfile.cpp.build.set_relative_base_folder( conanfile.build_folder) # convert directory entries to be relative to the declared folders.source conanfile.cpp.source.set_relative_base_folder( conanfile.source_folder) full_editable_cppinfo = NewCppInfo() full_editable_cppinfo.merge(conanfile.cpp.source) full_editable_cppinfo.merge(conanfile.cpp.build) # Paste the editable cpp_info but prioritizing it, only if a # variable is not declared at build/source, the package will keep the value fill_old_cppinfo(full_editable_cppinfo, conanfile.cpp_info) if conanfile._conan_dep_cpp_info is None: try: if not is_editable and not hasattr( conanfile, "layout"): # FIXME: The default for the cppinfo from build are not the same # so this check fails when editable # FIXME: Remove when new cppinfo model. If using the layout method # the cppinfo object is filled from self.cpp.package new # model and we cannot check if the defaults have been modified # because it doesn't exist in the new model where the defaults # for the components are always empty conanfile.cpp_info._raise_incorrect_components_definition( conanfile.name, conanfile.requires) except ConanException as e: raise ConanException("%s package_info(): %s" % (str(conanfile), e)) conanfile._conan_dep_cpp_info = DepCppInfo( conanfile.cpp_info) self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def new_cpp_info(self): if not self._conan_new_cpp_info: self._conan_new_cpp_info = NewCppInfo.from_old_cppinfo(self.cpp_info) return self._conan_new_cpp_info