def __init__(self, output, runner, settings, conanfile_directory, user=None, channel=None): # User defined generators self.generators = self.generators if hasattr(self, "generators") else ["txt"] if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings) self.exports = create_exports(self) self.exports_sources = create_exports_sources(self) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() self.copy = None # initialized at runtime # an output stream (writeln, info, warn error) self.output = output # something that can run commands, as os.sytem self._runner = runner self._conanfile_directory = conanfile_directory self.package_folder = None # Assigned at runtime self._scope = None # user specified env variables self._env_values = EnvValues() # Updated at runtime, user specified -e self._user = user self._channel = channel
def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # conan_ref Pattern: list of conan_ref
def _get_env_values(env, package_env): env_values = EnvValues() for name, value in env: env_values.add(name, EnvValues.load_value(value)) for package, data in package_env.items(): for name, value in data: env_values.add(name, EnvValues.load_value(value), package) return env_values
def test_update_concat(self): env_info = EnvInfo() env_info.path.append("SOME/PATH") deps_info = DepsEnvInfo() deps_info.update(env_info, "lib") deps_info2 = DepsEnvInfo() deps_info2.update(env_info, "lib2") env = EnvValues() env.add("PATH", ["MYPATH"]) env.update(deps_info) self.assertEquals(env.env_dicts(None), ({}, {'PATH': ['MYPATH', 'SOME/PATH']})) env.update(deps_info2) self.assertEquals(env.env_dicts(None), ({}, {'PATH': ['MYPATH', 'SOME/PATH', 'SOME/PATH']}))
def _apply_inner_profile(doc, base_profile): """ :param doc: ConfigParser object from the current profile (excluding includes and vars, and with values already replaced) :param base_profile: Profile inherited, it's used as a base profile to modify it. :return: None """ def get_package_name_value(item): """Parse items like package:name=value or name=value""" package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: base_profile.package_settings[package_name][name] = value else: base_profile.settings[name] = value if doc.build_requires: # FIXME CHECKS OF DUPLICATED? for req in doc.build_requires.splitlines(): tokens = req.split(":", 1) if len(tokens) == 1: pattern, req_list = "*", req else: pattern, req_list = tokens req_list = [ConanFileReference.loads(r.strip()) for r in req_list.split(",")] base_profile.build_requires.setdefault(pattern, []).extend(req_list) if doc.scopes: base_profile.update_scopes(Scopes.from_list(doc.scopes.splitlines())) if doc.options: base_profile.options.update(OptionsValues.loads(doc.options)) base_profile.env_values.update(EnvValues.loads(doc.env))
def loads(text): parser = ConfigParser(text, ["settings", "full_settings", "options", "full_options", "requires", "full_requires", "scope", "recipe_hash", "env"], raise_unexpected_field=False) result = ConanInfo() result.settings = Values.loads(parser.settings) result.full_settings = Values.loads(parser.full_settings) result.options = OptionsValues.loads(parser.options) result.full_options = OptionsValues.loads(parser.full_options) result.full_requires = RequirementsList.loads(parser.full_requires) result.requires = RequirementsInfo(result.full_requires) result.recipe_hash = parser.recipe_hash or None # TODO: Missing handling paring of requires, but not necessary now result.env_values = EnvValues.loads(parser.env) return result
def _apply_inner_profile(doc, base_profile): """ :param doc: ConfigParser object from the current profile (excluding includes and vars, and with values already replaced) :param base_profile: Profile inherited, it's used as a base profile to modify it. :return: None """ def get_package_name_value(item): """Parse items like package:name=value or name=value""" package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: base_profile.package_settings[package_name][name] = value else: base_profile.settings[name] = value if doc.build_requires: # FIXME CHECKS OF DUPLICATED? for req in doc.build_requires.splitlines(): _load_single_build_require(base_profile, req) if doc.options: base_profile.options.update(OptionsValues.loads(doc.options)) # The env vars from the current profile (read in doc) # are updated with the included profiles (base_profile) # the current env values has priority current_env_values = EnvValues.loads(doc.env) current_env_values.update(base_profile.env_values) base_profile.env_values = current_env_values
def valid_xml_test(self, use_toolset): tempdir = temp_folder() with chdir(tempdir): settings = Settings.loads(default_settings_yml) settings.os = "Windows" settings.compiler = "Visual Studio" settings.compiler.version = "11" settings.compiler.runtime = "MD" if use_toolset: settings.compiler.toolset = "v110" conanfile = ConanFile(None, None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg/0.1@user/testing") cpp_info = CppInfo("dummy_root_folder1") conanfile.deps_cpp_info.update(cpp_info, ref.name) ref = ConanFileReference.loads("My.Fancy-Pkg_2/0.1@user/testing") cpp_info = CppInfo("dummy_root_folder2") conanfile.deps_cpp_info.update(cpp_info, ref.name) settings.arch = "x86" settings.build_type = "Debug" conanfile.settings = settings generator = VisualStudioMultiGenerator(conanfile) generator.output_path = "" content = generator.content self.assertEqual(2, len(content)) self.assertIn('conanbuildinfo_multi.props', content.keys()) self.assertIn('conanbuildinfo_debug_win32_v110.props', content.keys()) content_multi = content['conanbuildinfo_multi.props'] self.assertIn( "<Import Condition=\"'$(Configuration)' == 'Debug' " "And '$(Platform)' == 'Win32' " "And '$(PlatformToolset)' == 'v110'\" " "Project=\"conanbuildinfo_debug_win32_v110.props\"/>", content_multi) with open('conanbuildinfo_multi.props', 'w') as f: f.write(content_multi) settings.arch = "x86_64" settings.build_type = "Release" settings.compiler.version = "15" settings.compiler.toolset = "v141" conanfile.settings = settings generator = VisualStudioMultiGenerator(conanfile) generator.output_path = "" content = generator.content self.assertEqual(2, len(content)) self.assertIn('conanbuildinfo_multi.props', content.keys()) self.assertIn('conanbuildinfo_release_x64_v141.props', content.keys()) content_multi = content['conanbuildinfo_multi.props'] self.assertIn( "<Import Condition=\"'$(Configuration)' == 'Debug' " "And '$(Platform)' == 'Win32' " "And '$(PlatformToolset)' == 'v110'\" " "Project=\"conanbuildinfo_debug_win32_v110.props\"/>", content_multi) self.assertIn( "<Import Condition=\"'$(Configuration)' == 'Release' " "And '$(Platform)' == 'x64' " "And '$(PlatformToolset)' == 'v141'\" " "Project=\"conanbuildinfo_release_x64_v141.props\"/>", content_multi) os.unlink('conanbuildinfo_multi.props')
def test_model(self): env = EnvValues() env.add("Z", "1") self.assertEquals(env.env_dicts(""), ({"Z": "1"}, {})) env.add("Z", "2") self.assertEquals(env.env_dicts(""), ({"Z": "1"}, {})) env.add("B", "223") self.assertEquals(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) env.add("B", "224", "package1") self.assertEquals(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224"}, {})) env.add("A", "1", "package1") self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224", "A": "1"}, {})) self.assertEquals(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) env.add("J", "21", "package21") self.assertEquals(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224", "A": "1"}, {})) env.add("A", ["99"], "package1") self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224", "A": "1"}, {})) env.add("M", ["99"], "package1") self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224", "A": "1"}, {"M": ["99"]})) env.add("M", "100", "package1") self.assertEquals(env.env_dicts("package1"), ({"Z": "1", "B": "224", "A": "1"}, {"M": ["99", "100"]})) self.assertEquals(env.env_dicts(""), ({"Z": "1", "B": "223"}, {}))
def update_priority_test(self): env = EnvValues() env.add("VAR", "VALUE1") env2 = EnvValues() env2.add("VAR", "VALUE2") env.update(env2) # Already set by env, discarded new value self.assertEquals(env.env_dicts(None), ({'VAR': 'VALUE1'}, {})) # Updates with lists and values env = EnvValues() env.add("VAR", ["1"]) env.add("VAR", "2") self.assertEquals(env.env_dicts(None), ({}, {'VAR': ['1', '2']})) # If the first value is not a list won't append env = EnvValues() env.add("VAR", "1") env.add("VAR", ["2"]) self.assertEquals(env.env_dicts(None), ({'VAR': '1'}, {}))
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[settings]"] for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[build_requires]") for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) def update_settings(self, new_settings): """Mix the specified settings with the current profile. Specified settings are prioritized to profile""" assert(isinstance(new_settings, OrderedDict)) # apply the current profile res = copy.copy(self.settings) if new_settings: # Invalidate the current subsettings if the parent setting changes # Example: new_settings declare a different "compiler", so invalidate the current "compiler.XXX" for name, value in new_settings.items(): if "." not in name: if name in self.settings and self.settings[name] != value: for cur_name, _ in self.settings.items(): if cur_name.startswith("%s." % name): del res[cur_name] # Now merge the new values res.update(new_settings) self.settings = res def update_package_settings(self, package_settings): """Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile""" for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings)
def test_update_priority(self): env = EnvValues() env.add("VAR", "VALUE1") env2 = EnvValues() env2.add("VAR", "VALUE2") env.update(env2) # Already set by env, discarded new value self.assertEqual(env.env_dicts(None), ({'VAR': 'VALUE1'}, {})) # Updates with lists and values env = EnvValues() env.add("VAR", ["1"]) env.add("VAR", "2") self.assertEqual(env.env_dicts(None), ({}, {'VAR': ['1', '2']})) # If the first value is not a list won't append env = EnvValues() env.add("VAR", "1") env.add("VAR", ["2"]) self.assertEqual(env.env_dicts(None), ({'VAR': '1'}, {}))
def test_toolchain_linux(self, build_type, arch, cppstd, libcxx, shared, fpic): settings_mock = _MockSettings(build_type, arch, cppstd, libcxx) conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.options = {"shared": [True, False], "fPIC": [True, False]} conanfile.default_options = {"shared": shared, "fPIC": fpic} conanfile.initialize(settings_mock, EnvValues()) toolchain = MakeToolchain(conanfile) content = toolchain.content expected_template = Template( textwrap.dedent(""" # Conan generated toolchain file ifndef CONAN_TOOLCHAIN_INCLUDED CONAN_TOOLCHAIN_INCLUDED = TRUE CONAN_TC_BUILD_TYPE = {{build_type}} CONAN_TC_OS_HOST = None CONAN_TC_ARCH_HOST = {{arch_host}} CONAN_TC_TRIPLET_HOST = False CONAN_TC_OS_BUILD = Linux CONAN_TC_ARCH_BUILD = {{arch_build}} CONAN_TC_TRIPLET_BUILD = False CONAN_TC_OS_TARGET = None CONAN_TC_ARCH_TARGET = None CONAN_TC_TRIPLET_TARGET = None CONAN_TC_COMPILER = {{compiler}} CONAN_TC_COMPILER_VERSION = {{compiler_version}} CONAN_TC_COMPILER_RUNTIME = None CONAN_TC_LIBCXX = {{libcxx}} CONAN_TC_CPPSTD_FLAG = {{cppstd_flag}} CONAN_TC_ARCH_FLAG = {{arch_flag}} CONAN_TC_BUILD_TYPE_FLAGS = {{build_type_flags}} CONAN_TC_DEFINES ={{preserved_space}} CONAN_TC_SET_LIBCXX = True CONAN_TC_SET_CPPSTD = True CONAN_TC_SET_ARCH = True CONAN_TC_SET_FPIC = {{set_fpic}} CONAN_TC_SET_SHARED = {{set_shared}} CONAN_TC_CFLAGS += $(CONAN_TC_BUILD_TYPE_FLAGS) CONAN_TC_CXXFLAGS += $(CONAN_TC_BUILD_TYPE_FLAGS) ifeq ($(CONAN_TC_BUILD_TYPE),Release) CONAN_TC_DEFINES += NDEBUG endif ifeq ($(CONAN_TC_SET_LIBCXX),True) CONAN_TC_CLANG_BASED := $(if $(filter $(CONAN_TC_COMPILER),clang apple-clang),true) ifeq ($(CONAN_TC_CLANG_BASED),True) CONAN_TC_LIBSTDCXX_BASED := $(if $(filter $(CONAN_TC_LIBCXX),libstdc++ libstdc++11),true) ifeq ($(CONAN_TC_LIBSTDCXX_BASED),True) CONAN_TC_CXXFLAGS += -stdlib=libstdc++ else ifeq ($(CONAN_TC_LIBCXX),libc++) CONAN_TC_CXXFLAGS += -stdlib=libc++ endif else ifeq ($(CONAN_TC_COMPILER),sun-cc) ifeq ($(CONAN_TC_LIBCXX),libCstd) CONAN_TC_CXXFLAGS += -library=Cstd++ else ifeq ($(CONAN_TC_LIBCXX),libstdcxx) CONAN_TC_CXXFLAGS += -library=stdcxx4 else ifeq ($(CONAN_TC_LIBCXX),libstlport) CONAN_TC_CXXFLAGS += -library=stlport4 else ifeq ($(CONAN_TC_LIBCXX),libstdc++) CONAN_TC_CXXFLAGS += -library=stdcpp endif endif ifeq ($(CONAN_TC_LIBCXX),libstdc++11) CONAN_TC_DEFINES += GLIBCXX_USE_CXX11_ABI=1 else ifeq ($(CONAN_TC_LIBCXX),libstdc++) CONAN_TC_DEFINES += GLIBCXX_USE_CXX11_ABI=0 endif endif ifeq ($(CONAN_TC_SET_CPPSTD),True) CONAN_TC_CXXFLAGS += $(CONAN_TC_CPPSTD_FLAG) endif ifeq ($(CONAN_TC_SET_ARCH),True) CONAN_TC_CFLAGS += $(CONAN_TC_ARCH_FLAG) CONAN_TC_CXXFLAGS += $(CONAN_TC_ARCH_FLAG) CONAN_TC_SHARED_LINKER_FLAGS += $(CONAN_TC_ARCH_FLAG) CONAN_TC_EXE_LINKER_FLAGS += $(CONAN_TC_ARCH_FLAG) endif ifeq ($(CONAN_TC_SET_FPIC),True) CONAN_TC_CFLAGS += -fPIC CONAN_TC_CXXFLAGS += -fPIC CONAN_TC_SHARED_LINKER_FLAGS += -fPIC CONAN_TC_EXE_LINKER_FLAGS += -pie endif ifeq ($(CONAN_TC_SET_SHARED),True) CONAN_TC_LDFLAGS += -shared CONAN_TC_LDFLAGS += $(CONAN_TC_SHARED_LINKER_FLAGS) else CONAN_TC_LDFLAGS += $(CONAN_TC_EXE_LINKER_FLAGS) endif endif CONAN_TC_CPPFLAGS += $(addprefix -D,$(CONAN_TC_DEFINES)) # Call this function in your Makefile to have Conan variables added to the standard variables # Example: $(call CONAN_TC_SETUP) CONAN_TC_SETUP = \\ $(eval CFLAGS += $(CONAN_TC_CFLAGS)) ; \\ $(eval CXXFLAGS += $(CONAN_TC_CXXFLAGS)) ; \\ $(eval CPPFLAGS += $(CONAN_TC_CPPFLAGS)) ; \\ $(eval LDFLAGS += $(CONAN_TC_LDFLAGS)) ; """)) context = { "arch_host": conanfile.settings.get_safe("arch"), "arch_build": detected_architecture(), "compiler": conanfile.settings.get_safe("compiler"), "compiler_version": conanfile.settings.get_safe("compiler.version"), "arch_flag": architecture_flag(settings_mock), "cppstd_flag": cppstd_flag_new(conanfile.settings), "build_type_flags": " ".join(build_type_flags(conanfile.settings)), "build_type": build_type, "libcxx": libcxx, "set_shared": shared, "set_fpic": fpic, "preserved_space": " ", } # expected_content = expected_template.render(context) self.maxDiff = None self.assertIn(expected_content, content)
def variables_setup_test(self): conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) # Add some cpp_info for dependencies ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder1") cpp_info.defines = ["MYDEFINE1"] cpp_info.cflags.append("-Flag1=23") cpp_info.version = "1.3" cpp_info.description = "My cool description" conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder2") cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cxxflags = ["-cxxflag"] cpp_info.public_deps = ["MyPkg"] conanfile.deps_cpp_info.add(ref.name, cpp_info) # Add env_info env_info = EnvInfo() env_info.VAR1 = "env_info-value1" env_info.PATH.append("path-extended") conanfile.deps_env_info.update(env_info, "env_info_pkg") # Add user_info user_info = UserInfo() user_info.VAR1 = "user_info-value1" conanfile.deps_user_info["user_info_pkg"] = user_info # Add user_info_build conanfile.user_info_build = DepsUserInfo() user_info = UserInfo() user_info.VAR1 = "user_info_build-value1" conanfile.user_info_build["user_info_build_pkg"] = user_info generator = JsonGenerator(conanfile) json_out = generator.content parsed = json.loads(json_out) # Check dependencies dependencies = parsed["dependencies"] self.assertEqual(len(dependencies), 2) my_pkg = dependencies[0] self.assertEqual(my_pkg["name"], "MyPkg") self.assertEqual(my_pkg["description"], "My cool description") self.assertEqual(my_pkg["defines"], ["MYDEFINE1"]) # Check env_info env_info = parsed["deps_env_info"] self.assertListEqual(sorted(env_info.keys()), sorted(["VAR1", "PATH"])) self.assertEqual(env_info["VAR1"], "env_info-value1") self.assertListEqual(env_info["PATH"], ["path-extended"]) # Check user_info user_info = parsed["deps_user_info"] self.assertListEqual(list(user_info.keys()), ["user_info_pkg"]) self.assertListEqual(list(user_info["user_info_pkg"].keys()), ["VAR1"]) self.assertEqual(user_info["user_info_pkg"]["VAR1"], "user_info-value1") # Check user_info_build user_info_build = parsed["user_info_build"] self.assertListEqual(list(user_info_build.keys()), ["user_info_build_pkg"]) self.assertListEqual( list(user_info_build["user_info_build_pkg"].keys()), ["VAR1"]) self.assertEqual(user_info_build["user_info_build_pkg"]["VAR1"], "user_info_build-value1")
def variables_setup_test(self): tmp_folder1 = temp_folder() tmp_folder2 = temp_folder() save(os.path.join(tmp_folder1, "include1", "file.h"), "") save(os.path.join(tmp_folder2, "include2", "file.h"), "") save(os.path.join(tmp_folder1, "lib1", "file.a"), "") save(os.path.join(tmp_folder2, "lib2", "file.a"), "") save(os.path.join(tmp_folder1, "bin1", "file.bin"), "") save(os.path.join(tmp_folder2, "bin2", "file.bin"), "") conanfile = ConanFile(None, None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg1/0.1@lasote/stables") cpp_info = CppInfo(tmp_folder1) cpp_info.defines = ["MYDEFINE1"] cpp_info.includedirs = ['include1'] cpp_info.libdirs = ['lib1'] cpp_info.libs = ['libfoo'] cpp_info.bindirs = ['bin1'] cpp_info.version = "0.1" cpp_info.cflags = ['-fPIC'] cpp_info.cppflags = ['-fPIE'] cpp_info.sharedlinkflags = ['-framework Cocoa'] cpp_info.exelinkflags = ['-framework QuartzCore'] conanfile.deps_cpp_info.update(cpp_info, ref.name) ref = ConanFileReference.loads("MyPkg2/3.2.3@lasote/stables") cpp_info = CppInfo(tmp_folder2) cpp_info.defines = ["MYDEFINE2"] cpp_info.includedirs = ['include2'] cpp_info.libdirs = ['lib2'] cpp_info.libs = ['libbar'] cpp_info.bindirs = ['bin2'] cpp_info.version = "3.2.3" cpp_info.cflags = ['-mtune=native'] cpp_info.cppflags = ['-march=native'] cpp_info.sharedlinkflags = ['-framework AudioFoundation'] cpp_info.exelinkflags = ['-framework VideoToolbox'] conanfile.deps_cpp_info.update(cpp_info, ref.name) generator = PremakeGenerator(conanfile) content = generator.content self.assertIn('conan_cppdefines = {"MYDEFINE2", "MYDEFINE1"}', content) self.assertIn('conan_cppdefines_MyPkg1 = {"MYDEFINE1"}', content) self.assertIn('conan_cppdefines_MyPkg2 = {"MYDEFINE2"}', content) inc1 = os.path.join(tmp_folder1, 'include1').replace('\\', '/') inc2 = os.path.join(tmp_folder2, 'include2').replace('\\', '/') self.assertIn('conan_includedirs = {"%s",\n"%s"}' % (inc1, inc2), content) self.assertIn('conan_includedirs_MyPkg1 = {"%s"}' % inc1, content) self.assertIn('conan_includedirs_MyPkg2 = {"%s"}' % inc2, content) lib1 = os.path.join(tmp_folder1, 'lib1').replace('\\', '/') lib2 = os.path.join(tmp_folder2, 'lib2').replace('\\', '/') self.assertIn('conan_libdirs = {"%s",\n"%s"}' % (lib1, lib2), content) self.assertIn('conan_libdirs_MyPkg1 = {"%s"}' % lib1, content) self.assertIn('conan_libdirs_MyPkg2 = {"%s"}' % lib2, content) bin1 = os.path.join(tmp_folder1, 'bin1').replace('\\', '/') bin2 = os.path.join(tmp_folder2, 'bin2').replace('\\', '/') self.assertIn('conan_bindirs = {"%s",\n"%s"}' % (bin1, bin2), content) self.assertIn('conan_bindirs_MyPkg1 = {"%s"}' % bin1, content) self.assertIn('conan_bindirs_MyPkg2 = {"%s"}' % bin2, content) self.assertIn('conan_libs = {"libfoo", "libbar"}', content) self.assertIn('conan_libs_MyPkg1 = {"libfoo"}', content) self.assertIn('conan_libs_MyPkg2 = {"libbar"}', content) self.assertIn('conan_cflags = {"-mtune=native", "-fPIC"}', content) self.assertIn('conan_cflags_MyPkg1 = {"-fPIC"}', content) self.assertIn('conan_cflags_MyPkg2 = {"-mtune=native"}', content) self.assertIn('conan_cppflags = {"-march=native", "-fPIE"}', content) self.assertIn('conan_cppflags_MyPkg1 = {"-fPIE"}', content) self.assertIn('conan_cppflags_MyPkg2 = {"-march=native"}', content) self.assertIn( 'conan_sharedlinkflags = {"-framework AudioFoundation", "-framework Cocoa"}', content) self.assertIn('conan_sharedlinkflags_MyPkg1 = {"-framework Cocoa"}', content) self.assertIn( 'conan_sharedlinkflags_MyPkg2 = {"-framework AudioFoundation"}', content) self.assertIn( 'conan_exelinkflags = {"-framework VideoToolbox", "-framework QuartzCore"}', content) self.assertIn('conan_exelinkflags_MyPkg1 = {"-framework QuartzCore"}', content) self.assertIn( 'conan_exelinkflags_MyPkg2 = {"-framework VideoToolbox"}', content)
def pkg_config_custom_names_test(self): conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "/dummy_root_folder1") cpp_info.filter_empty = False cpp_info.name = "my_pkg" cpp_info.names["pkg_config"] = "my_pkg_custom_name" cpp_info.defines = ["MYDEFINE1"] cpp_info.cflags.append("-Flag1=23") cpp_info.version = "1.3" cpp_info.description = "My cool description" conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg1/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "/dummy_root_folder1") cpp_info.filter_empty = False cpp_info.name = "MYPKG1" cpp_info.names["pkg_config"] = "my_pkg1_custom_name" cpp_info.defines = ["MYDEFINE11"] cpp_info.cflags.append("-Flag1=21") cpp_info.version = "1.7" cpp_info.description = "My other cool description" conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "/dummy_root_folder2") cpp_info.filter_empty = False cpp_info.names["pkg_config"] = "my_pkg2_custom_name" cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cxxflags = ["-cxxflag"] cpp_info.public_deps = ["MyPkg", "MyPkg1"] conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("zlib/1.2.11@lasote/stable") cpp_info = CppInfo(ref.name, "/dummy_root_folder_zlib") cpp_info.filter_empty = False cpp_info.name = "ZLIB" cpp_info.defines = ["MYZLIBDEFINE2"] cpp_info.version = "1.2.11" conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("bzip2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "/dummy_root_folder2") cpp_info.filter_empty = False cpp_info.name = "BZip2" cpp_info.names["pkg_config"] = "BZip2" cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cxxflags = ["-cxxflag"] cpp_info.public_deps = ["MyPkg", "MyPkg1", "zlib"] conanfile.deps_cpp_info.add(ref.name, cpp_info) generator = PkgConfigGenerator(conanfile) files = generator.content self.assertEqual( files["my_pkg2_custom_name.pc"], """prefix=/dummy_root_folder2 libdir=${prefix}/lib includedir=${prefix}/include Name: my_pkg2_custom_name Description: Conan package: my_pkg2_custom_name Version: 2.3 Libs: -L${libdir} -sharedlinkflag -exelinkflag Cflags: -I${includedir} -cxxflag -DMYDEFINE2 Requires: my_pkg_custom_name my_pkg1_custom_name """) self.assertEqual( files["my_pkg1_custom_name.pc"], """prefix=/dummy_root_folder1 libdir=${prefix}/lib includedir=${prefix}/include Name: my_pkg1_custom_name Description: My other cool description Version: 1.7 Libs: -L${libdir} Cflags: -I${includedir} -Flag1=21 -DMYDEFINE11 """) self.assertEqual( files["my_pkg_custom_name.pc"], """prefix=/dummy_root_folder1 libdir=${prefix}/lib includedir=${prefix}/include Name: my_pkg_custom_name Description: My cool description Version: 1.3 Libs: -L${libdir} Cflags: -I${includedir} -Flag1=23 -DMYDEFINE1 """) self.assertEqual( files["BZip2.pc"], """prefix=/dummy_root_folder2 libdir=${prefix}/lib includedir=${prefix}/include Name: BZip2 Description: Conan package: BZip2 Version: 2.3 Libs: -L${libdir} -sharedlinkflag -exelinkflag Cflags: -I${includedir} -cxxflag -DMYDEFINE2 Requires: my_pkg_custom_name my_pkg1_custom_name zlib """)
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Input sections, as defined by user profile files and command line self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # ref pattern: list of ref self.conf = ConfDefinition() # Cached processed values self.processed_settings = None # Settings with values, and smart completion self._user_options = None self._package_settings_values = None self.dev_reference = None # Reference of the package being develop @property def user_options(self): if self._user_options is None: self._user_options = self.options.copy() return self._user_options @property def package_settings_values(self): if self._package_settings_values is None: self._package_settings_values = {} for pkg, settings in self.package_settings.items(): self._package_settings_values[pkg] = list(settings.items()) return self._package_settings_values def process_settings(self, cache, preprocess=True): assert self.processed_settings is None, "processed settings must be None" self.processed_settings = cache.settings.copy() self.processed_settings.values = Values.from_list( list(self.settings.items())) if preprocess: settings_preprocessor.preprocess(self.processed_settings) # Redefine the profile settings values with the preprocessed ones # FIXME: Simplify the values.as_list() self.settings = OrderedDict( self.processed_settings.values.as_list()) # Preprocess also scoped settings for pkg, pkg_settings in self.package_settings.items(): pkg_profile = Profile() pkg_profile.settings = self.settings pkg_profile.update_settings(pkg_settings) try: pkg_profile.process_settings(cache=cache, preprocess=True) except Exception as e: pkg_profile = [ "{}={}".format(k, v) for k, v in pkg_profile.settings.items() ] raise ConanException( "Error in resulting settings for package" " '{}': {}\n{}".format(pkg, e, '\n'.join(pkg_profile))) # TODO: Assign the _validated_ settings and do not compute again def dumps(self): result = ["[settings]"] for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[build_requires]") for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[env]") result.append(self.env_values.dumps()) if self.conf: result.append("[conf]") result.append(self.conf.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) self.conf.update_conf_definition(other.conf) def update_settings(self, new_settings): """Mix the specified settings with the current profile. Specified settings are prioritized to profile""" assert (isinstance(new_settings, OrderedDict)) # apply the current profile res = copy.copy(self.settings) if new_settings: # Invalidate the current subsettings if the parent setting changes # Example: new_settings declare a different "compiler", # so invalidate the current "compiler.XXX" for name, value in new_settings.items(): if "." not in name: if name in self.settings and self.settings[name] != value: for cur_name, _ in self.settings.items(): if cur_name.startswith("%s." % name): del res[cur_name] # Now merge the new values res.update(new_settings) self.settings = res def update_package_settings(self, package_settings): """Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile""" for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings)
class Profile(object): '''A profile contains a set of setting (with values), environment variables and scopes''' def __init__(self): # Sections self._settings = OrderedDict() self._package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() @property def package_settings(self): return {package_name: list(settings.items()) for package_name, settings in self._package_settings.items()} @property def settings(self): return list(self._settings.items()) @staticmethod def loads(text): def get_package_name_value(item): '''Parse items like package:name=value or name=value''' package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value try: obj = Profile() doc = ConfigParser(text, allowed_fields=["settings", "env", "scopes"]) for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: obj._package_settings[package_name][name] = value else: obj._settings[name] = value if doc.scopes: obj.scopes = Scopes.from_list(doc.scopes.splitlines()) obj.env_values = EnvValues.loads(doc.env) obj._order() return obj except ConanException: raise except Exception as exc: raise ConanException("Error parsing the profile text file: %s" % str(exc)) def dumps(self): self._order() # gets in order the settings def dump_simple_items(items, result): for name, value in items: result.append("%s=%s" % (name, value)) def dump_package_items(items, result): for package, values in items: for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result = ["[settings]"] dump_simple_items(self._settings.items(), result) dump_package_items(self._package_settings.items(), result) result.append("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self._settings.update(new_settings) self._order() def update_package_settings(self, package_settings): '''Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile''' for package_name, settings in self._package_settings.items(): if package_name in package_settings: settings.update(dict(package_settings[package_name])) # The rest of new packages settings for package_name, settings in package_settings.items(): if package_name not in self._package_settings: self._package_settings[package_name].update(dict(settings)) self._order() def _mix_env_with_new(self, env_dict, new_env): res_env = OrderedDict() for name, value in new_env: if name in env_dict: del env_dict[name] res_env[name] = value # Insert first in the result for name, value in env_dict.items(): res_env[name] = value # Insert the rest of env vars at the end return res_env def update_packages_env(self, new_packages_env): '''Priorize new_packages_env to override the current package_env''' if not new_packages_env: return res_env = defaultdict(OrderedDict) # Mix the common packages env for package, env_vars in self._package_env.items(): new_env = new_packages_env.get(package, []) res_env[package] = self._mix_env_with_new(env_vars, new_env) # The rest of new packages env variables for package, env_vars in new_packages_env.items(): if package not in res_env: for name, value in env_vars: res_env[package][name] = value # Insert the rest of env vars at the end self._package_env = res_env def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes) self._order() def _order(self): def order_single_settings(settings): ret = OrderedDict() # Insert in a good order for func in [lambda x: "." not in x, # First the principal settings lambda x: "." in x]: for name, value in settings.items(): if func(name): ret[name] = value return ret # Order global settings self._settings = order_single_settings(self._settings) # Order package settings for package_name, settings in self._package_settings.items(): self._package_settings[package_name] = order_single_settings(settings)
def __init__(self): # Sections self._settings = OrderedDict() self._package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes()
def setUpClass(cls): env = EnvValues() env.add("USER_FLAG", "user_value") env.add("CL", ["cl1", "cl2"]) env.add("PATH", [ "another_path", ]) env.add("PATH2", ["p1", "p2"]) env.add("PATH3", ["p1", "p2", "p1", "p3", "p4", "p2"]) conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), env) cls.generator = VirtualEnvGenerator(conanfile) cls.generator.output_path = "not-used" cls.result = cls.generator.content
class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() self.build_requires = OrderedDict() # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[build_requires]"] for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[settings]") for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) self.update_scopes(other.scopes) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) def update_package_settings(self, package_settings): '''Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile''' for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result @staticmethod def read_file(profile_name, cwd, default_folder): """ Will look for "profile_name" in disk if profile_name is absolute path, in current folder if path is relative or in the default folder otherwise. return: a Profile object """ if not profile_name: return None if os.path.isabs(profile_name): profile_path = profile_name folder = os.path.dirname(profile_name) elif profile_name.startswith("."): # relative path name profile_path = os.path.abspath(os.path.join(cwd, profile_name)) folder = os.path.dirname(profile_path) else: folder = default_folder if not os.path.exists(folder): mkdir(folder) profile_path = os.path.join(folder, profile_name) try: text = load(profile_path) except IOError: if os.path.exists(folder): profiles = [name for name in os.listdir(folder) if not os.path.isdir(name)] else: profiles = [] current_profiles = ", ".join(profiles) or "[]" raise ConanException("Specified profile '%s' doesn't exist.\nExisting profiles: " "%s" % (profile_name, current_profiles)) try: text = text.replace("$PROFILE_DIR", os.path.abspath(folder)) # Allows PYTHONPATH=$PROFILE_DIR/pythontools return Profile.loads(text) except ConanException as exc: raise ConanException("Error reading '%s' profile: %s" % (profile_name, exc)) @staticmethod def loads(text): """ Parse and return a Profile object from a text config like representation """ def get_package_name_value(item): '''Parse items like package:name=value or name=value''' package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value try: obj = Profile() doc = ConfigParser(text, allowed_fields=["settings", "env", "scopes", "options"]) for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: obj.package_settings[package_name][name] = value else: obj.settings[name] = value if doc.scopes: obj.scopes = Scopes.from_list(doc.scopes.splitlines()) if doc.options: obj.options = OptionsValues.loads(doc.options) obj.env_values = EnvValues.loads(doc.env) return obj except ConanException: raise except Exception as exc: raise ConanException("Error parsing the profile text file: %s" % str(exc)) def dumps(self): result = ["[settings]"] for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) self.update_scopes(other.scopes) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) def update_package_settings(self, package_settings): '''Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile''' for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
def variables_setup_test(self): conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder1") cpp_info.name = "my_pkg" cpp_info.defines = ["MYDEFINE1"] cpp_info.cflags.append("-Flag1=23") cpp_info.version = "1.3" cpp_info.description = "My cool description" conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg1/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder1") cpp_info.name = "MYPKG1" cpp_info.defines = ["MYDEFINE11"] cpp_info.cflags.append("-Flag1=21") cpp_info.version = "1.7" cpp_info.description = "My other cool description" cpp_info.public_deps = ["MyPkg"] conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder2") cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cxxflags = ["-cxxflag"] cpp_info.public_deps = ["MyPkg"] conanfile.deps_cpp_info.add(ref.name, cpp_info) generator = PkgConfigGenerator(conanfile) files = generator.content self.assertEqual( files["MyPkg2.pc"], """prefix=dummy_root_folder2 libdir=${prefix}/lib includedir=${prefix}/include Name: MyPkg2 Description: Conan package: MyPkg2 Version: 2.3 Libs: -L${libdir} -sharedlinkflag -exelinkflag Cflags: -I${includedir} -cxxflag -DMYDEFINE2 Requires: my_pkg """) self.assertEqual( files["mypkg1.pc"], """prefix=dummy_root_folder1 libdir=${prefix}/lib includedir=${prefix}/include Name: mypkg1 Description: My other cool description Version: 1.7 Libs: -L${libdir} Cflags: -I${includedir} -Flag1=21 -DMYDEFINE11 Requires: my_pkg """) self.assertEqual( files["my_pkg.pc"], """prefix=dummy_root_folder1 libdir=${prefix}/lib includedir=${prefix}/include Name: my_pkg Description: My cool description Version: 1.3 Libs: -L${libdir} Cflags: -I${includedir} -Flag1=23 -DMYDEFINE1 """)
def __init__(self, output, runner, settings, user=None, channel=None, local=None): # User defined generators self.generators = self.generators if hasattr( self, "generators") else ["txt"] if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings, local) try: if self.settings.os_build and self.settings.os: output.writeln("*" * 60, front=Color.BRIGHT_RED) output.writeln( " This package defines both 'os' and 'os_build' ", front=Color.BRIGHT_RED) output.writeln( " Please use 'os' for libraries and 'os_build'", front=Color.BRIGHT_RED) output.writeln( " only for build-requires used for cross-building", front=Color.BRIGHT_RED) output.writeln("*" * 60, front=Color.BRIGHT_RED) except ConanException: pass self.exports = create_exports(self) self.exports_sources = create_exports_sources(self) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() # user declared variables self.user_info = None # Keys are the package names, and the values a dict with the vars self.deps_user_info = DepsUserInfo() self.copy = None # initialized at runtime # an output stream (writeln, info, warn error) self.output = output # something that can run commands, as os.sytem self._runner = runner self.develop = False # user specified env variables self._env_values = EnvValues() # Updated at runtime, user specified -e self._user = user self._channel = channel # Are we in local cache? Suggest a better name self.in_local_cache = False # Init a description self.description = None
def test_idempotent(self): conanfile = ConanFile(Mock(), None) conanfile.initialize(Settings({}), EnvValues()) # Add some cpp_info ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder1") cpp_info.names["txt"] = "mypkg1-txt" cpp_info.version = ref.version cpp_info.defines = ["MYDEFINE1"] cpp_info.cxxflags = ["-cxxflag_parent"] cpp_info.includedirs = ["mypkg1/include"] cpp_info.filter_empty = False conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder2") cpp_info.defines = ["MYDEFINE2"] cpp_info.cxxflags = ["-cxxflag_dep"] cpp_info.filter_empty = False conanfile.deps_cpp_info.add(ref.name, cpp_info) # Add env_info env_info = EnvInfo() env_info.VAR1 = "value1" env_info.PATH.append("path-extended") conanfile.deps_env_info.update(env_info, "my_pkg") env_info = EnvInfo() env_info.VAR1 = "other-value1" env_info.PATH.append("other-path-extended") conanfile.deps_env_info.update(env_info, "other-pkg") # Add user_info for HOST user_info = UserInfo() user_info.VAR1 = "value1" conanfile.deps_user_info["my_pkg"] = user_info user_info = UserInfo() user_info.VAR1 = "other-value1" conanfile.deps_user_info["other-pkg"] = user_info # Add user_info for BUILD conanfile.user_info_build = DepsUserInfo() user_info = UserInfo() user_info.VAR1 = "value1" conanfile.user_info_build["build_pkg"] = user_info user_info = UserInfo() user_info.VAR1 = "other-value1" conanfile.user_info_build["other-build-pkg"] = user_info master_content = TXTGenerator(conanfile).content after_cpp_info, after_user_info, after_env_info, after_user_info_build = \ TXTGenerator.loads(master_content, filter_empty=False) # Assign them to a different conanfile other_conanfile = ConanFile(Mock(), None) other_conanfile.initialize(Settings({}), EnvValues()) other_conanfile.deps_cpp_info = after_cpp_info other_conanfile.deps_env_info = after_env_info other_conanfile.deps_user_info = after_user_info other_conanfile.user_info_build = after_user_info_build after_content = TXTGenerator(other_conanfile).content self.assertListEqual(master_content.splitlines(), after_content.splitlines())
def variables_setup_test(self): conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder1") cpp_info.defines = ["MYDEFINE1"] cpp_info.cflags.append("-Flag1=23") cpp_info.version = "1.3" cpp_info.description = "My cool description" cpp_info.libs = ["MyLib1"] conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo(ref.name, "dummy_root_folder2") cpp_info.libs = ["MyLib2"] cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cxxflags = ["-cxxflag"] cpp_info.public_deps = ["MyPkg"] cpp_info.libdirs.extend(["Path\\with\\slashes", "regular/path/to/dir"]) cpp_info.includedirs.extend( ["other\\Path\\with\\slashes", "other/regular/path/to/dir"]) cpp_info.filter_empty = False conanfile.deps_cpp_info.add(ref.name, cpp_info) generator = BoostBuildGenerator(conanfile) self.assertEqual( generator.content, """lib MyLib1 : : # requirements <name>MyLib1 : # default-build : # usage-requirements <define>MYDEFINE1 <cflags>-Flag1=23 ; lib MyLib2 : : # requirements <name>MyLib2 <search>dummy_root_folder2/lib <search>dummy_root_folder2/Path/with/slashes <search>dummy_root_folder2/regular/path/to/dir : # default-build : # usage-requirements <define>MYDEFINE2 <include>dummy_root_folder2/include <include>dummy_root_folder2/other/Path/with/slashes <include>dummy_root_folder2/other/regular/path/to/dir <cxxflags>-cxxflag <ldflags>-sharedlinkflag ; alias conan-deps : MyLib1 MyLib2 ; """)
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Sections self.processed_settings = None self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # ref pattern: list of ref def process_settings(self, cache, preprocess=True): self.processed_settings = cache.settings.copy() self.processed_settings.values = Values.from_list(list(self.settings.items())) if preprocess: settings_preprocessor.preprocess(self.processed_settings) # Redefine the profile settings values with the preprocessed ones # FIXME: Simplify the values.as_list() self.settings = OrderedDict(self.processed_settings.values.as_list()) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[settings]"] for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[build_requires]") for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) def update_settings(self, new_settings): """Mix the specified settings with the current profile. Specified settings are prioritized to profile""" assert(isinstance(new_settings, OrderedDict)) # apply the current profile res = copy.copy(self.settings) if new_settings: # Invalidate the current subsettings if the parent setting changes # Example: new_settings declare a different "compiler", so invalidate the current "compiler.XXX" for name, value in new_settings.items(): if "." not in name: if name in self.settings and self.settings[name] != value: for cur_name, _ in self.settings.items(): if cur_name.startswith("%s." % name): del res[cur_name] # Now merge the new values res.update(new_settings) self.settings = res def update_package_settings(self, package_settings): """Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile""" for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings)
def loads(text): """ Parse and return a Profile object from a text config like representation """ def get_package_name_value(item): """Parse items like package:name=value or name=value""" package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value try: obj = Profile() doc = ConfigParser(text, allowed_fields=[ "build_requires", "settings", "env", "scopes", "options" ]) for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: obj.package_settings[package_name][name] = value else: obj.settings[name] = value if doc.build_requires: # FIXME CHECKS OF DUPLICATED? for req in doc.build_requires.splitlines(): tokens = req.split(":", 1) if len(tokens) == 1: pattern, req_list = "*", req else: pattern, req_list = tokens req_list = [ ConanFileReference.loads(r.strip()) for r in req_list.split(",") ] obj.build_requires.setdefault(pattern, []).extend(req_list) if doc.scopes: obj.scopes = Scopes.from_list(doc.scopes.splitlines()) if doc.options: obj.options = OptionsValues.loads(doc.options) obj.env_values = EnvValues.loads(doc.env) return obj except ConanException: raise except Exception as exc: raise ConanException("Error parsing the profile text file: %s" % str(exc))
def aux_cmake_test_setup_test(self): conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) generator = CMakeGenerator(conanfile) aux_cmake_test_setup = generator.content # extract the conan_basic_setup macro macro = self._extract_macro("conan_basic_setup", aux_cmake_test_setup) self.assertEqual( """macro(conan_basic_setup) set(options TARGETS NO_OUTPUT_DIRS SKIP_RPATH KEEP_RPATHS SKIP_STD SKIP_FPIC) cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) if(CONAN_EXPORTED) conan_message(STATUS "Conan: called by CMake conan helper") endif() if(CONAN_IN_LOCAL_CACHE) conan_message(STATUS "Conan: called inside local cache") endif() if(NOT ARGUMENTS_NO_OUTPUT_DIRS) conan_message(STATUS "Conan: Adjusting output directories") conan_output_dirs_setup() endif() if(NOT ARGUMENTS_TARGETS) conan_message(STATUS "Conan: Using cmake global configuration") conan_global_flags() else() conan_message(STATUS "Conan: Using cmake targets configuration") conan_define_targets() endif() if(ARGUMENTS_SKIP_RPATH) # Change by "DEPRECATION" or "SEND_ERROR" when we are ready conan_message(WARNING "Conan: SKIP_RPATH is deprecated, it has been renamed to KEEP_RPATHS") endif() if(NOT ARGUMENTS_SKIP_RPATH AND NOT ARGUMENTS_KEEP_RPATHS) # Parameter has renamed, but we keep the compatibility with old SKIP_RPATH conan_message(STATUS "Conan: Adjusting default RPATHs Conan policies") conan_set_rpath() endif() if(NOT ARGUMENTS_SKIP_STD) conan_message(STATUS "Conan: Adjusting language standard") conan_set_std() endif() if(NOT ARGUMENTS_SKIP_FPIC) conan_set_fpic() endif() conan_check_compiler() conan_set_libcxx() conan_set_vs_runtime() conan_set_find_paths() conan_include_build_modules() conan_set_find_library_paths() endmacro()""", macro) # extract the conan_set_find_paths macro macro = self._extract_macro("conan_set_find_paths", aux_cmake_test_setup) self.assertEqual( """macro(conan_set_find_paths) # CMAKE_MODULE_PATH does not have Debug/Release config, but there are variables # CONAN_CMAKE_MODULE_PATH_DEBUG to be used by the consumer # CMake can find findXXX.cmake files in the root of packages set(CMAKE_MODULE_PATH ${CONAN_CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}) # Make find_package() to work set(CMAKE_PREFIX_PATH ${CONAN_CMAKE_MODULE_PATH} ${CMAKE_PREFIX_PATH}) # Set the find root path (cross build) set(CMAKE_FIND_ROOT_PATH ${CONAN_CMAKE_FIND_ROOT_PATH} ${CMAKE_FIND_ROOT_PATH}) if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}) endif() if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_LIBRARY}) endif() if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}) endif() endmacro()""", macro)
class ConanFile(object): """ The base class for all package recipes """ name = None version = None # Any str, can be "1.1" or whatever url = None # The URL where this File is located, as github, to collaborate in package # The license of the PACKAGE, just a shortcut, does not replace or # change the actual license of the source code license = None author = None # Main maintainer/responsible for the package, any format build_policy = None short_paths = False def __init__(self, output, runner, settings, conanfile_directory, user=None, channel=None): # User defined generators self.generators = self.generators if hasattr( self, "generators") else ["txt"] if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings) self.exports = create_exports(self) self.exports_sources = create_exports_sources(self) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() self.copy = None # initialized at runtime # an output stream (writeln, info, warn error) self.output = output # something that can run commands, as os.sytem self._runner = runner self._conanfile_directory = conanfile_directory self.package_folder = None # Assigned at runtime self._scope = None # user specified env variables self._env_values = EnvValues() # Updated at runtime, user specified -e self._user = user self._channel = channel @property def env(self): simple, multiple = self._env_values.env_dicts(self.name) simple.update(multiple) return simple @property def channel(self): if not self._channel: self._channel = os.getenv("CONAN_CHANNEL") if not self._channel: raise ConanException( "CONAN_CHANNEL environment variable not defined, " "but self.channel is used in conanfile") return self._channel @property def user(self): if not self._user: self._user = os.getenv("CONAN_USERNAME") if not self._user: raise ConanException( "CONAN_USERNAME environment variable not defined, " "but self.user is used in conanfile") return self._user def collect_libs(self, folder="lib"): if not self.package_folder: return [] lib_folder = os.path.join(self.package_folder, folder) if not os.path.exists(lib_folder): self.output.warn( "Package folder doesn't exist, can't collect libraries") return [] files = os.listdir(lib_folder) result = [] for f in files: name, ext = os.path.splitext(f) if ext in (".so", ".lib", ".a", ".dylib"): if ext != ".lib" and name.startswith("lib"): name = name[3:] result.append(name) return result @property def scope(self): return self._scope @scope.setter def scope(self, value): self._scope = value if value.dev: self.requires.allow_dev = True try: if hasattr(self, "dev_requires"): if isinstance(self.dev_requires, tuple): self.requires.add_dev(*self.dev_requires) else: self.requires.add_dev(self.dev_requires, ) except Exception as e: raise ConanException( "Error while initializing dev_requirements. %s" % str(e)) @property def conanfile_directory(self): return self._conanfile_directory @property def build_policy_missing(self): return self.build_policy == "missing" @property def build_policy_always(self): return self.build_policy == "always" def source(self): pass def system_requirements(self): """ this method can be overwritten to implement logic for system package managers, as apt-get You can define self.global_system_requirements = True, if you want the installation to be for all packages (not depending on settings/options/requirements) """ def config_options(self): """ modify options, probably conditioned to some settings. This call is executed before config_settings. E.g. if self.settings.os == "Windows": del self.options.shared # shared/static not supported in win """ def configure(self): """ modify settings, probably conditioned to some options. This call is executed after config_options. E.g. if self.options.header_only: self.settings.clear() This is also the place for conditional requirements """ def imports(self): pass def build(self): self.output.warn("This conanfile has no build step") def package(self): self.output.warn("This conanfile has no package step") def package_info(self): """ define cpp_build_info, flags, etc """ def run(self, command, output=True, cwd=None): """ runs such a command in the folder the Conan is defined """ retcode = self._runner(command, output, os.path.abspath(RUN_LOG_NAME), cwd) if retcode != 0: raise ConanException("Error %d while executing %s" % (retcode, command)) def package_id(self): """ modify the conans info, typically to narrow values eg.: conaninfo.package_references = [] """ def test(self): raise ConanException( "You need to create a method 'test' in your test/conanfile.py") def __repr__(self): if self.name and self.version and self._channel and self._user: return "%s/%s@%s/%s" % (self.name, self.version, self.user, self.channel) elif self.name and self.version: return "%s/%s@PROJECT" % (self.name, self.version) else: return "PROJECT"
class ConanFile(object): """ The base class for all package recipes """ name = None version = None # Any str, can be "1.1" or whatever url = None # The URL where this File is located, as github, to collaborate in package # The license of the PACKAGE, just a shortcut, does not replace or # change the actual license of the source code license = None author = None # Main maintainer/responsible for the package, any format build_policy = None short_paths = False apply_env = True # Apply environment variables from requires deps_env_info and profiles def __init__(self, output, runner, settings, user=None, channel=None, local=None): # User defined generators self.generators = self.generators if hasattr( self, "generators") else ["txt"] if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings, local) try: if self.settings.os_build and self.settings.os: output.writeln("*" * 60, front=Color.BRIGHT_RED) output.writeln( " This package defines both 'os' and 'os_build' ", front=Color.BRIGHT_RED) output.writeln( " Please use 'os' for libraries and 'os_build'", front=Color.BRIGHT_RED) output.writeln( " only for build-requires used for cross-building", front=Color.BRIGHT_RED) output.writeln("*" * 60, front=Color.BRIGHT_RED) except ConanException: pass self.exports = create_exports(self) self.exports_sources = create_exports_sources(self) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() # user declared variables self.user_info = None # Keys are the package names, and the values a dict with the vars self.deps_user_info = DepsUserInfo() self.copy = None # initialized at runtime # an output stream (writeln, info, warn error) self.output = output # something that can run commands, as os.sytem self._runner = runner self.develop = False # user specified env variables self._env_values = EnvValues() # Updated at runtime, user specified -e self._user = user self._channel = channel # Are we in local cache? Suggest a better name self.in_local_cache = False # Init a description self.description = None @property def env(self): """Apply the self.deps_env_info into a copy of self._env_values (will prioritize the self._env_values, user specified from profiles or -e first, then inherited)""" # Cannot be lazy cached, because it's called in configure node, and we still don't have # the deps_env_info objects available tmp_env_values = self._env_values.copy() tmp_env_values.update(self.deps_env_info) ret, multiple = tmp_env_values.env_dicts(self.name) ret.update(multiple) return ret @property def channel(self): if not self._channel: self._channel = os.getenv("CONAN_CHANNEL") if not self._channel: raise ConanException( "CONAN_CHANNEL environment variable not defined, " "but self.channel is used in conanfile") return self._channel @property def user(self): if not self._user: self._user = os.getenv("CONAN_USERNAME") if not self._user: raise ConanException( "CONAN_USERNAME environment variable not defined, " "but self.user is used in conanfile") return self._user def collect_libs(self, folder="lib"): self.output.warn("Use 'self.collect_libs' is deprecated, " "use tools.collect_libs(self) instead") return tools.collect_libs(self, folder=folder) @property def build_policy_missing(self): return self.build_policy == "missing" @property def build_policy_always(self): return self.build_policy == "always" def source(self): pass def system_requirements(self): """ this method can be overwritten to implement logic for system package managers, as apt-get You can define self.global_system_requirements = True, if you want the installation to be for all packages (not depending on settings/options/requirements) """ def config_options(self): """ modify options, probably conditioned to some settings. This call is executed before config_settings. E.g. if self.settings.os == "Windows": del self.options.shared # shared/static not supported in win """ def configure(self): """ modify settings, probably conditioned to some options. This call is executed after config_options. E.g. if self.options.header_only: self.settings.clear() This is also the place for conditional requirements """ def build(self): self.output.warn("This conanfile has no build step") def package(self): self.output.warn("This conanfile has no package step") def package_info(self): """ define cpp_build_info, flags, etc """ def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True): if not win_bash: retcode = self._runner(command, output, os.path.abspath(RUN_LOG_NAME), cwd) else: retcode = tools.run_in_windows_bash(self, bashcmd=command, cwd=cwd, subsystem=subsystem, msys_mingw=msys_mingw) if retcode != 0: raise ConanException("Error %d while executing %s" % (retcode, command)) return retcode def package_id(self): """ modify the conans info, typically to narrow values eg.: conaninfo.package_references = [] """ def test(self): raise ConanException( "You need to create a method 'test' in your test/conanfile.py") def __repr__(self): if self.name and self.version and self._channel and self._user: return "%s/%s@%s/%s" % (self.name, self.version, self.user, self.channel) elif self.name and self.version: return "%s/%s@PROJECT" % (self.name, self.version) else: return "PROJECT"
def b2_test(self): settings = Settings.loads(default_settings_yml) settings.os = "Linux" settings.compiler = "gcc" settings.compiler.version = "6.3" settings.arch = "x86" settings.build_type = "Release" settings.cppstd = "gnu17" conanfile = ConanFile(None, None) conanfile.initialize(Settings({}), EnvValues()) conanfile.settings = settings ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables") cpp_info = CppInfo("dummy_root_folder1") cpp_info.defines = ["MYDEFINE1"] cpp_info.cflags.append("-Flag1=23") cpp_info.version = "1.3" cpp_info.description = "My cool description" cpp_info.libs = ["MyLib1"] conanfile.deps_cpp_info.update(cpp_info, ref.name) ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables") cpp_info = CppInfo("dummy_root_folder2") cpp_info.libs = ["MyLib2"] cpp_info.defines = ["MYDEFINE2"] cpp_info.version = "2.3" cpp_info.exelinkflags = ["-exelinkflag"] cpp_info.sharedlinkflags = ["-sharedlinkflag"] cpp_info.cppflags = ["-cppflag"] cpp_info.public_deps = ["MyPkg"] cpp_info.lib_paths.extend( ["Path\\with\\slashes", "regular/path/to/dir"]) cpp_info.include_paths.extend( ["other\\Path\\with\\slashes", "other/regular/path/to/dir"]) conanfile.deps_cpp_info.update(cpp_info, ref.name) generator = B2Generator(conanfile) content = { 'conanbuildinfo.jam': '''#| B2 definitions for Conan packages. This is a generated file. Edit the corresponding conanfile.txt instead. |# import path ; import project ; import modules ; import feature ; local base-project = [ project.current ] ; local base-project-mod = [ $(base-project).project-module ] ; local base-project-location = [ project.attribute $(base-project-mod) location ] ; rule project-define ( id ) { id = $(id:L) ; local saved-project = [ modules.peek project : .base-project ] ; local id-location = [ path.join $(base-project-location) $(id) ] ; local id-mod = [ project.load $(id-location) : synthesize ] ; project.initialize $(id-mod) : $(id-location) ; project.inherit-attributes $(id-mod) : $(base-project-mod) ; local attributes = [ project.attributes $(id-mod) ] ; $(attributes).set parent-module : $(base-project-mod) : exact ; modules.poke $(base-project-mod) : $(id)-mod : $(id-mod) ; modules.poke [ CALLER_MODULE ] : $(id)-mod : $(id-mod) ; modules.poke project : .base-project : $(saved-project) ; IMPORT $(__name__) : constant-if call-in-project : $(id-mod) : constant-if call-in-project ; return $(id-mod) ; } rule constant-if ( name : value * ) { if $(__define_constants__) && $(value) { call-in-project : constant $(name) : $(value) ; modules.poke $(__name__) : $(name) : [ modules.peek $(base-project-mod) : $(name) ] ; } } rule call-in-project ( project-mod ? : rule-name args * : * ) { project-mod ?= $(base-project-mod) ; project.push-current [ project.target $(project-mod) ] ; local result = [ modules.call-in $(project-mod) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] ; project.pop-current ; return $(result) ; } rule include-conanbuildinfo ( cbi ) { include $(cbi) ; } IMPORT $(__name__) : project-define constant-if call-in-project include-conanbuildinfo : $(base-project-mod) : project-define constant-if call-in-project include-conanbuildinfo ; if ! ( relwithdebinfo in [ feature.values variant ] ) { variant relwithdebinfo : : <optimization>speed <debug-symbols>on <inlining>full <runtime-debugging>off ; } if ! ( minsizerel in [ feature.values variant ] ) { variant minsizerel : : <optimization>space <debug-symbols>off <inlining>full <runtime-debugging>off ; } local __conanbuildinfo__ = [ GLOB $(__file__:D) : conanbuildinfo-*.jam : downcase ] ; { local __define_constants__ = yes ; for local __cbi__ in $(__conanbuildinfo__) { call-in-project : include-conanbuildinfo $(__cbi__) ; } } # mypkg # mypkg project-define mypkg ; # mypkg2 # mypkg2 project-define mypkg2 ; { local __define_targets__ = yes ; for local __cbi__ in $(__conanbuildinfo__) { call-in-project : include-conanbuildinfo $(__cbi__) ; } } ''', 'conanbuildinfo-316f2f0b155dc874a672d40d98d93f95.jam': '''#| B2 definitions for Conan packages. This is a generated file. Edit the corresponding conanfile.txt instead. |# # global constant-if rootpath(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "" ; constant-if includedirs(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "other/Path/with/slashes" "other/regular/path/to/dir" ; constant-if libdirs(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "Path/with/slashes" "regular/path/to/dir" ; constant-if defines(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "MYDEFINE2" "MYDEFINE1" ; constant-if cppflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "-cppflag" ; constant-if cflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "-Flag1=23" ; constant-if sharedlinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "-sharedlinkflag" ; constant-if exelinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) : "-exelinkflag" ; constant-if requirements(conan,32,x86,17,gnu,linux,gcc-6.3,release) : <address-model>32 <architecture>x86 <cxxstd>17 <cxxstd:dialect>gnu <target-os>linux <toolset>gcc-6.3 <variant>release ; constant-if usage-requirements(conan,32,x86,17,gnu,linux,gcc-6.3,release) : <include>$(includedirs(conan,32,x86,17,gnu,linux,gcc-6.3,release)) <define>$(defines(conan,32,x86,17,gnu,linux,gcc-6.3,release)) <cflags>$(cflags(conan,32,x86,17,gnu,linux,gcc-6.3,release)) <cxxflags>$(cppflags(conan,32,x86,17,gnu,linux,gcc-6.3,release)) <link>shared:<linkflags>$(sharedlinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release)) ; # mypkg constant-if rootpath(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) : "dummy_root_folder1" ; constant-if defines(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) : "MYDEFINE1" ; constant-if cflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) : "-Flag1=23" ; constant-if requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) : <address-model>32 <architecture>x86 <cxxstd>17 <cxxstd:dialect>gnu <target-os>linux <toolset>gcc-6.3 <variant>release ; constant-if usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) : <include>$(includedirs(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) <define>$(defines(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) <cflags>$(cflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) <cxxflags>$(cppflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) <link>shared:<linkflags>$(sharedlinkflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) ; # mypkg2 constant-if rootpath(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "dummy_root_folder2" ; constant-if includedirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "other/Path/with/slashes" "other/regular/path/to/dir" ; constant-if libdirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "Path/with/slashes" "regular/path/to/dir" ; constant-if defines(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "MYDEFINE2" ; constant-if cppflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "-cppflag" ; constant-if sharedlinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "-sharedlinkflag" ; constant-if exelinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : "-exelinkflag" ; constant-if requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : <address-model>32 <architecture>x86 <cxxstd>17 <cxxstd:dialect>gnu <target-os>linux <toolset>gcc-6.3 <variant>release ; constant-if usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) : <include>$(includedirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) <define>$(defines(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) <cflags>$(cflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) <cxxflags>$(cppflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) <link>shared:<linkflags>$(sharedlinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) ; # mypkg if $(__define_targets__) { call-in-project $(mypkg-mod) : lib MyLib1 : : <name>MyLib1 <search>$(libdirs(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) $(requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) : : $(usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) ; call-in-project $(mypkg-mod) : explicit MyLib1 ; } if $(__define_targets__) { call-in-project $(mypkg-mod) : alias libs : MyLib1 : $(requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) : : $(usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) ; call-in-project $(mypkg-mod) : explicit libs ; } # mypkg2 if $(__define_targets__) { call-in-project $(mypkg2-mod) : lib MyLib2 : : <name>MyLib2 <search>$(libdirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) $(requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) : : $(usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) ; call-in-project $(mypkg2-mod) : explicit MyLib2 ; } if $(__define_targets__) { call-in-project $(mypkg2-mod) : alias libs : MyLib2 : $(requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) : : $(usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) ; call-in-project $(mypkg2-mod) : explicit libs ; } ''', } for ck, cv in generator.content.items(): self.assertEquals(cv, content[ck])
def test_model(self): env = EnvValues() env.add("Z", "1") self.assertEqual(env.env_dicts(""), ({"Z": "1"}, {})) env.add("Z", "2") self.assertEqual(env.env_dicts(""), ({"Z": "1"}, {})) env.add("B", "223") self.assertEqual(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) env.add("B", "224", "package1") self.assertEqual(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224" }, {})) env.add("A", "1", "package1") self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224", "A": "1" }, {})) self.assertEqual(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) env.add("J", "21", "package21") self.assertEqual(env.env_dicts(""), ({"Z": "1", "B": "223"}, {})) self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224", "A": "1" }, {})) env.add("A", ["99"], "package1") self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224", "A": "1" }, {})) env.add("M", ["99"], "package1") self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224", "A": "1" }, { "M": ["99"] })) env.add("M", "100", "package1") self.assertEqual(env.env_dicts("package1"), ({ "Z": "1", "B": "224", "A": "1" }, { "M": ["99", "100"] })) self.assertEqual(env.env_dicts(""), ({"Z": "1", "B": "223"}, {}))
class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() self.build_requires = OrderedDict( ) # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[build_requires]"] for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[settings]") for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) self.update_scopes(other.scopes) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) def update_package_settings(self, package_settings): '''Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile''' for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
def variables_setup_test(self): tmp_folder1 = temp_folder() tmp_folder2 = temp_folder() save(os.path.join(tmp_folder1, "include1", "file.h"), "") save(os.path.join(tmp_folder2, "include2", "file.h"), "") save(os.path.join(tmp_folder1, "lib1", "file.a"), "") save(os.path.join(tmp_folder2, "lib2", "file.a"), "") save(os.path.join(tmp_folder1, "bin1", "file.bin"), "") save(os.path.join(tmp_folder2, "bin2", "file.bin"), "") save(os.path.join(tmp_folder1, "SystemFrameworks", "file.bin"), "") conanfile = ConanFile(TestBufferConanOutput(), None) conanfile.initialize(Settings({}), EnvValues()) ref = ConanFileReference.loads("MyPkg1/0.1@lasote/stables") cpp_info = CppInfo(ref.name, tmp_folder1) cpp_info.defines = ["MYDEFINE1"] cpp_info.includedirs = ['include1'] cpp_info.libdirs = ['lib1'] cpp_info.libs = ['libfoo'] cpp_info.bindirs = ['bin1'] cpp_info.version = "0.1" cpp_info.cflags = ['-fgimple'] cpp_info.cxxflags = ['-fdollars-in-identifiers'] cpp_info.sharedlinkflags = ['-framework Cocoa'] cpp_info.exelinkflags = ['-framework QuartzCore'] cpp_info.frameworks = ['AudioUnit'] cpp_info.frameworkdirs = ['SystemFrameworks'] cpp_info.system_libs = ["system_lib1"] conanfile.deps_cpp_info.add(ref.name, cpp_info) ref = ConanFileReference.loads("MyPkg2/3.2.3@lasote/stables") cpp_info = CppInfo(ref.name, tmp_folder2) cpp_info.defines = ["MYDEFINE2"] cpp_info.includedirs = ['include2'] cpp_info.libdirs = ['lib2'] cpp_info.libs = ['libbar'] cpp_info.bindirs = ['bin2'] cpp_info.version = "3.2.3" cpp_info.cflags = ['-fno-asm'] cpp_info.cxxflags = ['-pthread'] cpp_info.sharedlinkflags = ['-framework AudioFoundation'] cpp_info.exelinkflags = ['-framework VideoToolbox'] cpp_info.system_libs = ["system_lib2"] conanfile.deps_cpp_info.add(ref.name, cpp_info) generator = MakeGenerator(conanfile) content = generator.content content_template = """ CONAN_ROOT_MYPKG1 ?= \\ {conan_root_mypkg1} CONAN_SYSROOT_MYPKG1 ?= \\ CONAN_INCLUDE_DIRS_MYPKG1 += \\ {conan_include_dirs_mypkg1} CONAN_LIB_DIRS_MYPKG1 += \\ {conan_lib_dirs_mypkg1} CONAN_BIN_DIRS_MYPKG1 += \\ {conan_bin_dirs_mypkg1} CONAN_BUILD_DIRS_MYPKG1 += \\ {conan_build_dirs_mypkg1} CONAN_RES_DIRS_MYPKG1 += \\ CONAN_LIBS_MYPKG1 += \\ libfoo CONAN_SYSTEM_LIBS_MYPKG1 += \\ system_lib1 CONAN_DEFINES_MYPKG1 += \\ MYDEFINE1 CONAN_CFLAGS_MYPKG1 += \\ -fgimple CONAN_CXXFLAGS_MYPKG1 += \\ -fdollars-in-identifiers CONAN_SHAREDLINKFLAGS_MYPKG1 += \\ -framework Cocoa CONAN_EXELINKFLAGS_MYPKG1 += \\ -framework QuartzCore CONAN_FRAMEWORKS_MYPKG1 += \\ AudioUnit CONAN_FRAMEWORK_PATHS_MYPKG1 += \\ {conan_framework_dirs_mypkg1} CONAN_ROOT_MYPKG2 ?= \\ {conan_root_mypkg2} CONAN_SYSROOT_MYPKG2 ?= \\ CONAN_INCLUDE_DIRS_MYPKG2 += \\ {conan_include_dirs_mypkg2} CONAN_LIB_DIRS_MYPKG2 += \\ {conan_lib_dirs_mypkg2} CONAN_BIN_DIRS_MYPKG2 += \\ {conan_bin_dirs_mypkg2} CONAN_BUILD_DIRS_MYPKG2 += \\ {conan_build_dirs_mypkg2} CONAN_RES_DIRS_MYPKG2 += \\ CONAN_LIBS_MYPKG2 += \\ libbar CONAN_SYSTEM_LIBS_MYPKG2 += \\ system_lib2 CONAN_DEFINES_MYPKG2 += \\ MYDEFINE2 CONAN_CFLAGS_MYPKG2 += \\ -fno-asm CONAN_CXXFLAGS_MYPKG2 += \\ -pthread CONAN_SHAREDLINKFLAGS_MYPKG2 += \\ -framework AudioFoundation CONAN_EXELINKFLAGS_MYPKG2 += \\ -framework VideoToolbox CONAN_FRAMEWORKS_MYPKG2 += \\ CONAN_FRAMEWORK_PATHS_MYPKG2 += \\ CONAN_ROOTPATH += \\ $(CONAN_ROOTPATH_MYPKG1) \\ $(CONAN_ROOTPATH_MYPKG2) CONAN_SYSROOT += \\ $(CONAN_SYSROOT_MYPKG1) \\ $(CONAN_SYSROOT_MYPKG2) CONAN_INCLUDE_DIRS += \\ $(CONAN_INCLUDE_DIRS_MYPKG1) \\ $(CONAN_INCLUDE_DIRS_MYPKG2) CONAN_LIB_DIRS += \\ $(CONAN_LIB_DIRS_MYPKG1) \\ $(CONAN_LIB_DIRS_MYPKG2) CONAN_BIN_DIRS += \\ $(CONAN_BIN_DIRS_MYPKG1) \\ $(CONAN_BIN_DIRS_MYPKG2) CONAN_BUILD_DIRS += \\ $(CONAN_BUILD_DIRS_MYPKG1) \\ $(CONAN_BUILD_DIRS_MYPKG2) CONAN_RES_DIRS += \\ $(CONAN_RES_DIRS_MYPKG1) \\ $(CONAN_RES_DIRS_MYPKG2) CONAN_LIBS += \\ $(CONAN_LIBS_MYPKG1) \\ $(CONAN_LIBS_MYPKG2) CONAN_DEFINES += \\ $(CONAN_DEFINES_MYPKG1) \\ $(CONAN_DEFINES_MYPKG2) CONAN_CFLAGS += \\ $(CONAN_CFLAGS_MYPKG1) \\ $(CONAN_CFLAGS_MYPKG2) CONAN_CXXFLAGS += \\ $(CONAN_CXXFLAGS_MYPKG1) \\ $(CONAN_CXXFLAGS_MYPKG2) CONAN_SHAREDLINKFLAGS += \\ $(CONAN_SHAREDLINKFLAGS_MYPKG1) \\ $(CONAN_SHAREDLINKFLAGS_MYPKG2) CONAN_EXELINKFLAGS += \\ $(CONAN_EXELINKFLAGS_MYPKG1) \\ $(CONAN_EXELINKFLAGS_MYPKG2) CONAN_FRAMEWORKS += \\ $(CONAN_FRAMEWORKS_MYPKG1) \\ $(CONAN_FRAMEWORKS_MYPKG2) CONAN_FRAMEWORK_PATHS += \\ $(CONAN_FRAMEWORK_PATHS_MYPKG1) \\ $(CONAN_FRAMEWORK_PATHS_MYPKG2) """ root1 = tmp_folder1.replace('\\', '/') root2 = tmp_folder2.replace('\\', '/') inc1 = os.path.join(tmp_folder1, 'include1').replace('\\', '/') inc2 = os.path.join(tmp_folder2, 'include2').replace('\\', '/') lib1 = os.path.join(tmp_folder1, 'lib1').replace('\\', '/') lib2 = os.path.join(tmp_folder2, 'lib2').replace('\\', '/') bin1 = os.path.join(tmp_folder1, 'bin1').replace('\\', '/') bin2 = os.path.join(tmp_folder2, 'bin2').replace('\\', '/') expected_content = content_template.format( conan_root_mypkg1=root1, conan_include_dirs_mypkg1=inc1, conan_lib_dirs_mypkg1=lib1, conan_bin_dirs_mypkg1=bin1, conan_build_dirs_mypkg1=root1 + "/", conan_root_mypkg2=root2, conan_include_dirs_mypkg2=inc2, conan_lib_dirs_mypkg2=lib2, conan_bin_dirs_mypkg2=bin2, conan_build_dirs_mypkg2=root2 + "/", conan_framework_dirs_mypkg1=root1 + "/SystemFrameworks") self.maxDiff = None self.assertIn(expected_content, content)
class ConanFile(object): """ The base class for all package recipes """ name = None version = None # Any str, can be "1.1" or whatever url = None # The URL where this File is located, as github, to collaborate in package # The license of the PACKAGE, just a shortcut, does not replace or # change the actual license of the source code license = None author = None # Main maintainer/responsible for the package, any format build_policy = None short_paths = False def __init__(self, output, runner, settings, conanfile_directory, user=None, channel=None): # User defined generators self.generators = self.generators if hasattr(self, "generators") else ["txt"] if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings) self.exports = create_exports(self) self.exports_sources = create_exports_sources(self) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() self.copy = None # initialized at runtime # an output stream (writeln, info, warn error) self.output = output # something that can run commands, as os.sytem self._runner = runner self._conanfile_directory = conanfile_directory self.package_folder = None # Assigned at runtime self._scope = None # user specified env variables self._env_values = EnvValues() # Updated at runtime, user specified -e self._user = user self._channel = channel @property def env(self): simple, multiple = self._env_values.env_dicts(self.name) simple.update(multiple) return simple @property def channel(self): if not self._channel: self._channel = os.getenv("CONAN_CHANNEL") if not self._channel: raise ConanException("CONAN_CHANNEL environment variable not defined, " "but self.channel is used in conanfile") return self._channel @property def user(self): if not self._user: self._user = os.getenv("CONAN_USERNAME") if not self._user: raise ConanException("CONAN_USERNAME environment variable not defined, " "but self.user is used in conanfile") return self._user def collect_libs(self, folder="lib"): if not self.package_folder: return [] lib_folder = os.path.join(self.package_folder, folder) if not os.path.exists(lib_folder): self.output.warn("Package folder doesn't exist, can't collect libraries") return [] files = os.listdir(lib_folder) result = [] for f in files: name, ext = os.path.splitext(f) if ext in (".so", ".lib", ".a", ".dylib"): if ext != ".lib" and name.startswith("lib"): name = name[3:] result.append(name) return result @property def scope(self): return self._scope @scope.setter def scope(self, value): self._scope = value if value.dev: self.requires.allow_dev = True try: if hasattr(self, "dev_requires"): if isinstance(self.dev_requires, tuple): self.requires.add_dev(*self.dev_requires) else: self.requires.add_dev(self.dev_requires, ) except Exception as e: raise ConanException("Error while initializing dev_requirements. %s" % str(e)) @property def conanfile_directory(self): return self._conanfile_directory @property def build_policy_missing(self): return self.build_policy == "missing" @property def build_policy_always(self): return self.build_policy == "always" def source(self): pass def system_requirements(self): """ this method can be overwritten to implement logic for system package managers, as apt-get You can define self.global_system_requirements = True, if you want the installation to be for all packages (not depending on settings/options/requirements) """ def config_options(self): """ modify options, probably conditioned to some settings. This call is executed before config_settings. E.g. if self.settings.os == "Windows": del self.options.shared # shared/static not supported in win """ def configure(self): """ modify settings, probably conditioned to some options. This call is executed after config_options. E.g. if self.options.header_only: self.settings.clear() This is also the place for conditional requirements """ def imports(self): pass def build(self): self.output.warn("This conanfile has no build step") def package(self): self.output.warn("This conanfile has no package step") def package_info(self): """ define cpp_build_info, flags, etc """ def run(self, command, output=True, cwd=None): """ runs such a command in the folder the Conan is defined """ retcode = self._runner(command, output, os.path.abspath(RUN_LOG_NAME), cwd) if retcode != 0: raise ConanException("Error %d while executing %s" % (retcode, command)) def package_id(self): """ modify the conans info, typically to narrow values eg.: conaninfo.package_references = [] """ def test(self): raise ConanException("You need to create a method 'test' in your test/conanfile.py") def __repr__(self): if self.name and self.version and self._channel and self._user: return "%s/%s@%s/%s" % (self.name, self.version, self.user, self.channel) elif self.name and self.version: return "%s/%s@PROJECT" % (self.name, self.version) else: return "PROJECT"