From aecd29a70bd3558136910a1a5a41c10204e2dd4b Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Thu, 19 Nov 2020 17:19:54 +0100 Subject: [PATCH 01/23] Implemented Qbs Build Helper --- conans/__init__.py | 1 + conans/client/build/qbs.py | 225 +++++++++++++++ .../test/unittests/client/build/qbs_test.py | 262 ++++++++++++++++++ 3 files changed, 488 insertions(+) create mode 100644 conans/client/build/qbs.py create mode 100644 conans/test/unittests/client/build/qbs_test.py diff --git a/conans/__init__.py b/conans/__init__.py index 4c143965fcd..adba518adab 100644 --- a/conans/__init__.py +++ b/conans/__init__.py @@ -6,6 +6,7 @@ from conans.client.toolchain.make import MakeToolchain from conans.client.build.meson import Meson from conans.client.build.msbuild import MSBuild +from conans.client.build.qbs import Qbs from conans.client.build.visual_environment import VisualStudioBuildEnvironment from conans.client.run_environment import RunEnvironment from conans.model.conan_file import ConanFile diff --git a/conans/client/build/qbs.py b/conans/client/build/qbs.py new file mode 100644 index 00000000000..bb0202b78ec --- /dev/null +++ b/conans/client/build/qbs.py @@ -0,0 +1,225 @@ +import os +import platform + +from conans import tools +from conans.errors import ConanException + + +class QbsException(ConanException): + def __str__(self): + msg = super(QbsException, self).__str__() + return "Qbs build helper: {}".format(msg) + + +def _qbs_config(conanfile, profile_name, values): + key_prefix = "profiles.%s" % profile_name + for key, value in values.items(): + config_key = "%s.%s" % (key_prefix, key) + if type(value) is bool: + if value: + value = 'true' + else: + value = 'false' + cmd = 'qbs-config --settings-dir %s %s "%s"' % ( + _settings_dir(conanfile), config_key, value) + conanfile.run(cmd) + + +def _env_var_to_list(var): + elements = [] + flag_groups = var.split('"') + + latest_flag = '' + for i in range(len(flag_groups)): + if not flag_groups[i]: + continue + + def is_quoted_flag(): + return i % 2 + + if is_quoted_flag(): + if latest_flag: + elements.append(latest_flag + flag_groups[i]) + else: + elements.append(flag_groups[i]) + else: + flags = flag_groups[i].split() + latest_flag = flags.pop() + for s in flags: + elements.append(s) + if not latest_flag.endswith('='): + elements.append(latest_flag) + latest_flag = '' + + return elements + + +def _check_for_compiler(conanfile): + compiler = conanfile.settings.get_safe("compiler") + if not compiler: + raise QbsException("need compiler to be set in settings") + + if compiler not in ["Visual Studio", "gcc", "clang"]: + raise QbsException("compiler not supported") + + +def _compiler_name(conanfile): + # needs more work since currently only windows and linux is supported + compiler = conanfile.settings.compiler + if platform.system() == "Windows": + if compiler == "gcc": + return "mingw" + if compiler == "Visual Studio": + if tools.msvs_toolset(conanfile) == "ClangCl": + return "clang-cl" + return "cl" + if compiler == "clang": + return "clang-cl" + raise QbsException("unknown windows compiler") + + if platform.system() == "Linux": + return compiler + + raise QbsException("unknown compiler") + + +def _generate_profile_name(conanfile): + compiler = "_%s" % (conanfile.settings.get_safe("compiler")) + compiler_version = conanfile.settings.compiler.get_safe( + "version") + if compiler_version: + compiler_version = '_' + compiler_version + the_os = conanfile.settings.get_safe("os") + if the_os: + the_os = '_' + the_os + + return "_conan%s%s%s" % (the_os, compiler, compiler_version) + + +def _settings_dir(conanfile): + return conanfile.build_folder + + +def _setup_toolchain(conanfile, profile_name): + if tools.get_env("CC"): + compiler = tools.get_env("CC") + else: + compiler = _compiler_name(conanfile) + + env_context = tools.no_op() + if platform.system() == "Windows": + if compiler in ["cl", "clang-cl"]: + env_context = tools.vcvars() + + with env_context: + cmd = "qbs-setup-toolchains --settings-dir %s %s %s" % ( + _settings_dir(conanfile), compiler, profile_name) + conanfile.run(cmd) + + flags_from_env = {} + if tools.get_env("ASFLAGS"): + flags_from_env["cpp.assemblerFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("ASFLAGS"))) + if tools.get_env("CFLAGS"): + flags_from_env["cpp.cFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CFLAGS"))) + if tools.get_env("CPPFLAGS"): + flags_from_env["cpp.cppFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CPPFLAGS"))) + if tools.get_env("CXXFLAGS"): + flags_from_env["cpp.cxxFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CXXFLAGS"))) + if tools.get_env("LDFLAGS"): + ld_flags = [] + for item in _env_var_to_list(tools.get_env("LDFLAGS")): + flags = item[len("-Wl,"):] + ld_flags.extend(flags.split(",")) + flags_from_env["cpp.linkerFlags"] = '%s' % (ld_flags) + + if flags_from_env: + _qbs_config(conanfile, profile_name, flags_from_env) + + +def _configuration_dict_to_commandlist(name, dict): + command_list = ["config:%s" % name] + for key in dict: + value = dict[key] + if type(value) is bool: + if value: + b = "true" + else: + b = "false" + command_list.append("%s:%s" % (key, b)) + else: + command_list.append("%s:%s" % (key, value)) + return command_list + + +class Qbs(object): + def __init__(self, conanfile, project_file=None): + _check_for_compiler(conanfile) + self._conanfile = conanfile + self._set_project_file(project_file) + self._base_profile_name = _generate_profile_name(conanfile) + _setup_toolchain(conanfile, self._base_profile_name) + self.jobs = tools.cpu_count() + self._configuration = dict() + self._profile_name = "" + + def _set_project_file(self, project_file): + if not project_file: + self._project_file = self._conanfile.source_folder + else: + self._project_file = project_file + + if not os.path.exists(self._project_file): + raise QbsException("could not find project file") + + def setup_profile(self, name, values): + temp = {"baseProfile": self._base_profile_name} + temp.update(values) + _qbs_config(self._conanfile, name, temp) + self._profile_name = name + + def add_configuration(self, name, values): + self._configuration[name] = values + + def build(self, all_products=False, products=[]): + if not self._profile_name: + self._profile_name = self._base_profile_name + + args = [ + "--no-install", + "--settings-dir", _settings_dir(self._conanfile), + "--build-directory", self._conanfile.build_folder, + "--file", self._project_file, + ] + + if all_products: + args.append("--all-products") + if products: + args.extend(["-p", ",".join(products)]) + + args.extend(["--jobs", "%s" % self.jobs]) + args.append("profile:%s" % self._profile_name) + + for name in self._configuration: + config = self._configuration[name] + args.extend(_configuration_dict_to_commandlist(name, config)) + + cmd = "qbs build %s" % (" ".join(args)) + self._conanfile.run(cmd) + + def install(self): + args = [ + "--no-build", + "--clean-install-root", + "--install-root", self._conanfile.install_folder, + "--file", self._project_file + ] + + for name in self._configuration: + args.append("config:%s" % (name)) + + cmd = "qbs install %s" % (" ".join(args)) + self._conanfile.run(cmd) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py new file mode 100644 index 00000000000..2d5058c1c2d --- /dev/null +++ b/conans/test/unittests/client/build/qbs_test.py @@ -0,0 +1,262 @@ +import unittest +import conans.client.build.qbs as qbs + +from conans.client import tools +from conans.test.utils.mocks import ConanFileMock, MockSettings + + +class ConanFileMockWithMultipleCommands(ConanFileMock): + def __init__(self): + self.command = [] + + def run(self, command): + self.command.append(command) + + +class QbsTest(unittest.TestCase): + def test_call_qbs_config_with_single_value(self): + conanfile = ConanFileMock() + profile_name = "my_fancy_profile" + key = "test_key" + value = "test_value" + expected_key = "profiles.%s.%s" % (profile_name, key) + expected_value = value + qbs._qbs_config(conanfile, profile_name, value) + self.assertEqual(conanfile.command, + "qbs-config --settings-dir %s %s %s" % ( + conanfile.build_folder, expected_key, + expected_value)) + + def test_split_env_var_into_list(self): + expected_list = ['-p1', '-p2', '-p3_with_value=13', + '-p_with_space1="hello world"', + '"-p_with_space2=Hello World"'] + env_var = " ".join(expected_list) + self.assertEqual(qbs._env_var_to_list(env_var), expected_list) + + def test_compiler_not_in_settings(self): + conanfile = ConanFileMock() + conanfile.settings = MockSettings() + with self.assertRaises(qbs.QbsException): + qbs._check_for_compiler(conanfile) + + def test_compiler_in_settings_not_supported(self): + conanfile = ConanFileMock() + conanfile.settings = MockSettings({"compiler": + "not realy a compiler name"}) + with self.assertRaises(qbs.QbsException): + qbs._check_for_compiler(conanfile) + + def test_valid_compiler(self): + supported_compilers = ["Visual Studio", "gcc", "clang"] + for compiler in supported_compilers: + conanfile = ConanFileMock() + conanfile.settings = MockSettings({"compiler": compiler}) + qbs._check_for_compiler(conanfile) + + @staticmethod + def _settings_to_test_against(self): + return [ + {"os": "Windows", "compiler": "gcc", "qbs_compiler": "mingw"}, + {"os": "Windows", "compiler": "clang", + "qbs_compiler": "clang-cl"}, + {"os": "Windows", "compiler": "Visual Studio", + "qbs_compiler": "cl"}, + {"os": "Windows", "compiler": "Visual Studio", + "toolset": "ClangCl", "qbs_compiler": "clang-cl"}, + {"os": "Linux", "compiler": "gcc", "qbs_compiler": "gcc"}, + {"os": "Linux", "compiler": "clang", "qbs_compiler": "clang"} + ] + + def test_convert_compiler_name_to_qbs_compiler_name(self): + for settings in self._settings_to_test_against(): + def expected(): + return settings["qbs_compiler"] + conanfile = ConanFileMock() + conanfile.settings = settings + self.assertEqual(qbs._compiler_name(conanfile), expected()) + + def test_settings_dir_location(self): + conanfile = ConanFileMock() + self.assertEqual(qbs._settings_dir(conanfile), conanfile.build_folder) + + def test_setup_toolchain_without_any_env_values(self): + stub_profile_name = "foobar" + for settings in self._settings_to_test_against(): + conanfile = ConanFileMockWithMultipleCommands() + conanfile.settings = settings + qbs._setup_toolchain(conanfile, stub_profile_name) + self.assertEqual(len(conanfile.command), 1) + self.assertEqual( + conanfile.command[0], + "qbs-setup-toolchains --settings-dir %s %s %s" % ( + conanfile.build_folder, settings["qbs_compiler"], + stub_profile_name)) + + def test_setup_toolchain_with_compiler_from_env(self): + compiler = "compiler_from_env" + stub_profile_name = "foobar" + for settings in self._settings_to_test_against(): + conanfile = ConanFileMockWithMultipleCommands() + conanfile.settings = settings + with tools.environment_append({"CC": compiler}): + qbs._setup_toolchain(conanfile, stub_profile_name) + self.assertEqual(len(conanfile.command), 1) + self.assertEqual( + conanfile.command[0], + "qbs-setup-toolchains --settings-dir %s %s %s" % ( + conanfile.build_folder, compiler, + stub_profile_name)) + + @staticmethod + def _generate_flags(flag, qbs_key): + return {"env": ('-{0}1 -{0}2 -{0}3_with_value=13 ' + '-{0}_with_space1="hello world" ' + '"-{0}_with_space2=Hello World"').format(flag), + "qbs_value": ('["-{0}1", "-{0}2", "-{0}3_with_value=13", ' + '"-{0}_with_space1=hello world", ' + '"-{0}_with_space2=Hello World"').format(flag), + "qbs_key": qbs_key} + + def test_setup_toolchain_with_flags_from_env(self): + stub_profile_name = "foobar" + conanfile = ConanFileMockWithMultipleCommands() + compiler = "gcc" + conanfile.settings = {"os": "Linux", "compiler": compiler} + + asm = self._generate_flags("asm", "assemblerFlags") + c = self._generate_flags("c", "cFlags") + cpp = self._generate_flags("cpp", "cppFlags") + cxx = self._generate_flags("cxx", "cxxFlags") + wl = self._generate_flags("Wl,", "linkerFlags") + ld = self._generate_flags("ld", "linkerFlags") + env = { + "ASFLAGS": asm["env"], + "CFLAGS": c["env"], + "CPPFLAGS": cpp["env"], + "CXXFLAGS": cxx["env"], + "LDFLAGS": wl["env"] + "-Wl," + ld["env"].replace(" -", ",-") + } + with tools.environment_append(env): + qbs._setup_toolchain(conanfile, stub_profile_name) + self.assertEqual(len(conanfile.command), 1 + len(env)) + self.assertEqual( + conanfile.command[0], + "qbs-setup-toolchains --settings-dir %s %s %s" % ( + conanfile.build_folder, compiler, + stub_profile_name)) + + qbs_config = [ + {"key": asm["qbs_key"], "value": asm["qbs_value"]}, + {"key": c["qbs_key"], "value": c["qbs_value"]}, + {"key": cpp["qbs_key"], "value": cpp["qbs_value"]}, + {"key": cxx["qbs_key"], "value": cxx["qbs_value"]}, + {"key": wl["qbs_key"], + "value": (wl["qbs_value"] + + ld["qbs_values"]).replace("][", ", ", 1)}, + ] + self.assertEqual(len(conanfile.command)-1, len(qbs_config)) + for i in range(len(qbs_config)): + item = qbs_config[i] + key = "profiles.%s.%s" % (stub_profile_name, item["key"]) + self.assertEqual( + conanfile.command[i+1], + "qbs-config --settings-dir %s %s. %s" % ( + conanfile.build_folder, key, item["value"])) + + def test_generating_config_command_line(self): + name = "default" + dict = { + "modules.cpp.cxxFlags": ["-frtti", "-fexceptions"], + "modules.cpp.ldFlags": "--defsym=hello_world", + "products.App.myIntProperty": 13, + "products.App.myBoolProperty": True + } + self.assetEqual( + qbs._configuration_dict_to_commandlist(name, dict), + 'config:%s %s:["%s"] %s:"%s" %s:%s %s:%s' % ( + name, + "modules.cpp.cxxFlags", + '", "'.join(dict["modules.cpp.cxxFlags"]), + "modules.cpp.ldFlags", + dict["modules.cpp.ldFlags"], + "products.App.myIntProperty", + dict["products.App.myIntProperty"], + "products.App.myBoolProperty", "true")) + + def test_construct_build_helper_without_project_file(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile) + self.assertEqual(build_helper.jobs, tools.cpu_count()) + self.assertEqual(build_helper._project_file, conanfile.source_folder) + + def test_construct_build_helper_with_project_file(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile, project_file=conanfile.source_folder) + self.assertEqual(build_helper._project_file, conanfile.source_folder) + + def test_construct_build_helper_with_wrong_project_file_path(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + with self.assertRaises(qbs.QbsException): + qbs.Qbs(conanfile, project_file="random/file/path") + + def test_setup_profile(self): + conanfile = ConanFileMockWithMultipleCommands() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile) + + conanfile.command = [] + stub_profile_name = "stub_profile" + base_profile_name = build_helper._base_profile_name + key = "testKey" + value = "testValue" + expected_key = "profiles.%s.%s" % (stub_profile_name, key) + build_helper.setup_profile(stub_profile_name, {key, value}) + self.assertEqual(len(conanfile.command), 2) + self.assertEqual( + conanfile.command[0], + "qbs-config --settings-dir . %s profiles.%s.baseProfile %s" % ( + conanfile.build_folder, stub_profile_name, base_profile_name)) + self.assertEqual( + conanfile.command[1], + "qbs-config --settings-dir . %s %s %s" % ( + conanfile.build_folder, expected_key, value)) + + def test_add_configuration(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile) + configurations = [ + {"name": "debug", + "values": {"modules.cpp.cxxFlags": ["-frtti", "-fexceptions"]}}, + {"name": "release", + "values": {"modules.cpp.cxxFlags": ["-fno-exceptions", + "-fno-rtti"]}} + ] + for config in configurations: + build_helper.add_configuration(config["name"], config["values"]) + self.assertEqual(build_helper._configuration, configurations) + + def test_build(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile) + + self.assertEqual( + conanfile.command, + ("qbs build --no-install --settings-dir %s --build-directory %s " + "--file %s --jobs %s profile:%s") % ( + conanfile.build_folder, + conanfile.build_folder, build_helper._project_file, + build_helper.jobs, build_helper._base_profile_name)) + + def test_build_with_custom_configuration(self): + conanfile = ConanFileMock() + conanfile.settings = {"os": "Linux", "compiler": "gcc"} + build_helper = qbs.Qbs(conanfile) + config_name = "debug" + config_values = {"product.App.customProperty": []} + build_helper.add_configuration(config_name, config_values) From 595cdaa3c4c4e1136b4e93e84ff72c909b432146 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Fri, 20 Nov 2020 20:56:51 +0100 Subject: [PATCH 02/23] Added implementation of qbs toolchain --- conans/client/toolchain/qbs/__init__.py | 5 + conans/client/toolchain/qbs/generic.py | 152 +++++++++++ .../client/toolchain/test_qbs_generic.py | 235 ++++++++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 conans/client/toolchain/qbs/__init__.py create mode 100644 conans/client/toolchain/qbs/generic.py create mode 100644 conans/test/unittests/client/toolchain/test_qbs_generic.py diff --git a/conans/client/toolchain/qbs/__init__.py b/conans/client/toolchain/qbs/__init__.py new file mode 100644 index 00000000000..7b55f7e0dae --- /dev/null +++ b/conans/client/toolchain/qbs/__init__.py @@ -0,0 +1,5 @@ +from .generic import QbsGenericToolchain + + +def QbsToolchain(conanfile, **kwargs): + return QbsGenericToolchain(conanfile, **kwargs) diff --git a/conans/client/toolchain/qbs/generic.py b/conans/client/toolchain/qbs/generic.py new file mode 100644 index 00000000000..ec0005b88a8 --- /dev/null +++ b/conans/client/toolchain/qbs/generic.py @@ -0,0 +1,152 @@ +import shlex +import platform +import textwrap + +from io import StringIO +from jinja2 import Template +from conans import tools +from conans.errors import ConanException +from conans.util.files import save + +_profile_name = "conan" +_profiles_prefix_in_config = "profiles.%s" % _profile_name + + +class QbsException(ConanException): + def __str__(self): + msg = super(QbsException, self).__str__() + return "Qbs build helper: {}".format(msg) + + +def _env_var_to_list(var): + return list(shlex.shlex(var, posix=True, punctuation_chars=True)) + + +def _check_for_compiler(conanfile): + compiler = conanfile.settings.get_safe("compiler") + if not compiler: + raise QbsException("need compiler to be set in settings") + + if compiler not in ["Visual Studio", "gcc", "clang"]: + raise QbsException("compiler not supported") + + +def _compiler_name(conanfile): + # needs more work since currently only windows and linux is supported + compiler = conanfile.settings.get_safe("compiler") + the_os = conanfile.settings.get_safe("os") + if the_os == "Windows": + if compiler == "gcc": + return "mingw" + if compiler == "Visual Studio": + if tools.msvs_toolset(conanfile) == "ClangCl": + return "clang-cl" + return "cl" + if compiler == "clang": + return "clang-cl" + raise QbsException("unknown windows compiler") + + if the_os == "Linux": + return compiler + + raise QbsException("unknown compiler") + + +def _settings_dir(conanfile): + return conanfile.build_folder + + +def _setup_toolchains(conanfile): + if tools.get_env("CC"): + compiler = tools.get_env("CC") + else: + compiler = _compiler_name(conanfile) + + env_context = tools.no_op() + if platform.system() == "Windows": + if compiler in ["cl", "clang-cl"]: + env_context = tools.vcvars() + + with env_context: + cmd = "qbs-setup-toolchains --settings-dir %s %s %s" % ( + _settings_dir(conanfile), compiler, _profile_name) + conanfile.run(cmd) + + +def _read_qbs_toolchain_from_config(conanfile): + s = StringIO() + conanfile.run("qbs-config --settings-dir %s --list" % ( + _settings_dir(conanfile)), output=s) + config = {} + s.seek(0) + for line in s: + colon = line.index(':') + if 0 < colon and not line.startswith('#'): + full_key = line[:colon] + if full_key.startswith(_profiles_prefix_in_config): + key = full_key[len(_profiles_prefix_in_config)+1:] + value = line[colon+1:].strip() + if value.startswith('"') and value.endswith('"'): + temp_value = value[1:-1] + if (temp_value.isnumeric() or + temp_value in ['true', 'false', 'undefined']): + value = temp_value + config[key] = value + return config + + +def _flags_from_env(): + flags_from_env = {} + if tools.get_env("ASFLAGS"): + flags_from_env["cpp.assemblerFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("ASFLAGS"))) + if tools.get_env("CFLAGS"): + flags_from_env["cpp.cFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CFLAGS"))) + if tools.get_env("CPPFLAGS"): + flags_from_env["cpp.cppFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CPPFLAGS"))) + if tools.get_env("CXXFLAGS"): + flags_from_env["cpp.cxxFlags"] = '%s' % ( + _env_var_to_list(tools.get_env("CXXFLAGS"))) + if tools.get_env("LDFLAGS"): + ld_flags = [] + for item in _env_var_to_list(tools.get_env("LDFLAGS")): + if item not in ['-Wl', ',']: + ld_flags.append(item) + flags_from_env["cpp.linkerFlags"] = str(ld_flags) + return flags_from_env + + +class QbsGenericToolchain(object): + filename = "conan_toolchain.qbs" + + _template_toolchain = textwrap.dedent('''\ + import qbs + + Project { + Profile { + name: "conan_toolchain_profile" + {%- for key, value in profile_values.items() %} + {{ key }}: {{ value }} + {%- endfor %} + } + } + ''') + + def __init__(self, conanfile): + _check_for_compiler(conanfile) + self._conanfile = conanfile + _setup_toolchains(conanfile) + self._profile_values = _read_qbs_toolchain_from_config(conanfile) + self._profile_values.update(_flags_from_env()) + + def write_toolchain_files(self): + save(self.filename, self.content) + + @property + def content(self): + context = {"profile_values": self._profile_values} + t = Template(self._template_toolchain) + content = t.render(**context) + return content diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py new file mode 100644 index 00000000000..1802bcfef46 --- /dev/null +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -0,0 +1,235 @@ +import unittest +import textwrap +import conans.client.toolchain.qbs.generic as qbs + +from conans.client import tools +from conans.test.utils.mocks import MockConanfile, MockSettings + + +class RunnerMock(object): + class Expectation(object): + def __init__(self, return_ok=True, output=None): + self.return_ok = return_ok + self.output = output + + def __init__(self, expectations=[Expectation()]): + self.command_called = [] + self.expectations = expectations + + def __call__(self, command, output, win_bash=False, subsystem=None): + self.command_called.append(command) + self.win_bash = win_bash + self.subsystem = subsystem + if not self.expectations: + return 1 + expectation = self.expectations.pop(0) + if expectation.output and output and hasattr(output, "write"): + output.write(expectation.output) + return 0 if expectation.return_ok else 1 + + +class MockConanfileWithFolders(MockConanfile): + build_folder = "just/some/foobar/path" + + def run(self, *args, **kwargs): + if self.runner: + if "output" not in kwargs: + kwargs["output"] = None + self.runner(*args, **kwargs) + + +class QbsGenericTest(unittest.TestCase): + def test_split_env_var_into_list(self): + list = ['-p1', '-p2', '-p3_with_value=13', + '-p_with_space1="hello world"', + '"-p_with_space2=Hello World"'] + expected_list = ['-p1', '-p2', '-p3_with_value=13', + '-p_with_space1=hello world', + '-p_with_space2=Hello World'] + env_var = " ".join(list) + self.assertEqual(qbs._env_var_to_list(env_var), expected_list) + + def test_compiler_not_in_settings(self): + conanfile = MockConanfile(MockSettings({})) + with self.assertRaises(qbs.QbsException): + qbs._check_for_compiler(conanfile) + + def test_compiler_in_settings_not_supported(self): + conanfile = MockConanfile( + MockSettings({"compiler": "not realy a compiler name"})) + with self.assertRaises(qbs.QbsException): + qbs._check_for_compiler(conanfile) + + def test_valid_compiler(self): + supported_compilers = ["Visual Studio", "gcc", "clang"] + for compiler in supported_compilers: + conanfile = MockConanfile(MockSettings({"compiler": compiler})) + qbs._check_for_compiler(conanfile) + + @staticmethod + def _settings_to_test_against(): + return [ + {"os": "Windows", "compiler": "gcc", "qbs_compiler": "mingw"}, + {"os": "Windows", "compiler": "clang", + "qbs_compiler": "clang-cl"}, + {"os": "Windows", "compiler": "Visual Studio", + "qbs_compiler": "cl"}, + {"os": "Windows", "compiler": "Visual Studio", + "compiler.toolset": "ClangCl", "qbs_compiler": "clang-cl"}, + {"os": "Linux", "compiler": "gcc", "qbs_compiler": "gcc"}, + {"os": "Linux", "compiler": "clang", "qbs_compiler": "clang"} + ] + + def test_convert_compiler_name_to_qbs_compiler_name(self): + for settings in self._settings_to_test_against(): + def expected(): + return settings["qbs_compiler"] + conanfile = MockConanfile(MockSettings(settings)) + self.assertEqual(qbs._compiler_name(conanfile), expected()) + + def test_settings_dir_location(self): + conanfile = MockConanfileWithFolders(MockSettings({})) + self.assertEqual(qbs._settings_dir(conanfile), conanfile.build_folder) + + def test_setup_toolchain_without_any_env_values(self): + for settings in self._settings_to_test_against(): + conanfile = MockConanfileWithFolders(MockSettings(settings), + runner=RunnerMock()) + qbs._setup_toolchains(conanfile) + self.assertEqual(len(conanfile.runner.command_called), 1) + self.assertEqual( + conanfile.runner.command_called[0], + "qbs-setup-toolchains --settings-dir %s %s %s" % ( + conanfile.build_folder, settings["qbs_compiler"], + qbs._profile_name)) + + def test_setup_toolchain_with_compiler_from_env(self): + compiler = "compiler_from_env" + for settings in self._settings_to_test_against(): + conanfile = MockConanfileWithFolders(MockSettings(settings), + runner=RunnerMock()) + with tools.environment_append({"CC": compiler}): + qbs._setup_toolchains(conanfile) + self.assertEqual(len(conanfile.runner.command_called), 1) + self.assertEqual( + conanfile.runner.command_called[0], + "qbs-setup-toolchains --settings-dir %s %s %s" % ( + conanfile.build_folder, compiler, + qbs._profile_name)) + + @staticmethod + def _generate_flags(flag, qbs_key): + return {"env": ('-{0}1 -{0}2 -{0}3_with_value=13 ' + '-{0}_with_space="hello world"').format(flag), + "qbs_value": ("['-{0}1', '-{0}2', '-{0}3_with_value=13', " + "'-{0}_with_space=hello world']").format(flag), + "qbs_key": qbs_key} + + def test_flags_from_env(self): + asm = self._generate_flags("asm", "assemblerFlags") + c = self._generate_flags("c", "cFlags") + cpp = self._generate_flags("cpp", "cppFlags") + cxx = self._generate_flags("cxx", "cxxFlags") + wl = self._generate_flags("Wl,", "linkerFlags") + ld = self._generate_flags("ld", "linkerFlags") + env = { + "ASFLAGS": asm["env"], + "CFLAGS": c["env"], + "CPPFLAGS": cpp["env"], + "CXXFLAGS": cxx["env"], + "LDFLAGS": "%s -Wl,%s" % (wl["env"], ld["env"].replace(" -", ",-")) + } + with tools.environment_append(env): + flags_from_env = qbs._flags_from_env() + + expected_flags = { + 'cpp.'+asm["qbs_key"]: asm["qbs_value"], + 'cpp.'+c["qbs_key"]: c["qbs_value"], + 'cpp.'+cpp["qbs_key"]: cpp["qbs_value"], + 'cpp.'+cxx["qbs_key"]: cxx["qbs_value"], + 'cpp.'+wl["qbs_key"]: ("%s%s" % (wl["qbs_value"], + ld["qbs_value"])).replace( + "][", ", ", 1).replace( + "-Wl,", ""), + } + self.assertEqual(flags_from_env, expected_flags) + + @staticmethod + def _generate_qbs_config_output(): + return textwrap.dedent('''\ + profiles.conan.cpp.cCompilerName: "gcc" + profiles.conan.cpp.compilerName: "g++" + profiles.conan.cpp.cxxCompilerName: "g++" + profiles.conan.cpp.driverFlags: \ + ["-march=armv7e-m", "-mtune=cortex-m4", "--specs=nosys.specs"] + profiles.conan.cpp.platformCommonCompilerFlags: undefined + profiles.conan.cpp.platformLinkerFlags: undefined + profiles.conan.cpp.toolchainInstallPath: "/usr/bin" + profiles.conan.cpp.toolchainPrefix: "arm-none-eabi-" + profiles.conan.qbs.targetPlatform: "" + profiles.conan.qbs.someBoolProp: "true" + profiles.conan.qbs.someIntProp: "13" + profiles.conan.qbs.toolchain: ["gcc"] + ''') + + def test_read_qbs_toolchain_from_qbs_config_output(self): + expected_config = { + 'cpp.cCompilerName': '"gcc"', + 'cpp.compilerName': '"g++"', + 'cpp.cxxCompilerName': '"g++"', + 'cpp.driverFlags': '["-march=armv7e-m", "-mtune=cortex-m4", "--specs=nosys.specs"]', + 'cpp.platformCommonCompilerFlags': 'undefined', + 'cpp.platformLinkerFlags': 'undefined', + 'cpp.toolchainInstallPath': '"/usr/bin"', + 'cpp.toolchainPrefix': '"arm-none-eabi-"', + 'qbs.targetPlatform': '""', + 'qbs.someBoolProp': 'true', + 'qbs.someIntProp': '13', + 'qbs.toolchain': '["gcc"]' + } + + conanfile = MockConanfileWithFolders( + MockSettings({}), runner=RunnerMock( + expectations=[RunnerMock.Expectation( + output=self._generate_qbs_config_output())])) + config = qbs._read_qbs_toolchain_from_config(conanfile) + self.assertEqual(len(conanfile.runner.command_called), 1) + self.assertEqual(conanfile.runner.command_called[0], + "qbs-config --settings-dir %s --list" % ( + conanfile.build_folder)) + self.assertEqual(config, expected_config) + + def test_toolchain_content(self): + expected_content = textwrap.dedent('''\ + import qbs + + Project { + Profile { + name: "conan_toolchain_profile" + cpp.cCompilerName: "gcc" + cpp.compilerName: "g++" + cpp.cxxCompilerName: "g++" + cpp.driverFlags: ["-march=armv7e-m", "-mtune=cortex-m4", "--specs=nosys.specs"] + cpp.platformCommonCompilerFlags: undefined + cpp.platformLinkerFlags: undefined + cpp.toolchainInstallPath: "/usr/bin" + cpp.toolchainPrefix: "arm-none-eabi-" + qbs.targetPlatform: "" + qbs.someBoolProp: true + qbs.someIntProp: 13 + qbs.toolchain: ["gcc"] + } + }''') + + conanfile = MockConanfileWithFolders( + MockSettings({"compiler": "gcc", "os": "Linux"}), + runner=RunnerMock( + expectations=[ + RunnerMock.Expectation(), + RunnerMock.Expectation( + output=self._generate_qbs_config_output()), + ])) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + + self.assertEqual(qbs_toolchain.content, expected_content) From c2cfb5be13d604fb8675a0ad6aada7eb32377bb3 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 21 Nov 2020 16:33:44 +0100 Subject: [PATCH 03/23] Finished first implementation of Qbs build helper --- conans/client/build/qbs.py | 171 ++------- .../test/unittests/client/build/qbs_test.py | 327 ++++++------------ 2 files changed, 130 insertions(+), 368 deletions(-) diff --git a/conans/client/build/qbs.py b/conans/client/build/qbs.py index bb0202b78ec..807d8c2e716 100644 --- a/conans/client/build/qbs.py +++ b/conans/client/build/qbs.py @@ -1,5 +1,4 @@ import os -import platform from conans import tools from conans.errors import ConanException @@ -11,139 +10,9 @@ def __str__(self): return "Qbs build helper: {}".format(msg) -def _qbs_config(conanfile, profile_name, values): - key_prefix = "profiles.%s" % profile_name - for key, value in values.items(): - config_key = "%s.%s" % (key_prefix, key) - if type(value) is bool: - if value: - value = 'true' - else: - value = 'false' - cmd = 'qbs-config --settings-dir %s %s "%s"' % ( - _settings_dir(conanfile), config_key, value) - conanfile.run(cmd) - - -def _env_var_to_list(var): - elements = [] - flag_groups = var.split('"') - - latest_flag = '' - for i in range(len(flag_groups)): - if not flag_groups[i]: - continue - - def is_quoted_flag(): - return i % 2 - - if is_quoted_flag(): - if latest_flag: - elements.append(latest_flag + flag_groups[i]) - else: - elements.append(flag_groups[i]) - else: - flags = flag_groups[i].split() - latest_flag = flags.pop() - for s in flags: - elements.append(s) - if not latest_flag.endswith('='): - elements.append(latest_flag) - latest_flag = '' - - return elements - - -def _check_for_compiler(conanfile): - compiler = conanfile.settings.get_safe("compiler") - if not compiler: - raise QbsException("need compiler to be set in settings") - - if compiler not in ["Visual Studio", "gcc", "clang"]: - raise QbsException("compiler not supported") - - -def _compiler_name(conanfile): - # needs more work since currently only windows and linux is supported - compiler = conanfile.settings.compiler - if platform.system() == "Windows": - if compiler == "gcc": - return "mingw" - if compiler == "Visual Studio": - if tools.msvs_toolset(conanfile) == "ClangCl": - return "clang-cl" - return "cl" - if compiler == "clang": - return "clang-cl" - raise QbsException("unknown windows compiler") - - if platform.system() == "Linux": - return compiler - - raise QbsException("unknown compiler") - - -def _generate_profile_name(conanfile): - compiler = "_%s" % (conanfile.settings.get_safe("compiler")) - compiler_version = conanfile.settings.compiler.get_safe( - "version") - if compiler_version: - compiler_version = '_' + compiler_version - the_os = conanfile.settings.get_safe("os") - if the_os: - the_os = '_' + the_os - - return "_conan%s%s%s" % (the_os, compiler, compiler_version) - - -def _settings_dir(conanfile): - return conanfile.build_folder - - -def _setup_toolchain(conanfile, profile_name): - if tools.get_env("CC"): - compiler = tools.get_env("CC") - else: - compiler = _compiler_name(conanfile) - - env_context = tools.no_op() - if platform.system() == "Windows": - if compiler in ["cl", "clang-cl"]: - env_context = tools.vcvars() - - with env_context: - cmd = "qbs-setup-toolchains --settings-dir %s %s %s" % ( - _settings_dir(conanfile), compiler, profile_name) - conanfile.run(cmd) - - flags_from_env = {} - if tools.get_env("ASFLAGS"): - flags_from_env["cpp.assemblerFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("ASFLAGS"))) - if tools.get_env("CFLAGS"): - flags_from_env["cpp.cFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CFLAGS"))) - if tools.get_env("CPPFLAGS"): - flags_from_env["cpp.cppFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CPPFLAGS"))) - if tools.get_env("CXXFLAGS"): - flags_from_env["cpp.cxxFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CXXFLAGS"))) - if tools.get_env("LDFLAGS"): - ld_flags = [] - for item in _env_var_to_list(tools.get_env("LDFLAGS")): - flags = item[len("-Wl,"):] - ld_flags.extend(flags.split(",")) - flags_from_env["cpp.linkerFlags"] = '%s' % (ld_flags) - - if flags_from_env: - _qbs_config(conanfile, profile_name, flags_from_env) - - def _configuration_dict_to_commandlist(name, dict): command_list = ["config:%s" % name] - for key in dict: - value = dict[key] + for key, value in dict.items(): if type(value) is bool: if value: b = "true" @@ -157,14 +26,10 @@ def _configuration_dict_to_commandlist(name, dict): class Qbs(object): def __init__(self, conanfile, project_file=None): - _check_for_compiler(conanfile) self._conanfile = conanfile self._set_project_file(project_file) - self._base_profile_name = _generate_profile_name(conanfile) - _setup_toolchain(conanfile, self._base_profile_name) self.jobs = tools.cpu_count() self._configuration = dict() - self._profile_name = "" def _set_project_file(self, project_file): if not project_file: @@ -175,33 +40,37 @@ def _set_project_file(self, project_file): if not os.path.exists(self._project_file): raise QbsException("could not find project file") - def setup_profile(self, name, values): - temp = {"baseProfile": self._base_profile_name} - temp.update(values) - _qbs_config(self._conanfile, name, temp) - self._profile_name = name - def add_configuration(self, name, values): self._configuration[name] = values - def build(self, all_products=False, products=[]): - if not self._profile_name: - self._profile_name = self._base_profile_name - + def build(self, products=[]): args = [ "--no-install", - "--settings-dir", _settings_dir(self._conanfile), "--build-directory", self._conanfile.build_folder, "--file", self._project_file, ] - if all_products: - args.append("--all-products") if products: - args.extend(["-p", ",".join(products)]) + args.extend(["--products", ",".join(products)]) + + args.extend(["--jobs", "%s" % self.jobs]) + + for name in self._configuration: + config = self._configuration[name] + args.extend(_configuration_dict_to_commandlist(name, config)) + + cmd = "qbs build %s" % (" ".join(args)) + self._conanfile.run(cmd) + + def build_all(self): + args = [ + "--no-install", + "--build-directory", self._conanfile.build_folder, + "--file", self._project_file, + "--all-products" + ] args.extend(["--jobs", "%s" % self.jobs]) - args.append("profile:%s" % self._profile_name) for name in self._configuration: config = self._configuration[name] diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 2d5058c1c2d..8257147095f 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -2,168 +2,25 @@ import conans.client.build.qbs as qbs from conans.client import tools -from conans.test.utils.mocks import ConanFileMock, MockSettings +from conans.test.utils.mocks import MockConanfile, MockSettings -class ConanFileMockWithMultipleCommands(ConanFileMock): - def __init__(self): - self.command = [] +class RunnerMock(object): + def __init__(self, return_ok=True, output=None): + self.command_called = None + self.return_ok = return_ok + self.output = output - def run(self, command): - self.command.append(command) + def __call__(self, command, output, win_bash=False, subsystem=None): + self.command_called = command + self.win_bash = win_bash + self.subsystem = subsystem + if self.output and output and hasattr(output, "write"): + output.write(self.output) + return 0 if self.return_ok else 1 class QbsTest(unittest.TestCase): - def test_call_qbs_config_with_single_value(self): - conanfile = ConanFileMock() - profile_name = "my_fancy_profile" - key = "test_key" - value = "test_value" - expected_key = "profiles.%s.%s" % (profile_name, key) - expected_value = value - qbs._qbs_config(conanfile, profile_name, value) - self.assertEqual(conanfile.command, - "qbs-config --settings-dir %s %s %s" % ( - conanfile.build_folder, expected_key, - expected_value)) - - def test_split_env_var_into_list(self): - expected_list = ['-p1', '-p2', '-p3_with_value=13', - '-p_with_space1="hello world"', - '"-p_with_space2=Hello World"'] - env_var = " ".join(expected_list) - self.assertEqual(qbs._env_var_to_list(env_var), expected_list) - - def test_compiler_not_in_settings(self): - conanfile = ConanFileMock() - conanfile.settings = MockSettings() - with self.assertRaises(qbs.QbsException): - qbs._check_for_compiler(conanfile) - - def test_compiler_in_settings_not_supported(self): - conanfile = ConanFileMock() - conanfile.settings = MockSettings({"compiler": - "not realy a compiler name"}) - with self.assertRaises(qbs.QbsException): - qbs._check_for_compiler(conanfile) - - def test_valid_compiler(self): - supported_compilers = ["Visual Studio", "gcc", "clang"] - for compiler in supported_compilers: - conanfile = ConanFileMock() - conanfile.settings = MockSettings({"compiler": compiler}) - qbs._check_for_compiler(conanfile) - - @staticmethod - def _settings_to_test_against(self): - return [ - {"os": "Windows", "compiler": "gcc", "qbs_compiler": "mingw"}, - {"os": "Windows", "compiler": "clang", - "qbs_compiler": "clang-cl"}, - {"os": "Windows", "compiler": "Visual Studio", - "qbs_compiler": "cl"}, - {"os": "Windows", "compiler": "Visual Studio", - "toolset": "ClangCl", "qbs_compiler": "clang-cl"}, - {"os": "Linux", "compiler": "gcc", "qbs_compiler": "gcc"}, - {"os": "Linux", "compiler": "clang", "qbs_compiler": "clang"} - ] - - def test_convert_compiler_name_to_qbs_compiler_name(self): - for settings in self._settings_to_test_against(): - def expected(): - return settings["qbs_compiler"] - conanfile = ConanFileMock() - conanfile.settings = settings - self.assertEqual(qbs._compiler_name(conanfile), expected()) - - def test_settings_dir_location(self): - conanfile = ConanFileMock() - self.assertEqual(qbs._settings_dir(conanfile), conanfile.build_folder) - - def test_setup_toolchain_without_any_env_values(self): - stub_profile_name = "foobar" - for settings in self._settings_to_test_against(): - conanfile = ConanFileMockWithMultipleCommands() - conanfile.settings = settings - qbs._setup_toolchain(conanfile, stub_profile_name) - self.assertEqual(len(conanfile.command), 1) - self.assertEqual( - conanfile.command[0], - "qbs-setup-toolchains --settings-dir %s %s %s" % ( - conanfile.build_folder, settings["qbs_compiler"], - stub_profile_name)) - - def test_setup_toolchain_with_compiler_from_env(self): - compiler = "compiler_from_env" - stub_profile_name = "foobar" - for settings in self._settings_to_test_against(): - conanfile = ConanFileMockWithMultipleCommands() - conanfile.settings = settings - with tools.environment_append({"CC": compiler}): - qbs._setup_toolchain(conanfile, stub_profile_name) - self.assertEqual(len(conanfile.command), 1) - self.assertEqual( - conanfile.command[0], - "qbs-setup-toolchains --settings-dir %s %s %s" % ( - conanfile.build_folder, compiler, - stub_profile_name)) - - @staticmethod - def _generate_flags(flag, qbs_key): - return {"env": ('-{0}1 -{0}2 -{0}3_with_value=13 ' - '-{0}_with_space1="hello world" ' - '"-{0}_with_space2=Hello World"').format(flag), - "qbs_value": ('["-{0}1", "-{0}2", "-{0}3_with_value=13", ' - '"-{0}_with_space1=hello world", ' - '"-{0}_with_space2=Hello World"').format(flag), - "qbs_key": qbs_key} - - def test_setup_toolchain_with_flags_from_env(self): - stub_profile_name = "foobar" - conanfile = ConanFileMockWithMultipleCommands() - compiler = "gcc" - conanfile.settings = {"os": "Linux", "compiler": compiler} - - asm = self._generate_flags("asm", "assemblerFlags") - c = self._generate_flags("c", "cFlags") - cpp = self._generate_flags("cpp", "cppFlags") - cxx = self._generate_flags("cxx", "cxxFlags") - wl = self._generate_flags("Wl,", "linkerFlags") - ld = self._generate_flags("ld", "linkerFlags") - env = { - "ASFLAGS": asm["env"], - "CFLAGS": c["env"], - "CPPFLAGS": cpp["env"], - "CXXFLAGS": cxx["env"], - "LDFLAGS": wl["env"] + "-Wl," + ld["env"].replace(" -", ",-") - } - with tools.environment_append(env): - qbs._setup_toolchain(conanfile, stub_profile_name) - self.assertEqual(len(conanfile.command), 1 + len(env)) - self.assertEqual( - conanfile.command[0], - "qbs-setup-toolchains --settings-dir %s %s %s" % ( - conanfile.build_folder, compiler, - stub_profile_name)) - - qbs_config = [ - {"key": asm["qbs_key"], "value": asm["qbs_value"]}, - {"key": c["qbs_key"], "value": c["qbs_value"]}, - {"key": cpp["qbs_key"], "value": cpp["qbs_value"]}, - {"key": cxx["qbs_key"], "value": cxx["qbs_value"]}, - {"key": wl["qbs_key"], - "value": (wl["qbs_value"] + - ld["qbs_values"]).replace("][", ", ", 1)}, - ] - self.assertEqual(len(conanfile.command)-1, len(qbs_config)) - for i in range(len(qbs_config)): - item = qbs_config[i] - key = "profiles.%s.%s" % (stub_profile_name, item["key"]) - self.assertEqual( - conanfile.command[i+1], - "qbs-config --settings-dir %s %s. %s" % ( - conanfile.build_folder, key, item["value"])) - def test_generating_config_command_line(self): name = "default" dict = { @@ -172,91 +29,127 @@ def test_generating_config_command_line(self): "products.App.myIntProperty": 13, "products.App.myBoolProperty": True } - self.assetEqual( + expected_config_line = [ + 'config:%s' % name, + ] + for key, value in dict.items(): + if type(value) is bool: + if value: + value = 'true' + else: + value = 'false' + expected_config_line.append('%s:%s' % (key, value)) + print(qbs._configuration_dict_to_commandlist(name, dict)) + print(expected_config_line) + self.assertEqual( qbs._configuration_dict_to_commandlist(name, dict), - 'config:%s %s:["%s"] %s:"%s" %s:%s %s:%s' % ( - name, - "modules.cpp.cxxFlags", - '", "'.join(dict["modules.cpp.cxxFlags"]), - "modules.cpp.ldFlags", - dict["modules.cpp.ldFlags"], - "products.App.myIntProperty", - dict["products.App.myIntProperty"], - "products.App.myBoolProperty", "true")) + expected_config_line) def test_construct_build_helper_without_project_file(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"})) + conanfile.source_folder = '.' build_helper = qbs.Qbs(conanfile) self.assertEqual(build_helper.jobs, tools.cpu_count()) self.assertEqual(build_helper._project_file, conanfile.source_folder) def test_construct_build_helper_with_project_file(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} - build_helper = qbs.Qbs(conanfile, project_file=conanfile.source_folder) - self.assertEqual(build_helper._project_file, conanfile.source_folder) + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"})) + # just asume that the test is called from repo root + profile_file_path = "conans/client" + build_helper = qbs.Qbs(conanfile, project_file=profile_file_path) + self.assertEqual(build_helper._project_file, profile_file_path) def test_construct_build_helper_with_wrong_project_file_path(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"})) with self.assertRaises(qbs.QbsException): qbs.Qbs(conanfile, project_file="random/file/path") - def test_setup_profile(self): - conanfile = ConanFileMockWithMultipleCommands() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} - build_helper = qbs.Qbs(conanfile) - - conanfile.command = [] - stub_profile_name = "stub_profile" - base_profile_name = build_helper._base_profile_name - key = "testKey" - value = "testValue" - expected_key = "profiles.%s.%s" % (stub_profile_name, key) - build_helper.setup_profile(stub_profile_name, {key, value}) - self.assertEqual(len(conanfile.command), 2) - self.assertEqual( - conanfile.command[0], - "qbs-config --settings-dir . %s profiles.%s.baseProfile %s" % ( - conanfile.build_folder, stub_profile_name, base_profile_name)) - self.assertEqual( - conanfile.command[1], - "qbs-config --settings-dir . %s %s %s" % ( - conanfile.build_folder, expected_key, value)) - def test_add_configuration(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"})) + conanfile.source_folder = '.' build_helper = qbs.Qbs(conanfile) - configurations = [ - {"name": "debug", - "values": {"modules.cpp.cxxFlags": ["-frtti", "-fexceptions"]}}, - {"name": "release", - "values": {"modules.cpp.cxxFlags": ["-fno-exceptions", - "-fno-rtti"]}} - ] - for config in configurations: - build_helper.add_configuration(config["name"], config["values"]) + configurations = { + "debug": {"products.MyLib.specialFlags": ["-frtti", + "-fexceptions"]}, + "release": {"products.MyLib.specialFlags": ["-fno-exceptions", + "-fno-rtti"]} + } + for name, config in configurations.items(): + build_helper.add_configuration(name, config) self.assertEqual(build_helper._configuration, configurations) def test_build(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"}), + runner=RunnerMock()) + conanfile.source_folder = '.' + conanfile.build_folder = '.' build_helper = qbs.Qbs(conanfile) + build_helper.build() self.assertEqual( - conanfile.command, - ("qbs build --no-install --settings-dir %s --build-directory %s " - "--file %s --jobs %s profile:%s") % ( - conanfile.build_folder, + conanfile.runner.command_called, + ("qbs build --no-install --build-directory %s " + "--file %s --jobs %s") % ( conanfile.build_folder, build_helper._project_file, - build_helper.jobs, build_helper._base_profile_name)) + build_helper.jobs)) + + build_helper.build(products=["app1", "app2", "lib"]) + self.assertEqual( + conanfile.runner.command_called, + ("qbs build --no-install --build-directory %s " + "--file %s --products app1,app2,lib --jobs %s") % ( + conanfile.build_folder, build_helper._project_file, + build_helper.jobs)) + + def test_build_all(self): + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"}), + runner=RunnerMock()) + conanfile.source_folder = '.' + conanfile.build_folder = '.' + build_helper = qbs.Qbs(conanfile) + + build_helper.build_all() + self.assertEqual( + conanfile.runner.command_called, + ("qbs build --no-install --build-directory %s " + "--file %s --all-products --jobs %s") % ( + conanfile.build_folder, build_helper._project_file, + build_helper.jobs)) def test_build_with_custom_configuration(self): - conanfile = ConanFileMock() - conanfile.settings = {"os": "Linux", "compiler": "gcc"} + conanfile = MockConanfile( + MockSettings({"os": "Linux", "compiler": "gcc"}), + runner=RunnerMock()) + conanfile.source_folder = '.' + conanfile.build_folder = '.' build_helper = qbs.Qbs(conanfile) config_name = "debug" - config_values = {"product.App.customProperty": []} + config_values = { + 'product.App.boolProperty': True, + 'product.App.intProperty': 1337, + 'product.App.stringProperty': 'Hello World', + 'product.App.stringListProperty': ['Hello', 'World'] + } build_helper.add_configuration(config_name, config_values) + build_helper.build() + self.assertEqual( + conanfile.runner.command_called, + ("qbs build --no-install --build-directory %s " + "--file %s --jobs %s " + "config:%s %s:%s %s:%s %s:%s %s:%s") % ( + conanfile.build_folder, build_helper._project_file, + build_helper.jobs, config_name, + 'product.App.boolProperty', + 'true', + 'product.App.intProperty', + config_values['product.App.intProperty'], + 'product.App.stringProperty', + config_values['product.App.stringProperty'], + 'product.App.stringListProperty', + config_values['product.App.stringListProperty'])) From 1f9906138347efac4199db7449ed4c0bb4f66d9c Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 21 Nov 2020 17:18:05 +0100 Subject: [PATCH 04/23] Changed build_folder to install_folder since build_folder might not be set when calling conan install --- conans/client/toolchain/qbs/generic.py | 5 +++-- .../client/toolchain/test_qbs_generic.py | 16 +++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/conans/client/toolchain/qbs/generic.py b/conans/client/toolchain/qbs/generic.py index ec0005b88a8..68ce5db7448 100644 --- a/conans/client/toolchain/qbs/generic.py +++ b/conans/client/toolchain/qbs/generic.py @@ -15,7 +15,7 @@ class QbsException(ConanException): def __str__(self): msg = super(QbsException, self).__str__() - return "Qbs build helper: {}".format(msg) + return "Qbs generic toolchain: {}".format(msg) def _env_var_to_list(var): @@ -53,7 +53,7 @@ def _compiler_name(conanfile): def _settings_dir(conanfile): - return conanfile.build_folder + return '%s/conan_qbs_toolchain_settings_dir' % conanfile.install_folder def _setup_toolchains(conanfile): @@ -140,6 +140,7 @@ def __init__(self, conanfile): _setup_toolchains(conanfile) self._profile_values = _read_qbs_toolchain_from_config(conanfile) self._profile_values.update(_flags_from_env()) + tools.rmdir(_settings_dir(conanfile)) def write_toolchain_files(self): save(self.filename, self.content) diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 1802bcfef46..f185a9ae7bb 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,4 +1,5 @@ import unittest +import tempfile import textwrap import conans.client.toolchain.qbs.generic as qbs @@ -29,7 +30,10 @@ def __call__(self, command, output, win_bash=False, subsystem=None): class MockConanfileWithFolders(MockConanfile): - build_folder = "just/some/foobar/path" + install_folder = tempfile.mkdtemp() + + def __del__(self): + tools.rmdir(self.install_folder) def run(self, *args, **kwargs): if self.runner: @@ -89,7 +93,9 @@ def expected(): def test_settings_dir_location(self): conanfile = MockConanfileWithFolders(MockSettings({})) - self.assertEqual(qbs._settings_dir(conanfile), conanfile.build_folder) + self.assertEqual( + qbs._settings_dir(conanfile), + '%s/conan_qbs_toolchain_settings_dir' % conanfile.install_folder) def test_setup_toolchain_without_any_env_values(self): for settings in self._settings_to_test_against(): @@ -100,7 +106,7 @@ def test_setup_toolchain_without_any_env_values(self): self.assertEqual( conanfile.runner.command_called[0], "qbs-setup-toolchains --settings-dir %s %s %s" % ( - conanfile.build_folder, settings["qbs_compiler"], + qbs._settings_dir(conanfile), settings["qbs_compiler"], qbs._profile_name)) def test_setup_toolchain_with_compiler_from_env(self): @@ -114,7 +120,7 @@ def test_setup_toolchain_with_compiler_from_env(self): self.assertEqual( conanfile.runner.command_called[0], "qbs-setup-toolchains --settings-dir %s %s %s" % ( - conanfile.build_folder, compiler, + qbs._settings_dir(conanfile), compiler, qbs._profile_name)) @staticmethod @@ -196,7 +202,7 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual(conanfile.runner.command_called[0], "qbs-config --settings-dir %s --list" % ( - conanfile.build_folder)) + qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) def test_toolchain_content(self): From 3b5989b6a7d4e22f4ec4452677e80daf0fd089ee Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 28 Nov 2020 14:24:06 +0100 Subject: [PATCH 05/23] Added detection of buildVariant, architecture, optimization, sysroot, PIC, cxxLanguageVersion --- conan/tools/qbs/generic.py | 217 ++++++++++++---- .../client/toolchain/test_qbs_generic.py | 235 ++++++++++++++---- 2 files changed, 350 insertions(+), 102 deletions(-) diff --git a/conan/tools/qbs/generic.py b/conan/tools/qbs/generic.py index 68ce5db7448..408c981e777 100644 --- a/conan/tools/qbs/generic.py +++ b/conan/tools/qbs/generic.py @@ -8,14 +8,79 @@ from conans.errors import ConanException from conans.util.files import save -_profile_name = "conan" -_profiles_prefix_in_config = "profiles.%s" % _profile_name +_profile_name = 'conan' +_profiles_prefix_in_config = 'profiles.%s' % _profile_name + +_architecture = { + 'x86': 'x86', + 'x86_64': 'x86_64', + 'ppc32be': 'ppc', + 'ppc32': 'ppc', + 'ppc64le': 'ppc64', + 'ppc64': 'ppc64', + 'armv4': 'arm', + 'armv4i': 'arm', + 'armv5el': 'arm', + 'armv5hf': 'arm', + 'armv6': 'arm', + 'armv7': 'arm', + 'armv7hf': 'arm', + 'armv7s': 'arm', + 'armv7k': 'arm', + 'armv8': 'arm64', + 'armv8_32': 'arm64', + 'armv8.3': 'arm64', + 'sparc': 'sparc', + 'sparcv9': 'sparc64', + 'mips': 'mips', + 'mips64': 'mips64', + 'avr': 'avr', + 's390': 's390x', + 's390x': 's390x', + 'asm.js': None, + 'wasm': None, + 'sh4le': 'sh' +} +_build_variant = { + 'Debug': 'debug', + 'Release': 'release', + 'RelWithDebInfo': 'profiling', + 'MinSizeRel': 'release' +} +_optimization = { + 'MinSizeRel': 'small' +} +_cxx_language_version = { + '98': 'c++98', + 'gnu98': 'c++98', + '11': 'c++11', + 'gnu11': 'c++11', + '14': 'c++14', + 'gnu14': 'c++14', + '17': 'c++17', + 'gnu17': 'c++17', + '20': 'c++20', + 'gnu20': 'c++20' +} class QbsException(ConanException): def __str__(self): msg = super(QbsException, self).__str__() - return "Qbs generic toolchain: {}".format(msg) + return 'Qbs generic toolchain: {}'.format(msg) + + +def _bool(b): + if b is None: + return None + + if type(b)is not bool: + raise QbsException('Tried to convert non bool type value to bool') + + if b: + return 'true' + else: + return 'false' def _env_var_to_list(var): @@ -23,33 +88,30 @@ def _env_var_to_list(var): def _check_for_compiler(conanfile): - compiler = conanfile.settings.get_safe("compiler") + compiler = conanfile.settings.get_safe('compiler') if not compiler: - raise QbsException("need compiler to be set in settings") + raise QbsException('need compiler to be set in settings') - if compiler not in ["Visual Studio", "gcc", "clang"]: - raise QbsException("compiler not supported") + if compiler not in ['Visual Studio', 'gcc', 'clang']: + raise QbsException('compiler not supported') -def _compiler_name(conanfile): +def _default_compiler_name(conanfile): # needs more work since currently only windows and linux is supported - compiler = conanfile.settings.get_safe("compiler") - the_os = conanfile.settings.get_safe("os") - if the_os == "Windows": - if compiler == "gcc": - return "mingw" - if compiler == "Visual Studio": - if tools.msvs_toolset(conanfile) == "ClangCl": - return "clang-cl" - return "cl" - if compiler == "clang": - return "clang-cl" - raise QbsException("unknown windows compiler") + compiler = conanfile.settings.get_safe('compiler') + the_os = conanfile.settings.get_safe('os') + if the_os == 'Windows': + if compiler == 'gcc': + return 'mingw' + if compiler == 'Visual Studio': + if tools.msvs_toolset(conanfile) == 'ClangCl': + return 'clang-cl' + return 'cl' + if compiler == 'clang': + return 'clang-cl' + raise QbsException('unknown windows compiler') - if the_os == "Linux": - return compiler - - raise QbsException("unknown compiler") + return compiler def _settings_dir(conanfile): @@ -57,25 +119,25 @@ def _settings_dir(conanfile): def _setup_toolchains(conanfile): - if tools.get_env("CC"): - compiler = tools.get_env("CC") + if tools.get_env('CC'): + compiler = tools.get_env('CC') else: - compiler = _compiler_name(conanfile) + compiler = _default_compiler_name(conanfile) env_context = tools.no_op() - if platform.system() == "Windows": - if compiler in ["cl", "clang-cl"]: + if platform.system() == 'Windows': + if compiler in ['cl', 'clang-cl']: env_context = tools.vcvars() with env_context: - cmd = "qbs-setup-toolchains --settings-dir %s %s %s" % ( + cmd = 'qbs-setup-toolchains --settings-dir %s %s %s' % ( _settings_dir(conanfile), compiler, _profile_name) conanfile.run(cmd) def _read_qbs_toolchain_from_config(conanfile): s = StringIO() - conanfile.run("qbs-config --settings-dir %s --list" % ( + conanfile.run('qbs-config --settings-dir %s --list' % ( _settings_dir(conanfile)), output=s) config = {} s.seek(0) @@ -97,29 +159,29 @@ def _read_qbs_toolchain_from_config(conanfile): def _flags_from_env(): flags_from_env = {} - if tools.get_env("ASFLAGS"): - flags_from_env["cpp.assemblerFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("ASFLAGS"))) - if tools.get_env("CFLAGS"): - flags_from_env["cpp.cFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CFLAGS"))) - if tools.get_env("CPPFLAGS"): - flags_from_env["cpp.cppFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CPPFLAGS"))) - if tools.get_env("CXXFLAGS"): - flags_from_env["cpp.cxxFlags"] = '%s' % ( - _env_var_to_list(tools.get_env("CXXFLAGS"))) - if tools.get_env("LDFLAGS"): + if tools.get_env('ASFLAGS'): + flags_from_env['cpp.assemblerFlags'] = '%s' % ( + _env_var_to_list(tools.get_env('ASFLAGS'))) + if tools.get_env('CFLAGS'): + flags_from_env['cpp.cFlags'] = '%s' % ( + _env_var_to_list(tools.get_env('CFLAGS'))) + if tools.get_env('CPPFLAGS'): + flags_from_env['cpp.cppFlags'] = '%s' % ( + _env_var_to_list(tools.get_env('CPPFLAGS'))) + if tools.get_env('CXXFLAGS'): + flags_from_env['cpp.cxxFlags'] = '%s' % ( + _env_var_to_list(tools.get_env('CXXFLAGS'))) + if tools.get_env('LDFLAGS'): ld_flags = [] - for item in _env_var_to_list(tools.get_env("LDFLAGS")): + for item in _env_var_to_list(tools.get_env('LDFLAGS')): if item not in ['-Wl', ',']: ld_flags.append(item) - flags_from_env["cpp.linkerFlags"] = str(ld_flags) + flags_from_env['cpp.linkerFlags'] = str(ld_flags) return flags_from_env class QbsGenericToolchain(object): - filename = "conan_toolchain.qbs" + filename = 'conan_toolchain.qbs' _template_toolchain = textwrap.dedent('''\ import qbs @@ -127,9 +189,38 @@ class QbsGenericToolchain(object): Project { Profile { name: "conan_toolchain_profile" - {%- for key, value in profile_values.items() %} + + /* detected via qbs-setup-toolchains */ + {%- for key, value in _profile_values_from_setup.items() %} {{ key }}: {{ value }} {%- endfor %} + + /* deduced from environment */ + {%- for key, value in _profile_values_from_env.items() %} + {{ key }}: {{ value }} + {%- endfor %} + {%- if sysroot %} + qbs.sysroot: "{{ sysroot }}" + {%- endif %} + + /* conan settings */ + {%- if build_variant %} + qbs.buildVariant: "{{ build_variant }}" + {%- endif %} + {%- if architecture %} + qbs.architecture: "{{ architecture }}" + {%- endif %} + {%- if optimization %} + qbs.optimization: "{{ optimization }}" + {%- endif %} + {%- if cxx_language_version %} + cpp.cxxLanguageVersion: "{{ cxx_language_version }}" + {%- endif %} + + /* package options */ + {%- if position_independent_code %} + cpp.positionIndependentCode: {{ position_independent_code }} + {%- endif %} } } ''') @@ -138,16 +229,38 @@ def __init__(self, conanfile): _check_for_compiler(conanfile) self._conanfile = conanfile _setup_toolchains(conanfile) - self._profile_values = _read_qbs_toolchain_from_config(conanfile) - self._profile_values.update(_flags_from_env()) + self._profile_values_from_setup = ( + _read_qbs_toolchain_from_config(conanfile)) + self._profile_values_from_env = _flags_from_env() tools.rmdir(_settings_dir(conanfile)) - def write_toolchain_files(self): + self._architecture = _architecture.get( + conanfile.settings.get_safe('arch')) + self._build_variant = _build_variant.get( + conanfile.settings.get_safe('build_type')) + self._optimization = _optimization.get( + conanfile.settings.get_safe('build_type')) + self._cxx_language_version = _cxx_language_version.get( + str(conanfile.settings.get_safe('compiler.cppstd'))) + self._sysroot = tools.get_env('SYSROOT') + self._position_independent_code = _bool( + conanfile.options.get_safe('fPIC')) + + def generate(self): save(self.filename, self.content) @property def content(self): - context = {"profile_values": self._profile_values} + context = { + '_profile_values_from_setup': self._profile_values_from_setup, + '_profile_values_from_env': self._profile_values_from_env, + 'build_variant': self._build_variant, + 'architecture': self._architecture, + 'optimization': self._optimization, + 'sysroot': self._sysroot, + 'position_independent_code': self._position_independent_code, + 'cxx_language_version': self._cxx_language_version + } t = Template(self._template_toolchain) content = t.render(**context) return content diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index f185a9ae7bb..15d408cf8ff 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -3,8 +3,8 @@ import textwrap import conans.client.toolchain.qbs.generic as qbs -from conans.client import tools -from conans.test.utils.mocks import MockConanfile, MockSettings +from conans import tools +from conans.test.utils.mocks import MockConanfile, MockSettings, MockOptions class RunnerMock(object): @@ -24,7 +24,7 @@ def __call__(self, command, output, win_bash=False, subsystem=None): if not self.expectations: return 1 expectation = self.expectations.pop(0) - if expectation.output and output and hasattr(output, "write"): + if expectation.output and output and hasattr(output, 'write'): output.write(expectation.output) return 0 if expectation.return_ok else 1 @@ -37,12 +37,123 @@ def __del__(self): def run(self, *args, **kwargs): if self.runner: - if "output" not in kwargs: - kwargs["output"] = None + if 'output' not in kwargs: + kwargs['output'] = None self.runner(*args, **kwargs) class QbsGenericTest(unittest.TestCase): + def test_convert_bool(self): + self.assertEqual(qbs._bool(True), 'true') + self.assertEqual(qbs._bool(False), 'false') + with self.assertRaises(qbs.QbsException): + qbs._bool("") + + def test_convert_build_variant(self): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc'})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._build_variant, None) + + for build_type, build_variant in qbs._build_variant.items(): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc', + 'build_type': build_type})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._build_variant, build_variant) + + def test_convert_architecture(self): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc'})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._architecture, None) + + for arch, architecture in qbs._architecture.items(): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc', + 'arch': arch})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._architecture, architecture) + + def test_convert_optimization(self): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc'})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._optimization, None) + + for build_type, optimization in qbs._optimization.items(): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc', + 'build_type': build_type})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._optimization, optimization) + + def test_use_sysroot_from_env(self): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc'})) + + sysroot = '/path/to/sysroot/foo/bar' + with tools.environment_append({'SYSROOT': sysroot}): + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._sysroot, sysroot) + + def test_detect_fpic_from_options(self): + f_pic = { + True: 'true', + False: 'false', + None: None + } + + for option, value in f_pic.items(): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc' + }), + MockOptions({ + 'fPIC': option + })) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._position_independent_code, value) + + def test_convert_cxx_language_version(self): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc'})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._cxx_language_version, None) + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc', + 'compiler.cppstd': 17})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._cxx_language_version, 'c++17') + + for cppstd, cxx_language_version in qbs._cxx_language_version.items(): + conanfile = MockConanfileWithFolders(MockSettings({ + 'os': 'Linux', + 'compiler': 'gcc', + 'compiler.cppstd': cppstd})) + + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + self.assertEqual(qbs_toolchain._cxx_language_version, + cxx_language_version) + def test_split_env_var_into_list(self): list = ['-p1', '-p2', '-p3_with_value=13', '-p_with_space1="hello world"', @@ -50,7 +161,7 @@ def test_split_env_var_into_list(self): expected_list = ['-p1', '-p2', '-p3_with_value=13', '-p_with_space1=hello world', '-p_with_space2=Hello World'] - env_var = " ".join(list) + env_var = ' '.join(list) self.assertEqual(qbs._env_var_to_list(env_var), expected_list) def test_compiler_not_in_settings(self): @@ -60,36 +171,36 @@ def test_compiler_not_in_settings(self): def test_compiler_in_settings_not_supported(self): conanfile = MockConanfile( - MockSettings({"compiler": "not realy a compiler name"})) + MockSettings({'compiler': 'not realy a compiler name'})) with self.assertRaises(qbs.QbsException): qbs._check_for_compiler(conanfile) def test_valid_compiler(self): - supported_compilers = ["Visual Studio", "gcc", "clang"] + supported_compilers = ['Visual Studio', 'gcc', 'clang'] for compiler in supported_compilers: - conanfile = MockConanfile(MockSettings({"compiler": compiler})) + conanfile = MockConanfile(MockSettings({'compiler': compiler})) qbs._check_for_compiler(conanfile) @staticmethod def _settings_to_test_against(): return [ - {"os": "Windows", "compiler": "gcc", "qbs_compiler": "mingw"}, - {"os": "Windows", "compiler": "clang", - "qbs_compiler": "clang-cl"}, - {"os": "Windows", "compiler": "Visual Studio", - "qbs_compiler": "cl"}, - {"os": "Windows", "compiler": "Visual Studio", - "compiler.toolset": "ClangCl", "qbs_compiler": "clang-cl"}, - {"os": "Linux", "compiler": "gcc", "qbs_compiler": "gcc"}, - {"os": "Linux", "compiler": "clang", "qbs_compiler": "clang"} + {'os': 'Windows', 'compiler': 'gcc', 'qbs_compiler': 'mingw'}, + {'os': 'Windows', 'compiler': 'clang', + 'qbs_compiler': 'clang-cl'}, + {'os': 'Windows', 'compiler': 'Visual Studio', + 'qbs_compiler': 'cl'}, + {'os': 'Windows', 'compiler': 'Visual Studio', + 'compiler.toolset': 'ClangCl', 'qbs_compiler': 'clang-cl'}, + {'os': 'Linux', 'compiler': 'gcc', 'qbs_compiler': 'gcc'}, + {'os': 'Linux', 'compiler': 'clang', 'qbs_compiler': 'clang'} ] def test_convert_compiler_name_to_qbs_compiler_name(self): for settings in self._settings_to_test_against(): def expected(): - return settings["qbs_compiler"] + return settings['qbs_compiler'] conanfile = MockConanfile(MockSettings(settings)) - self.assertEqual(qbs._compiler_name(conanfile), expected()) + self.assertEqual(qbs._default_compiler_name(conanfile), expected()) def test_settings_dir_location(self): conanfile = MockConanfileWithFolders(MockSettings({})) @@ -105,58 +216,58 @@ def test_setup_toolchain_without_any_env_values(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - "qbs-setup-toolchains --settings-dir %s %s %s" % ( - qbs._settings_dir(conanfile), settings["qbs_compiler"], + 'qbs-setup-toolchains --settings-dir %s %s %s' % ( + qbs._settings_dir(conanfile), settings['qbs_compiler'], qbs._profile_name)) def test_setup_toolchain_with_compiler_from_env(self): - compiler = "compiler_from_env" + compiler = 'compiler_from_env' for settings in self._settings_to_test_against(): conanfile = MockConanfileWithFolders(MockSettings(settings), runner=RunnerMock()) - with tools.environment_append({"CC": compiler}): + with tools.environment_append({'CC': compiler}): qbs._setup_toolchains(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - "qbs-setup-toolchains --settings-dir %s %s %s" % ( + 'qbs-setup-toolchains --settings-dir %s %s %s' % ( qbs._settings_dir(conanfile), compiler, qbs._profile_name)) @staticmethod def _generate_flags(flag, qbs_key): - return {"env": ('-{0}1 -{0}2 -{0}3_with_value=13 ' + return {'env': ('-{0}1 -{0}2 -{0}3_with_value=13 ' '-{0}_with_space="hello world"').format(flag), - "qbs_value": ("['-{0}1', '-{0}2', '-{0}3_with_value=13', " + 'qbs_value': ("['-{0}1', '-{0}2', '-{0}3_with_value=13', " "'-{0}_with_space=hello world']").format(flag), - "qbs_key": qbs_key} + 'qbs_key': qbs_key} def test_flags_from_env(self): - asm = self._generate_flags("asm", "assemblerFlags") - c = self._generate_flags("c", "cFlags") - cpp = self._generate_flags("cpp", "cppFlags") - cxx = self._generate_flags("cxx", "cxxFlags") - wl = self._generate_flags("Wl,", "linkerFlags") - ld = self._generate_flags("ld", "linkerFlags") + asm = self._generate_flags('asm', 'assemblerFlags') + c = self._generate_flags('c', 'cFlags') + cpp = self._generate_flags('cpp', 'cppFlags') + cxx = self._generate_flags('cxx', 'cxxFlags') + wl = self._generate_flags('Wl,', 'linkerFlags') + ld = self._generate_flags('ld', 'linkerFlags') env = { - "ASFLAGS": asm["env"], - "CFLAGS": c["env"], - "CPPFLAGS": cpp["env"], - "CXXFLAGS": cxx["env"], - "LDFLAGS": "%s -Wl,%s" % (wl["env"], ld["env"].replace(" -", ",-")) + 'ASFLAGS': asm['env'], + 'CFLAGS': c['env'], + 'CPPFLAGS': cpp['env'], + 'CXXFLAGS': cxx['env'], + 'LDFLAGS': '%s -Wl,%s' % (wl['env'], ld['env'].replace(' -', ',-')) } with tools.environment_append(env): flags_from_env = qbs._flags_from_env() expected_flags = { - 'cpp.'+asm["qbs_key"]: asm["qbs_value"], - 'cpp.'+c["qbs_key"]: c["qbs_value"], - 'cpp.'+cpp["qbs_key"]: cpp["qbs_value"], - 'cpp.'+cxx["qbs_key"]: cxx["qbs_value"], - 'cpp.'+wl["qbs_key"]: ("%s%s" % (wl["qbs_value"], - ld["qbs_value"])).replace( - "][", ", ", 1).replace( - "-Wl,", ""), + 'cpp.'+asm['qbs_key']: asm['qbs_value'], + 'cpp.'+c['qbs_key']: c['qbs_value'], + 'cpp.'+cpp['qbs_key']: cpp['qbs_value'], + 'cpp.'+cxx['qbs_key']: cxx['qbs_value'], + 'cpp.'+wl['qbs_key']: ('%s%s' % (wl['qbs_value'], + ld['qbs_value'])).replace( + '][', ', ', 1).replace( + '-Wl,', ''), } self.assertEqual(flags_from_env, expected_flags) @@ -201,7 +312,7 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): config = qbs._read_qbs_toolchain_from_config(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual(conanfile.runner.command_called[0], - "qbs-config --settings-dir %s --list" % ( + 'qbs-config --settings-dir %s --list' % ( qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) @@ -212,6 +323,8 @@ def test_toolchain_content(self): Project { Profile { name: "conan_toolchain_profile" + + /* detected via qbs-setup-toolchains */ cpp.cCompilerName: "gcc" cpp.compilerName: "g++" cpp.cxxCompilerName: "g++" @@ -224,11 +337,32 @@ def test_toolchain_content(self): qbs.someBoolProp: true qbs.someIntProp: 13 qbs.toolchain: ["gcc"] + + /* deduced from environment */ + qbs.sysroot: "/foo/bar/path" + + /* conan settings */ + qbs.buildVariant: "release" + qbs.architecture: "x86_64" + qbs.optimization: "small" + cpp.cxxLanguageVersion: "c++17" + + /* package options */ + cpp.positionIndependentCode: true } }''') conanfile = MockConanfileWithFolders( - MockSettings({"compiler": "gcc", "os": "Linux"}), + MockSettings({ + 'compiler': 'gcc', + 'compiler.cppstd': 17, + 'os': 'Linux', + 'build_type': 'MinSizeRel', + 'arch': 'x86_64' + }), + options=MockOptions({ + 'fPIC': True + }), runner=RunnerMock( expectations=[ RunnerMock.Expectation(), @@ -236,6 +370,7 @@ def test_toolchain_content(self): output=self._generate_qbs_config_output()), ])) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + with tools.environment_append({'SYSROOT': '/foo/bar/path'}): + qbs_toolchain = qbs.QbsGenericToolchain(conanfile) self.assertEqual(qbs_toolchain.content, expected_content) From 72c82aaa7ecb42fdbbff0669a628b9a67fb39d08 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 28 Nov 2020 14:43:10 +0100 Subject: [PATCH 06/23] Added property `use_toolchain_profile` to compile with specified profile --- conans/client/build/qbs.py | 60 +++++++++------- .../test/unittests/client/build/qbs_test.py | 69 ++++++++++--------- 2 files changed, 70 insertions(+), 59 deletions(-) diff --git a/conans/client/build/qbs.py b/conans/client/build/qbs.py index 807d8c2e716..71cceb7cd89 100644 --- a/conans/client/build/qbs.py +++ b/conans/client/build/qbs.py @@ -7,24 +7,27 @@ class QbsException(ConanException): def __str__(self): msg = super(QbsException, self).__str__() - return "Qbs build helper: {}".format(msg) + return 'Qbs build helper: {}'.format(msg) def _configuration_dict_to_commandlist(name, dict): - command_list = ["config:%s" % name] + command_list = ['config:%s' % name] for key, value in dict.items(): if type(value) is bool: if value: - b = "true" + b = 'true' else: - b = "false" - command_list.append("%s:%s" % (key, b)) + b = 'false' + command_list.append('%s:%s' % (key, b)) else: - command_list.append("%s:%s" % (key, value)) + command_list.append('%s:%s' % (key, value)) return command_list class Qbs(object): + # hardcoded name, see qbs toolchain + use_toolchain_profile = 'conan_toolchain_profile' + def __init__(self, conanfile, project_file=None): self._conanfile = conanfile self._set_project_file(project_file) @@ -38,57 +41,64 @@ def _set_project_file(self, project_file): self._project_file = project_file if not os.path.exists(self._project_file): - raise QbsException("could not find project file") + raise QbsException( + 'could not find project file %s' % self._project_file) def add_configuration(self, name, values): self._configuration[name] = values def build(self, products=[]): args = [ - "--no-install", - "--build-directory", self._conanfile.build_folder, - "--file", self._project_file, + '--no-install', + '--build-directory', self._conanfile.build_folder, + '--file', self._project_file, ] if products: - args.extend(["--products", ",".join(products)]) + args.extend(['--products', ','.join(products)]) + + args.extend(['--jobs', '%s' % self.jobs]) - args.extend(["--jobs", "%s" % self.jobs]) + if self.use_toolchain_profile: + args.append('profile:%s' % self.use_toolchain_profile) for name in self._configuration: config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = "qbs build %s" % (" ".join(args)) + cmd = 'qbs build %s' % (' '.join(args)) self._conanfile.run(cmd) def build_all(self): args = [ - "--no-install", - "--build-directory", self._conanfile.build_folder, - "--file", self._project_file, - "--all-products" + '--no-install', + '--build-directory', self._conanfile.build_folder, + '--file', self._project_file, + '--all-products' ] - args.extend(["--jobs", "%s" % self.jobs]) + args.extend(['--jobs', '%s' % self.jobs]) + + if self.use_toolchain_profile: + args.append('profile:%s' % self.use_toolchain_profile) for name in self._configuration: config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = "qbs build %s" % (" ".join(args)) + cmd = 'qbs build %s' % (' '.join(args)) self._conanfile.run(cmd) def install(self): args = [ - "--no-build", - "--clean-install-root", - "--install-root", self._conanfile.install_folder, - "--file", self._project_file + '--no-build', + '--clean-install-root', + '--install-root', self._conanfile.install_folder, + '--file', self._project_file ] for name in self._configuration: - args.append("config:%s" % (name)) + args.append('config:%s' % (name)) - cmd = "qbs install %s" % (" ".join(args)) + cmd = 'qbs install %s' % (' '.join(args)) self._conanfile.run(cmd) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 8257147095f..d8e003cd08d 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -15,19 +15,19 @@ def __call__(self, command, output, win_bash=False, subsystem=None): self.command_called = command self.win_bash = win_bash self.subsystem = subsystem - if self.output and output and hasattr(output, "write"): + if self.output and output and hasattr(output, 'write'): output.write(self.output) return 0 if self.return_ok else 1 class QbsTest(unittest.TestCase): def test_generating_config_command_line(self): - name = "default" + name = 'default' dict = { - "modules.cpp.cxxFlags": ["-frtti", "-fexceptions"], - "modules.cpp.ldFlags": "--defsym=hello_world", - "products.App.myIntProperty": 13, - "products.App.myBoolProperty": True + 'modules.cpp.cxxFlags': ['-frtti', '-fexceptions'], + 'modules.cpp.ldFlags': '--defsym=hello_world', + 'products.App.myIntProperty': 13, + 'products.App.myBoolProperty': True } expected_config_line = [ 'config:%s' % name, @@ -47,7 +47,7 @@ def test_generating_config_command_line(self): def test_construct_build_helper_without_project_file(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"})) + MockSettings({'os': 'Linux', 'compiler': 'gcc'})) conanfile.source_folder = '.' build_helper = qbs.Qbs(conanfile) self.assertEqual(build_helper.jobs, tools.cpu_count()) @@ -55,28 +55,28 @@ def test_construct_build_helper_without_project_file(self): def test_construct_build_helper_with_project_file(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"})) + MockSettings({'os': 'Linux', 'compiler': 'gcc'})) # just asume that the test is called from repo root - profile_file_path = "conans/client" + profile_file_path = 'conans/client' build_helper = qbs.Qbs(conanfile, project_file=profile_file_path) self.assertEqual(build_helper._project_file, profile_file_path) def test_construct_build_helper_with_wrong_project_file_path(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"})) + MockSettings({'os': 'Linux', 'compiler': 'gcc'})) with self.assertRaises(qbs.QbsException): - qbs.Qbs(conanfile, project_file="random/file/path") + qbs.Qbs(conanfile, project_file='random/file/path') def test_add_configuration(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"})) + MockSettings({'os': 'Linux', 'compiler': 'gcc'})) conanfile.source_folder = '.' build_helper = qbs.Qbs(conanfile) configurations = { - "debug": {"products.MyLib.specialFlags": ["-frtti", - "-fexceptions"]}, - "release": {"products.MyLib.specialFlags": ["-fno-exceptions", - "-fno-rtti"]} + 'debug': {'products.MyLib.specialFlags': ['-frtti', + '-fexceptions']}, + 'release': {'products.MyLib.specialFlags': ['-fno-exceptions', + '-fno-rtti']} } for name, config in configurations.items(): build_helper.add_configuration(name, config) @@ -84,7 +84,7 @@ def test_add_configuration(self): def test_build(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"}), + MockSettings({'os': 'Linux', 'compiler': 'gcc'}), runner=RunnerMock()) conanfile.source_folder = '.' conanfile.build_folder = '.' @@ -93,22 +93,22 @@ def test_build(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ("qbs build --no-install --build-directory %s " - "--file %s --jobs %s") % ( + ('qbs build --no-install --build-directory %s ' + '--file %s --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, - build_helper.jobs)) + build_helper.jobs, build_helper.use_toolchain_profile)) - build_helper.build(products=["app1", "app2", "lib"]) + build_helper.build(products=['app1', 'app2', 'lib']) self.assertEqual( conanfile.runner.command_called, - ("qbs build --no-install --build-directory %s " - "--file %s --products app1,app2,lib --jobs %s") % ( + ('qbs build --no-install --build-directory %s ' + '--file %s --products app1,app2,lib --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, - build_helper.jobs)) + build_helper.jobs, build_helper.use_toolchain_profile)) def test_build_all(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"}), + MockSettings({'os': 'Linux', 'compiler': 'gcc'}), runner=RunnerMock()) conanfile.source_folder = '.' conanfile.build_folder = '.' @@ -117,19 +117,19 @@ def test_build_all(self): build_helper.build_all() self.assertEqual( conanfile.runner.command_called, - ("qbs build --no-install --build-directory %s " - "--file %s --all-products --jobs %s") % ( + ('qbs build --no-install --build-directory %s ' + '--file %s --all-products --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, - build_helper.jobs)) + build_helper.jobs, build_helper.use_toolchain_profile)) def test_build_with_custom_configuration(self): conanfile = MockConanfile( - MockSettings({"os": "Linux", "compiler": "gcc"}), + MockSettings({'os': 'Linux', 'compiler': 'gcc'}), runner=RunnerMock()) conanfile.source_folder = '.' conanfile.build_folder = '.' build_helper = qbs.Qbs(conanfile) - config_name = "debug" + config_name = 'debug' config_values = { 'product.App.boolProperty': True, 'product.App.intProperty': 1337, @@ -140,11 +140,12 @@ def test_build_with_custom_configuration(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ("qbs build --no-install --build-directory %s " - "--file %s --jobs %s " - "config:%s %s:%s %s:%s %s:%s %s:%s") % ( + ('qbs build --no-install --build-directory %s ' + '--file %s --jobs %s profile:%s ' + 'config:%s %s:%s %s:%s %s:%s %s:%s') % ( conanfile.build_folder, build_helper._project_file, - build_helper.jobs, config_name, + build_helper.jobs, build_helper.use_toolchain_profile, + config_name, 'product.App.boolProperty', 'true', 'product.App.intProperty', From 6c529175a544bf1fe8270225057e0a61302ab840 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 28 Nov 2020 21:39:15 +0100 Subject: [PATCH 07/23] Set cpp.linkerFlags for LDFLAGS with -Wl and cpp.driverLinkerFlags for LDFLAGS without -Wl --- conan/tools/qbs/generic.py | 45 ++++++++++++++++--- .../client/toolchain/test_qbs_generic.py | 37 ++++++++++++--- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/conan/tools/qbs/generic.py b/conan/tools/qbs/generic.py index 408c981e777..be4f90808e8 100644 --- a/conan/tools/qbs/generic.py +++ b/conan/tools/qbs/generic.py @@ -157,6 +157,42 @@ def _read_qbs_toolchain_from_config(conanfile): return config +class LinkerFlagsParser(object): + def __init__(self, ld_flags): + self.driver_linker_flags = [] + self.linker_flags = [] + self._parse = self._detect_wl_or_add_driver_linker_flag + for token in ld_flags: + print('parse token: %s' % token) + self._parse(token) + + def _detect_wl_or_add_driver_linker_flag(self, token): + print('_detect_wl_or_add_driver_linker_flag') + if token == '-Wl': + self._parse = self._assert_comma + else: + self.driver_linker_flags.append(token) + self._parse = self._detect_wl_or_add_driver_linker_flag + + def _detect_wl_or_detect_comma_or_add_driver_linker_flag(self, token): + print('_detect_wl_or_detect_comma_or_add_driver_linker_flag') + if token == ',': + self._parse = self._add_linker_flag + else: + self._detect_wl_or_add_driver_linker_flag(token) + + def _assert_comma(self, token): + print('_assert_comma') + if token != ',': + raise QbsException('Could not parse LDFLAGS') + self._parse = self._add_linker_flag + + def _add_linker_flag(self, token): + print('_add_linker_flag') + self.linker_flags.append(token) + self._parse = self._detect_wl_or_detect_comma_or_add_driver_linker_flag + + def _flags_from_env(): flags_from_env = {} if tools.get_env('ASFLAGS'): @@ -172,11 +208,10 @@ def _flags_from_env(): flags_from_env['cpp.cxxFlags'] = '%s' % ( _env_var_to_list(tools.get_env('CXXFLAGS'))) if tools.get_env('LDFLAGS'): - ld_flags = [] - for item in _env_var_to_list(tools.get_env('LDFLAGS')): - if item not in ['-Wl', ',']: - ld_flags.append(item) - flags_from_env['cpp.linkerFlags'] = str(ld_flags) + parser = LinkerFlagsParser(_env_var_to_list(tools.get_env('LDFLAGS'))) + flags_from_env['cpp.linkerFlags'] = str(parser.linker_flags) + flags_from_env['cpp.driverLinkerFlags'] = str( + parser.driver_linker_flags) return flags_from_env diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 15d408cf8ff..4a2778a64fb 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -234,6 +234,32 @@ def test_setup_toolchain_with_compiler_from_env(self): qbs._settings_dir(conanfile), compiler, qbs._profile_name)) + def test_linker_flags_parser(self): + test_data_ld_flags = { + '-Wl,flag1': ([], ['flag1']), + '-Wl,flag1,flag2': ([], ['flag1', 'flag2']), + '-Wl,flag1 -Wl,flag2': ([], ['flag1', 'flag2']), + '-dFlag1': (['-dFlag1'], []), + '-dFlag1 -dFlag2': (['-dFlag1', '-dFlag2'], []), + '-Wl,flag1 -dFlag1': (['-dFlag1'], ['flag1']), + '-Wl,flag1,flag2 -dFlag1': (['-dFlag1'], ['flag1', 'flag2']), + '-Wl,flag1,flag2 -dFlag1 -Wl,flag3 -dFlag2 -dFlag3 -Wl,flag4,flag5': + (['-dFlag1', '-dFlag2', '-dFlag3'], + ['flag1', 'flag2', 'flag3', 'flag4', 'flag5']), + } + for ld_flags, expected in test_data_ld_flags.items(): + driver_linker_flags, linker_flags = expected + print(ld_flags) + print(driver_linker_flags) + print(linker_flags) + parser = qbs.LinkerFlagsParser(qbs._env_var_to_list(ld_flags)) + print(parser.driver_linker_flags) + print(parser.linker_flags) + self.assertEqual(parser.driver_linker_flags, + driver_linker_flags) + self.assertEqual(parser.linker_flags, + linker_flags) + @staticmethod def _generate_flags(flag, qbs_key): return {'env': ('-{0}1 -{0}2 -{0}3_with_value=13 ' @@ -248,14 +274,15 @@ def test_flags_from_env(self): cpp = self._generate_flags('cpp', 'cppFlags') cxx = self._generate_flags('cxx', 'cxxFlags') wl = self._generate_flags('Wl,', 'linkerFlags') - ld = self._generate_flags('ld', 'linkerFlags') + ld = self._generate_flags('ld', 'driverLinkerFlags') env = { 'ASFLAGS': asm['env'], 'CFLAGS': c['env'], 'CPPFLAGS': cpp['env'], 'CXXFLAGS': cxx['env'], - 'LDFLAGS': '%s -Wl,%s' % (wl['env'], ld['env'].replace(' -', ',-')) + 'LDFLAGS': '%s %s' % (wl['env'], ld['env']) } + print(env) with tools.environment_append(env): flags_from_env = qbs._flags_from_env() @@ -264,10 +291,8 @@ def test_flags_from_env(self): 'cpp.'+c['qbs_key']: c['qbs_value'], 'cpp.'+cpp['qbs_key']: cpp['qbs_value'], 'cpp.'+cxx['qbs_key']: cxx['qbs_value'], - 'cpp.'+wl['qbs_key']: ('%s%s' % (wl['qbs_value'], - ld['qbs_value'])).replace( - '][', ', ', 1).replace( - '-Wl,', ''), + 'cpp.'+wl['qbs_key']: wl['qbs_value'].replace('-Wl,', ''), + 'cpp.'+ld['qbs_key']: ld['qbs_value'] } self.assertEqual(flags_from_env, expected_flags) From 56b4c2494cb1cc7b13ede91072fff02410a0636f Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 28 Nov 2020 21:40:01 +0100 Subject: [PATCH 08/23] Made use_toolchain_profile non static --- conans/client/build/qbs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conans/client/build/qbs.py b/conans/client/build/qbs.py index 71cceb7cd89..641c227aa73 100644 --- a/conans/client/build/qbs.py +++ b/conans/client/build/qbs.py @@ -25,10 +25,9 @@ def _configuration_dict_to_commandlist(name, dict): class Qbs(object): - # hardcoded name, see qbs toolchain - use_toolchain_profile = 'conan_toolchain_profile' - def __init__(self, conanfile, project_file=None): + # hardcoded name, see qbs toolchain + self.use_toolchain_profile = 'conan_toolchain_profile' self._conanfile = conanfile self._set_project_file(project_file) self.jobs = tools.cpu_count() From 47f036def4f56206939c544f998f0165f83af093 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Sat, 28 Nov 2020 21:47:00 +0100 Subject: [PATCH 09/23] Removed prints --- conan/tools/qbs/generic.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/conan/tools/qbs/generic.py b/conan/tools/qbs/generic.py index be4f90808e8..19a3acdb5be 100644 --- a/conan/tools/qbs/generic.py +++ b/conan/tools/qbs/generic.py @@ -163,11 +163,9 @@ def __init__(self, ld_flags): self.linker_flags = [] self._parse = self._detect_wl_or_add_driver_linker_flag for token in ld_flags: - print('parse token: %s' % token) self._parse(token) def _detect_wl_or_add_driver_linker_flag(self, token): - print('_detect_wl_or_add_driver_linker_flag') if token == '-Wl': self._parse = self._assert_comma else: @@ -175,20 +173,17 @@ def _detect_wl_or_add_driver_linker_flag(self, token): self._parse = self._detect_wl_or_add_driver_linker_flag def _detect_wl_or_detect_comma_or_add_driver_linker_flag(self, token): - print('_detect_wl_or_detect_comma_or_add_driver_linker_flag') if token == ',': self._parse = self._add_linker_flag else: self._detect_wl_or_add_driver_linker_flag(token) def _assert_comma(self, token): - print('_assert_comma') if token != ',': raise QbsException('Could not parse LDFLAGS') self._parse = self._add_linker_flag def _add_linker_flag(self, token): - print('_add_linker_flag') self.linker_flags.append(token) self._parse = self._detect_wl_or_detect_comma_or_add_driver_linker_flag From 7813894623be71f26c3ad7403933d2e5843f9738 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 11:54:30 +0100 Subject: [PATCH 10/23] Put settings dir into quotes to support settings dir with spaces --- conan/tools/qbs/generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conan/tools/qbs/generic.py b/conan/tools/qbs/generic.py index 19a3acdb5be..3222b6669a4 100644 --- a/conan/tools/qbs/generic.py +++ b/conan/tools/qbs/generic.py @@ -130,14 +130,14 @@ def _setup_toolchains(conanfile): env_context = tools.vcvars() with env_context: - cmd = 'qbs-setup-toolchains --settings-dir %s %s %s' % ( + cmd = 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( _settings_dir(conanfile), compiler, _profile_name) conanfile.run(cmd) def _read_qbs_toolchain_from_config(conanfile): s = StringIO() - conanfile.run('qbs-config --settings-dir %s --list' % ( + conanfile.run('qbs-config --settings-dir "%s" --list' % ( _settings_dir(conanfile)), output=s) config = {} s.seek(0) From 1d988b59ef9b0dacabda64c5be348fc7f46faaaf Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 12:14:50 +0100 Subject: [PATCH 11/23] Moved qbs to conan/tools --- conan/tools/qbs/__init__.py | 2 ++ conan/tools/qbs/{generic.py => generictoolchain.py} | 0 {conans/client/build => conan/tools/qbs}/qbs.py | 0 conans/__init__.py | 1 - 4 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 conan/tools/qbs/__init__.py rename conan/tools/qbs/{generic.py => generictoolchain.py} (100%) rename {conans/client/build => conan/tools/qbs}/qbs.py (100%) diff --git a/conan/tools/qbs/__init__.py b/conan/tools/qbs/__init__.py new file mode 100644 index 00000000000..131c1d129c2 --- /dev/null +++ b/conan/tools/qbs/__init__.py @@ -0,0 +1,2 @@ +from .generictoolchain import QbsGenericToolchain +from .qbs import Qbs diff --git a/conan/tools/qbs/generic.py b/conan/tools/qbs/generictoolchain.py similarity index 100% rename from conan/tools/qbs/generic.py rename to conan/tools/qbs/generictoolchain.py diff --git a/conans/client/build/qbs.py b/conan/tools/qbs/qbs.py similarity index 100% rename from conans/client/build/qbs.py rename to conan/tools/qbs/qbs.py diff --git a/conans/__init__.py b/conans/__init__.py index bc0ac23cd0e..55de992ee4b 100644 --- a/conans/__init__.py +++ b/conans/__init__.py @@ -6,7 +6,6 @@ from conans.client.build.cmake import CMake from conans.client.build.meson import Meson from conans.client.build.msbuild import MSBuild -from conans.client.build.qbs import Qbs from conans.client.build.visual_environment import VisualStudioBuildEnvironment from conans.client.run_environment import RunEnvironment from conans.model.conan_file import ConanFile From d4c5c75e2cda39944c56b01a6ef6047498ea596b Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 12:15:32 +0100 Subject: [PATCH 12/23] Renamed exception to be independent --- conan/tools/qbs/generictoolchain.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/conan/tools/qbs/generictoolchain.py b/conan/tools/qbs/generictoolchain.py index 3222b6669a4..74572bbcd2b 100644 --- a/conan/tools/qbs/generictoolchain.py +++ b/conan/tools/qbs/generictoolchain.py @@ -64,9 +64,9 @@ } -class QbsException(ConanException): +class QbsToolchainException(ConanException): def __str__(self): - msg = super(QbsException, self).__str__() + msg = super(QbsToolchainException, self).__str__() return 'Qbs generic toolchain: {}'.format(msg) @@ -75,7 +75,8 @@ def _bool(b): return None if type(b)is not bool: - raise QbsException('Tried to convert non bool type value to bool') + raise QbsToolchainException( + 'Tried to convert non bool type value to bool') if b: return 'true' @@ -90,10 +91,10 @@ def _env_var_to_list(var): def _check_for_compiler(conanfile): compiler = conanfile.settings.get_safe('compiler') if not compiler: - raise QbsException('need compiler to be set in settings') + raise QbsToolchainException('need compiler to be set in settings') if compiler not in ['Visual Studio', 'gcc', 'clang']: - raise QbsException('compiler not supported') + raise QbsToolchainException('compiler not supported') def _default_compiler_name(conanfile): @@ -109,7 +110,7 @@ def _default_compiler_name(conanfile): return 'cl' if compiler == 'clang': return 'clang-cl' - raise QbsException('unknown windows compiler') + raise QbsToolchainException('unknown windows compiler') return compiler @@ -180,7 +181,7 @@ def _detect_wl_or_detect_comma_or_add_driver_linker_flag(self, token): def _assert_comma(self, token): if token != ',': - raise QbsException('Could not parse LDFLAGS') + raise QbsToolchainException('Could not parse LDFLAGS') self._parse = self._add_linker_flag def _add_linker_flag(self, token): From 38e79928d4046f2d25004f5663ce74e3769ff0b0 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 12:21:31 +0100 Subject: [PATCH 13/23] Use the right import paths --- conans/test/unittests/client/build/qbs_test.py | 2 +- conans/test/unittests/client/toolchain/test_qbs_generic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index d8e003cd08d..72e6c98e781 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -1,5 +1,5 @@ import unittest -import conans.client.build.qbs as qbs +import conan.tools.qbs.qbs as qbs from conans.client import tools from conans.test.utils.mocks import MockConanfile, MockSettings diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 4a2778a64fb..f52505f1c0c 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,7 +1,7 @@ import unittest import tempfile import textwrap -import conans.client.toolchain.qbs.generic as qbs +import conan.tools.qbs.generictoolchain as qbs from conans import tools from conans.test.utils.mocks import MockConanfile, MockSettings, MockOptions From 1ba7782e13a34dbb248bc5edb54552f2f0f551b1 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 13:55:16 +0100 Subject: [PATCH 14/23] Put settings-dir parameter in quotes in test --- conans/test/unittests/client/toolchain/test_qbs_generic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index f52505f1c0c..29e75706099 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -216,7 +216,7 @@ def test_setup_toolchain_without_any_env_values(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qbs-setup-toolchains --settings-dir %s %s %s' % ( + 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), settings['qbs_compiler'], qbs._profile_name)) @@ -230,7 +230,7 @@ def test_setup_toolchain_with_compiler_from_env(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qbs-setup-toolchains --settings-dir %s %s %s' % ( + 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), compiler, qbs._profile_name)) @@ -337,7 +337,7 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): config = qbs._read_qbs_toolchain_from_config(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual(conanfile.runner.command_called[0], - 'qbs-config --settings-dir %s --list' % ( + 'qbs-config --settings-dir "%s" --list' % ( qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) From d436aec7fc64fb5cdf5ed13162483bac488a886c Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 14:05:46 +0100 Subject: [PATCH 15/23] Modified tests to assert for QbsToolchainException instead of QbsException --- conans/test/unittests/client/toolchain/test_qbs_generic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 29e75706099..a4f0738d843 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -46,7 +46,7 @@ class QbsGenericTest(unittest.TestCase): def test_convert_bool(self): self.assertEqual(qbs._bool(True), 'true') self.assertEqual(qbs._bool(False), 'false') - with self.assertRaises(qbs.QbsException): + with self.assertRaises(qbs.QbsToolchainException): qbs._bool("") def test_convert_build_variant(self): @@ -166,13 +166,13 @@ def test_split_env_var_into_list(self): def test_compiler_not_in_settings(self): conanfile = MockConanfile(MockSettings({})) - with self.assertRaises(qbs.QbsException): + with self.assertRaises(qbs.QbsToolchainException): qbs._check_for_compiler(conanfile) def test_compiler_in_settings_not_supported(self): conanfile = MockConanfile( MockSettings({'compiler': 'not realy a compiler name'})) - with self.assertRaises(qbs.QbsException): + with self.assertRaises(qbs.QbsToolchainException): qbs._check_for_compiler(conanfile) def test_valid_compiler(self): From 2cf5fd667a4b3930554d2699c5bc6f1c7f679c8e Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 30 Nov 2020 20:52:55 +0100 Subject: [PATCH 16/23] Use shlex.split and made LinkerFlagsParser much easier This makes the module python 3.5 compatible --- conan/tools/qbs/generictoolchain.py | 33 ++++--------------- .../client/toolchain/test_qbs_generic.py | 5 --- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/conan/tools/qbs/generictoolchain.py b/conan/tools/qbs/generictoolchain.py index 74572bbcd2b..ca604a5a6a4 100644 --- a/conan/tools/qbs/generictoolchain.py +++ b/conan/tools/qbs/generictoolchain.py @@ -85,7 +85,7 @@ def _bool(b): def _env_var_to_list(var): - return list(shlex.shlex(var, posix=True, punctuation_chars=True)) + return shlex.split(var) def _check_for_compiler(conanfile): @@ -162,31 +162,12 @@ class LinkerFlagsParser(object): def __init__(self, ld_flags): self.driver_linker_flags = [] self.linker_flags = [] - self._parse = self._detect_wl_or_add_driver_linker_flag - for token in ld_flags: - self._parse(token) - - def _detect_wl_or_add_driver_linker_flag(self, token): - if token == '-Wl': - self._parse = self._assert_comma - else: - self.driver_linker_flags.append(token) - self._parse = self._detect_wl_or_add_driver_linker_flag - - def _detect_wl_or_detect_comma_or_add_driver_linker_flag(self, token): - if token == ',': - self._parse = self._add_linker_flag - else: - self._detect_wl_or_add_driver_linker_flag(token) - - def _assert_comma(self, token): - if token != ',': - raise QbsToolchainException('Could not parse LDFLAGS') - self._parse = self._add_linker_flag - - def _add_linker_flag(self, token): - self.linker_flags.append(token) - self._parse = self._detect_wl_or_detect_comma_or_add_driver_linker_flag + + for item in ld_flags: + if item.startswith('-Wl'): + self.linker_flags.extend(item.split(',')[1:]) + else: + self.driver_linker_flags.append(item) def _flags_from_env(): diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index a4f0738d843..4cdf580e7f3 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -249,12 +249,7 @@ def test_linker_flags_parser(self): } for ld_flags, expected in test_data_ld_flags.items(): driver_linker_flags, linker_flags = expected - print(ld_flags) - print(driver_linker_flags) - print(linker_flags) parser = qbs.LinkerFlagsParser(qbs._env_var_to_list(ld_flags)) - print(parser.driver_linker_flags) - print(parser.linker_flags) self.assertEqual(parser.driver_linker_flags, driver_linker_flags) self.assertEqual(parser.linker_flags, From b9d4c09d4295c7a1e01edc11433f9cbe91c67f92 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Thu, 10 Dec 2020 09:43:15 +0100 Subject: [PATCH 17/23] Just convert True/False to true/false with _bool --- conan/tools/qbs/generictoolchain.py | 10 +--------- .../unittests/client/toolchain/test_qbs_generic.py | 2 -- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/conan/tools/qbs/generictoolchain.py b/conan/tools/qbs/generictoolchain.py index ca604a5a6a4..b70e9747877 100644 --- a/conan/tools/qbs/generictoolchain.py +++ b/conan/tools/qbs/generictoolchain.py @@ -73,15 +73,7 @@ def __str__(self): def _bool(b): if b is None: return None - - if type(b)is not bool: - raise QbsToolchainException( - 'Tried to convert non bool type value to bool') - - if b: - return 'true' - else: - return 'false' + return str(b).lower() def _env_var_to_list(var): diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 4cdf580e7f3..ea483565116 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -46,8 +46,6 @@ class QbsGenericTest(unittest.TestCase): def test_convert_bool(self): self.assertEqual(qbs._bool(True), 'true') self.assertEqual(qbs._bool(False), 'false') - with self.assertRaises(qbs.QbsToolchainException): - qbs._bool("") def test_convert_build_variant(self): conanfile = MockConanfileWithFolders(MockSettings({ From a7057823d96dfac67f1242894823aafcefeac3b5 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 17 Dec 2020 00:58:48 +0100 Subject: [PATCH 18/23] working --- conan/tools/qbs/__init__.py | 2 - conan/tools/qt/__init__.py | 2 + conan/tools/{qbs => qt}/generictoolchain.py | 30 +++++------- conan/tools/{qbs => qt}/qbs.py | 17 ++----- conans/client/generators/qbs.py | 11 ++--- conans/paths/__init__.py | 2 +- .../functional/generators/generators_test.py | 4 +- conans/test/functional/generators/qbs_test.py | 4 +- .../test/unittests/client/build/qbs_test.py | 10 ++-- .../client/toolchain/test_qbs_generic.py | 49 ++++++++++--------- 10 files changed, 59 insertions(+), 72 deletions(-) delete mode 100644 conan/tools/qbs/__init__.py create mode 100644 conan/tools/qt/__init__.py rename conan/tools/{qbs => qt}/generictoolchain.py (90%) rename conan/tools/{qbs => qt}/qbs.py (85%) diff --git a/conan/tools/qbs/__init__.py b/conan/tools/qbs/__init__.py deleted file mode 100644 index 131c1d129c2..00000000000 --- a/conan/tools/qbs/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .generictoolchain import QbsGenericToolchain -from .qbs import Qbs diff --git a/conan/tools/qt/__init__.py b/conan/tools/qt/__init__.py new file mode 100644 index 00000000000..9aad9ff816e --- /dev/null +++ b/conan/tools/qt/__init__.py @@ -0,0 +1,2 @@ +from conan.tools.qt.generictoolchain import QbsGenericToolchain +from conan.tools.qt.qbs import Qbs diff --git a/conan/tools/qbs/generictoolchain.py b/conan/tools/qt/generictoolchain.py similarity index 90% rename from conan/tools/qbs/generictoolchain.py rename to conan/tools/qt/generictoolchain.py index b70e9747877..100979aa557 100644 --- a/conan/tools/qbs/generictoolchain.py +++ b/conan/tools/qt/generictoolchain.py @@ -64,12 +64,6 @@ } -class QbsToolchainException(ConanException): - def __str__(self): - msg = super(QbsToolchainException, self).__str__() - return 'Qbs generic toolchain: {}'.format(msg) - - def _bool(b): if b is None: return None @@ -83,10 +77,10 @@ def _env_var_to_list(var): def _check_for_compiler(conanfile): compiler = conanfile.settings.get_safe('compiler') if not compiler: - raise QbsToolchainException('need compiler to be set in settings') + raise ConanException('Qbs: need compiler to be set in settings') if compiler not in ['Visual Studio', 'gcc', 'clang']: - raise QbsToolchainException('compiler not supported') + raise ConanException('Qbs: compiler {} not supported'.format(compiler)) def _default_compiler_name(conanfile): @@ -102,7 +96,7 @@ def _default_compiler_name(conanfile): return 'cl' if compiler == 'clang': return 'clang-cl' - raise QbsToolchainException('unknown windows compiler') + raise ConanException('unknown windows compiler') return compiler @@ -123,14 +117,14 @@ def _setup_toolchains(conanfile): env_context = tools.vcvars() with env_context: - cmd = 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( + cmd = 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( _settings_dir(conanfile), compiler, _profile_name) conanfile.run(cmd) def _read_qbs_toolchain_from_config(conanfile): s = StringIO() - conanfile.run('qbs-config --settings-dir "%s" --list' % ( + conanfile.run('qt-config --settings-dir "%s" --list' % ( _settings_dir(conanfile)), output=s) config = {} s.seek(0) @@ -185,16 +179,16 @@ def _flags_from_env(): class QbsGenericToolchain(object): - filename = 'conan_toolchain.qbs' + filename = 'conan_toolchain.qt' _template_toolchain = textwrap.dedent('''\ - import qbs + import qt Project { Profile { name: "conan_toolchain_profile" - /* detected via qbs-setup-toolchains */ + /* detected via qt-setup-toolchains */ {%- for key, value in _profile_values_from_setup.items() %} {{ key }}: {{ value }} {%- endfor %} @@ -204,18 +198,18 @@ class QbsGenericToolchain(object): {{ key }}: {{ value }} {%- endfor %} {%- if sysroot %} - qbs.sysroot: "{{ sysroot }}" + qt.sysroot: "{{ sysroot }}" {%- endif %} /* conan settings */ {%- if build_variant %} - qbs.buildVariant: "{{ build_variant }}" + qt.buildVariant: "{{ build_variant }}" {%- endif %} {%- if architecture %} - qbs.architecture: "{{ architecture }}" + qt.architecture: "{{ architecture }}" {%- endif %} {%- if optimization %} - qbs.optimization: "{{ optimization }}" + qt.optimization: "{{ optimization }}" {%- endif %} {%- if cxx_language_version %} cpp.cxxLanguageVersion: "{{ cxx_language_version }}" diff --git a/conan/tools/qbs/qbs.py b/conan/tools/qt/qbs.py similarity index 85% rename from conan/tools/qbs/qbs.py rename to conan/tools/qt/qbs.py index 641c227aa73..4c2b2e676f9 100644 --- a/conan/tools/qbs/qbs.py +++ b/conan/tools/qt/qbs.py @@ -4,12 +4,6 @@ from conans.errors import ConanException -class QbsException(ConanException): - def __str__(self): - msg = super(QbsException, self).__str__() - return 'Qbs build helper: {}'.format(msg) - - def _configuration_dict_to_commandlist(name, dict): command_list = ['config:%s' % name] for key, value in dict.items(): @@ -26,7 +20,7 @@ def _configuration_dict_to_commandlist(name, dict): class Qbs(object): def __init__(self, conanfile, project_file=None): - # hardcoded name, see qbs toolchain + # hardcoded name, see qt toolchain self.use_toolchain_profile = 'conan_toolchain_profile' self._conanfile = conanfile self._set_project_file(project_file) @@ -40,8 +34,7 @@ def _set_project_file(self, project_file): self._project_file = project_file if not os.path.exists(self._project_file): - raise QbsException( - 'could not find project file %s' % self._project_file) + raise ConanException('Qbs: could not find project file %s' % self._project_file) def add_configuration(self, name, values): self._configuration[name] = values @@ -65,7 +58,7 @@ def build(self, products=[]): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qbs build %s' % (' '.join(args)) + cmd = 'qt build %s' % (' '.join(args)) self._conanfile.run(cmd) def build_all(self): @@ -85,7 +78,7 @@ def build_all(self): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qbs build %s' % (' '.join(args)) + cmd = 'qt build %s' % (' '.join(args)) self._conanfile.run(cmd) def install(self): @@ -99,5 +92,5 @@ def install(self): for name in self._configuration: args.append('config:%s' % (name)) - cmd = 'qbs install %s' % (' '.join(args)) + cmd = 'qt install %s' % (' '.join(args)) self._conanfile.run(cmd) diff --git a/conans/client/generators/qbs.py b/conans/client/generators/qbs.py index 4f6cba5e62d..e510d08a526 100755 --- a/conans/client/generators/qbs.py +++ b/conans/client/generators/qbs.py @@ -1,4 +1,3 @@ -from conans.model import Generator from conans.paths import BUILD_INFO_QBS @@ -25,8 +24,8 @@ def __init__(self, cpp_info): self.rootpath = '%s' % cpp_info.rootpath.replace("\\", "/") -class QbsGenerator(Generator): - name = "qbs" +class QbsGenerator(object): + name = "qt" @property def filename(self): @@ -34,7 +33,7 @@ def filename(self): @property def content(self): - deps = DepsCppQbs(self.deps_build_info) + deps = DepsCppQbs(self.conanfile.deps_build_info) template = (' Product {{\n' ' name: "{dep}"\n' @@ -61,11 +60,11 @@ def content(self): sections.append(all_flags) template_deps = template + ' // {dep} root path: {deps.rootpath}\n' - for dep_name, dep_cpp_info in self.deps_build_info.dependencies: + for dep_name, dep_cpp_info in self.conanfile.deps_build_info.dependencies: deps = DepsCppQbs(dep_cpp_info) depends_items = "" for public_dep in dep_cpp_info.public_deps: - name = self.deps_build_info[public_dep].get_name(QbsGenerator.name) + name = self.conanfile.deps_build_info[public_dep].get_name(QbsGenerator.name) depends_items += depends_template.format(dep=name) dep_flags = template_deps.format(dep=dep_name, deps=deps, depends_items=depends_items) sections.append(dep_flags) diff --git a/conans/paths/__init__.py b/conans/paths/__init__.py index d5b8b54c396..bce31fea34a 100644 --- a/conans/paths/__init__.py +++ b/conans/paths/__init__.py @@ -30,7 +30,7 @@ def get_conan_user_home(): BUILD_INFO_GCC = 'conanbuildinfo.gcc' BUILD_INFO_COMPILER_ARGS = 'conanbuildinfo.args' BUILD_INFO_CMAKE = 'conanbuildinfo.cmake' -BUILD_INFO_QBS = 'conanbuildinfo.qbs' +BUILD_INFO_QBS = 'conanbuildinfo.qt' BUILD_INFO_VISUAL_STUDIO = 'conanbuildinfo.props' BUILD_INFO_XCODE = 'conanbuildinfo.xcconfig' BUILD_INFO_PREMAKE = 'conanbuildinfo.premake.lua' diff --git a/conans/test/functional/generators/generators_test.py b/conans/test/functional/generators/generators_test.py index c938eca7014..bd1a225f5e1 100644 --- a/conans/test/functional/generators/generators_test.py +++ b/conans/test/functional/generators/generators_test.py @@ -26,7 +26,7 @@ def test_base(self): [generators] cmake gcc -qbs +qt qmake scons txt @@ -47,7 +47,7 @@ def test_base(self): venv_files.extend(["activate.bat", "deactivate.bat", "environment.bat.env"]) self.assertEqual(sorted(['conanfile.txt', 'conaninfo.txt', 'conanbuildinfo.cmake', - 'conanbuildinfo.gcc', 'conanbuildinfo.qbs', 'conanbuildinfo.pri', + 'conanbuildinfo.gcc', 'conanbuildinfo.qt', 'conanbuildinfo.pri', 'SConscript_conan', 'conanbuildinfo.txt', 'conanbuildinfo.props', 'conanbuildinfo.vsprops', 'conanbuildinfo.xcconfig', 'conan_ycm_flags.json', 'conan_ycm_extra_conf.py', diff --git a/conans/test/functional/generators/qbs_test.py b/conans/test/functional/generators/qbs_test.py index 52cf9b00b7a..42c5da0172e 100644 --- a/conans/test/functional/generators/qbs_test.py +++ b/conans/test/functional/generators/qbs_test.py @@ -17,6 +17,6 @@ def test(self): pkg = GenConanfile("pkg", "0.1").with_requires("dep/0.1@user/testing") client.save({"conanfile.py": pkg}, clean_first=True) client.run("create . user/testing") - client.run("install pkg/0.1@user/testing -g=qbs") - qbs = client.load("conanbuildinfo.qbs") + client.run("install pkg/0.1@user/testing -g=qt") + qbs = client.load("conanbuildinfo.qt") self.assertIn('Depends { name: "dep" }', qbs) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 72e6c98e781..78075a8b6b7 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -1,5 +1,5 @@ import unittest -import conan.tools.qbs.qbs as qbs +import conan.tools.qt.qbs as qbs from conans.client import tools from conans.test.utils.mocks import MockConanfile, MockSettings @@ -93,7 +93,7 @@ def test_build(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ('qbs build --no-install --build-directory %s ' + ('qt build --no-install --build-directory %s ' '--file %s --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -101,7 +101,7 @@ def test_build(self): build_helper.build(products=['app1', 'app2', 'lib']) self.assertEqual( conanfile.runner.command_called, - ('qbs build --no-install --build-directory %s ' + ('qt build --no-install --build-directory %s ' '--file %s --products app1,app2,lib --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -117,7 +117,7 @@ def test_build_all(self): build_helper.build_all() self.assertEqual( conanfile.runner.command_called, - ('qbs build --no-install --build-directory %s ' + ('qt build --no-install --build-directory %s ' '--file %s --all-products --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -140,7 +140,7 @@ def test_build_with_custom_configuration(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ('qbs build --no-install --build-directory %s ' + ('qt build --no-install --build-directory %s ' '--file %s --jobs %s profile:%s ' 'config:%s %s:%s %s:%s %s:%s %s:%s') % ( conanfile.build_folder, build_helper._project_file, diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index ea483565116..d5fbe4a2e5a 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,9 +1,10 @@ import unittest import tempfile import textwrap -import conan.tools.qbs.generictoolchain as qbs +import conan.tools.qt.generictoolchain as qbs from conans import tools +from conans.errors import ConanException from conans.test.utils.mocks import MockConanfile, MockSettings, MockOptions @@ -164,13 +165,13 @@ def test_split_env_var_into_list(self): def test_compiler_not_in_settings(self): conanfile = MockConanfile(MockSettings({})) - with self.assertRaises(qbs.QbsToolchainException): + with self.assertRaises(ConanException): qbs._check_for_compiler(conanfile) def test_compiler_in_settings_not_supported(self): conanfile = MockConanfile( MockSettings({'compiler': 'not realy a compiler name'})) - with self.assertRaises(qbs.QbsToolchainException): + with self.assertRaises(ConanException): qbs._check_for_compiler(conanfile) def test_valid_compiler(self): @@ -214,7 +215,7 @@ def test_setup_toolchain_without_any_env_values(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( + 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), settings['qbs_compiler'], qbs._profile_name)) @@ -228,7 +229,7 @@ def test_setup_toolchain_with_compiler_from_env(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( + 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), compiler, qbs._profile_name)) @@ -301,10 +302,10 @@ def _generate_qbs_config_output(): profiles.conan.cpp.platformLinkerFlags: undefined profiles.conan.cpp.toolchainInstallPath: "/usr/bin" profiles.conan.cpp.toolchainPrefix: "arm-none-eabi-" - profiles.conan.qbs.targetPlatform: "" - profiles.conan.qbs.someBoolProp: "true" - profiles.conan.qbs.someIntProp: "13" - profiles.conan.qbs.toolchain: ["gcc"] + profiles.conan.qt.targetPlatform: "" + profiles.conan.qt.someBoolProp: "true" + profiles.conan.qt.someIntProp: "13" + profiles.conan.qt.toolchain: ["gcc"] ''') def test_read_qbs_toolchain_from_qbs_config_output(self): @@ -317,10 +318,10 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): 'cpp.platformLinkerFlags': 'undefined', 'cpp.toolchainInstallPath': '"/usr/bin"', 'cpp.toolchainPrefix': '"arm-none-eabi-"', - 'qbs.targetPlatform': '""', - 'qbs.someBoolProp': 'true', - 'qbs.someIntProp': '13', - 'qbs.toolchain': '["gcc"]' + 'qt.targetPlatform': '""', + 'qt.someBoolProp': 'true', + 'qt.someIntProp': '13', + 'qt.toolchain': '["gcc"]' } conanfile = MockConanfileWithFolders( @@ -330,19 +331,19 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): config = qbs._read_qbs_toolchain_from_config(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual(conanfile.runner.command_called[0], - 'qbs-config --settings-dir "%s" --list' % ( + 'qt-config --settings-dir "%s" --list' % ( qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) def test_toolchain_content(self): expected_content = textwrap.dedent('''\ - import qbs + import qt Project { Profile { name: "conan_toolchain_profile" - /* detected via qbs-setup-toolchains */ + /* detected via qt-setup-toolchains */ cpp.cCompilerName: "gcc" cpp.compilerName: "g++" cpp.cxxCompilerName: "g++" @@ -351,18 +352,18 @@ def test_toolchain_content(self): cpp.platformLinkerFlags: undefined cpp.toolchainInstallPath: "/usr/bin" cpp.toolchainPrefix: "arm-none-eabi-" - qbs.targetPlatform: "" - qbs.someBoolProp: true - qbs.someIntProp: 13 - qbs.toolchain: ["gcc"] + qt.targetPlatform: "" + qt.someBoolProp: true + qt.someIntProp: 13 + qt.toolchain: ["gcc"] /* deduced from environment */ - qbs.sysroot: "/foo/bar/path" + qt.sysroot: "/foo/bar/path" /* conan settings */ - qbs.buildVariant: "release" - qbs.architecture: "x86_64" - qbs.optimization: "small" + qt.buildVariant: "release" + qt.architecture: "x86_64" + qt.optimization: "small" cpp.cxxLanguageVersion: "c++17" /* package options */ From 9f69914542a74948108d00df6466eebc4db00bec Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 17 Dec 2020 01:26:34 +0100 Subject: [PATCH 19/23] working --- conan/tools/qt/__init__.py | 2 +- conan/tools/qt/qbs.py | 17 ++--- .../{generictoolchain.py => qbstoolchain.py} | 20 +++--- conans/client/generators/__init__.py | 5 +- conans/client/generators/qbs.py | 11 +-- conans/paths/__init__.py | 2 +- .../functional/generators/generators_test.py | 4 +- conans/test/functional/generators/qbs_test.py | 4 +- .../test/unittests/client/build/qbs_test.py | 19 +++-- .../client/toolchain/test_qbs_generic.py | 72 +++++++++---------- 10 files changed, 80 insertions(+), 76 deletions(-) rename conan/tools/qt/{generictoolchain.py => qbstoolchain.py} (94%) diff --git a/conan/tools/qt/__init__.py b/conan/tools/qt/__init__.py index 9aad9ff816e..22a8730f3f9 100644 --- a/conan/tools/qt/__init__.py +++ b/conan/tools/qt/__init__.py @@ -1,2 +1,2 @@ -from conan.tools.qt.generictoolchain import QbsGenericToolchain +from conan.tools.qt.qbstoolchain import QbsToolchain from conan.tools.qt.qbs import Qbs diff --git a/conan/tools/qt/qbs.py b/conan/tools/qt/qbs.py index 4c2b2e676f9..8fd77a990c3 100644 --- a/conan/tools/qt/qbs.py +++ b/conan/tools/qt/qbs.py @@ -4,9 +4,9 @@ from conans.errors import ConanException -def _configuration_dict_to_commandlist(name, dict): +def _configuration_dict_to_commandlist(name, config_dict): command_list = ['config:%s' % name] - for key, value in dict.items(): + for key, value in config_dict.items(): if type(value) is bool: if value: b = 'true' @@ -20,7 +20,7 @@ def _configuration_dict_to_commandlist(name, dict): class Qbs(object): def __init__(self, conanfile, project_file=None): - # hardcoded name, see qt toolchain + # hardcoded name, see qbs toolchain self.use_toolchain_profile = 'conan_toolchain_profile' self._conanfile = conanfile self._set_project_file(project_file) @@ -39,7 +39,8 @@ def _set_project_file(self, project_file): def add_configuration(self, name, values): self._configuration[name] = values - def build(self, products=[]): + def build(self, products=None): + products = products or [] args = [ '--no-install', '--build-directory', self._conanfile.build_folder, @@ -58,7 +59,7 @@ def build(self, products=[]): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qt build %s' % (' '.join(args)) + cmd = 'qbs build %s' % (' '.join(args)) self._conanfile.run(cmd) def build_all(self): @@ -78,7 +79,7 @@ def build_all(self): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qt build %s' % (' '.join(args)) + cmd = 'qbs build %s' % (' '.join(args)) self._conanfile.run(cmd) def install(self): @@ -90,7 +91,7 @@ def install(self): ] for name in self._configuration: - args.append('config:%s' % (name)) + args.append('config:%s' % name) - cmd = 'qt install %s' % (' '.join(args)) + cmd = 'qbs install %s' % (' '.join(args)) self._conanfile.run(cmd) diff --git a/conan/tools/qt/generictoolchain.py b/conan/tools/qt/qbstoolchain.py similarity index 94% rename from conan/tools/qt/generictoolchain.py rename to conan/tools/qt/qbstoolchain.py index 100979aa557..731686ef1d6 100644 --- a/conan/tools/qt/generictoolchain.py +++ b/conan/tools/qt/qbstoolchain.py @@ -117,14 +117,14 @@ def _setup_toolchains(conanfile): env_context = tools.vcvars() with env_context: - cmd = 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( + cmd = 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( _settings_dir(conanfile), compiler, _profile_name) conanfile.run(cmd) def _read_qbs_toolchain_from_config(conanfile): s = StringIO() - conanfile.run('qt-config --settings-dir "%s" --list' % ( + conanfile.run('qbs-config --settings-dir "%s" --list' % ( _settings_dir(conanfile)), output=s) config = {} s.seek(0) @@ -178,17 +178,17 @@ def _flags_from_env(): return flags_from_env -class QbsGenericToolchain(object): - filename = 'conan_toolchain.qt' +class QbsToolchain(object): + filename = 'conan_toolchain.qbs' _template_toolchain = textwrap.dedent('''\ - import qt + import qbs Project { Profile { name: "conan_toolchain_profile" - /* detected via qt-setup-toolchains */ + /* detected via qbs-setup-toolchains */ {%- for key, value in _profile_values_from_setup.items() %} {{ key }}: {{ value }} {%- endfor %} @@ -198,18 +198,18 @@ class QbsGenericToolchain(object): {{ key }}: {{ value }} {%- endfor %} {%- if sysroot %} - qt.sysroot: "{{ sysroot }}" + qbs.sysroot: "{{ sysroot }}" {%- endif %} /* conan settings */ {%- if build_variant %} - qt.buildVariant: "{{ build_variant }}" + qbs.buildVariant: "{{ build_variant }}" {%- endif %} {%- if architecture %} - qt.architecture: "{{ architecture }}" + qbs.architecture: "{{ architecture }}" {%- endif %} {%- if optimization %} - qt.optimization: "{{ optimization }}" + qbs.optimization: "{{ optimization }}" {%- endif %} {%- if cxx_language_version %} cpp.cxxLanguageVersion: "{{ cxx_language_version }}" diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py index c6c0d663cfd..69791f56d26 100644 --- a/conans/client/generators/__init__.py +++ b/conans/client/generators/__init__.py @@ -68,7 +68,7 @@ def __init__(self): "deploy": DeployGenerator, "markdown": MarkdownGenerator} self._new_generators = ["CMakeToolchain", "MakeToolchain", "MSBuildToolchain", - "MesonToolchain", "MSBuildDeps", "msbuild"] + "MesonToolchain", "MSBuildDeps", "QbsToolchain", "msbuild"] def add(self, name, generator_class, custom=False): if name not in self._generators or custom: @@ -103,6 +103,9 @@ def _new_generator(self, generator_name, output): elif generator_name in ("MSBuildDeps", "msbuild"): from conan.tools.microsoft import MSBuildDeps return MSBuildDeps + elif generator_name == "QbsToolchain": + from conan.tools.qt.qbstoolchain import QbsToolchain + return QbsToolchain else: raise ConanException("Internal Conan error: Generator '{}' " "not commplete".format(generator_name)) diff --git a/conans/client/generators/qbs.py b/conans/client/generators/qbs.py index e510d08a526..4f6cba5e62d 100755 --- a/conans/client/generators/qbs.py +++ b/conans/client/generators/qbs.py @@ -1,3 +1,4 @@ +from conans.model import Generator from conans.paths import BUILD_INFO_QBS @@ -24,8 +25,8 @@ def __init__(self, cpp_info): self.rootpath = '%s' % cpp_info.rootpath.replace("\\", "/") -class QbsGenerator(object): - name = "qt" +class QbsGenerator(Generator): + name = "qbs" @property def filename(self): @@ -33,7 +34,7 @@ def filename(self): @property def content(self): - deps = DepsCppQbs(self.conanfile.deps_build_info) + deps = DepsCppQbs(self.deps_build_info) template = (' Product {{\n' ' name: "{dep}"\n' @@ -60,11 +61,11 @@ def content(self): sections.append(all_flags) template_deps = template + ' // {dep} root path: {deps.rootpath}\n' - for dep_name, dep_cpp_info in self.conanfile.deps_build_info.dependencies: + for dep_name, dep_cpp_info in self.deps_build_info.dependencies: deps = DepsCppQbs(dep_cpp_info) depends_items = "" for public_dep in dep_cpp_info.public_deps: - name = self.conanfile.deps_build_info[public_dep].get_name(QbsGenerator.name) + name = self.deps_build_info[public_dep].get_name(QbsGenerator.name) depends_items += depends_template.format(dep=name) dep_flags = template_deps.format(dep=dep_name, deps=deps, depends_items=depends_items) sections.append(dep_flags) diff --git a/conans/paths/__init__.py b/conans/paths/__init__.py index bce31fea34a..d5b8b54c396 100644 --- a/conans/paths/__init__.py +++ b/conans/paths/__init__.py @@ -30,7 +30,7 @@ def get_conan_user_home(): BUILD_INFO_GCC = 'conanbuildinfo.gcc' BUILD_INFO_COMPILER_ARGS = 'conanbuildinfo.args' BUILD_INFO_CMAKE = 'conanbuildinfo.cmake' -BUILD_INFO_QBS = 'conanbuildinfo.qt' +BUILD_INFO_QBS = 'conanbuildinfo.qbs' BUILD_INFO_VISUAL_STUDIO = 'conanbuildinfo.props' BUILD_INFO_XCODE = 'conanbuildinfo.xcconfig' BUILD_INFO_PREMAKE = 'conanbuildinfo.premake.lua' diff --git a/conans/test/functional/generators/generators_test.py b/conans/test/functional/generators/generators_test.py index bd1a225f5e1..c938eca7014 100644 --- a/conans/test/functional/generators/generators_test.py +++ b/conans/test/functional/generators/generators_test.py @@ -26,7 +26,7 @@ def test_base(self): [generators] cmake gcc -qt +qbs qmake scons txt @@ -47,7 +47,7 @@ def test_base(self): venv_files.extend(["activate.bat", "deactivate.bat", "environment.bat.env"]) self.assertEqual(sorted(['conanfile.txt', 'conaninfo.txt', 'conanbuildinfo.cmake', - 'conanbuildinfo.gcc', 'conanbuildinfo.qt', 'conanbuildinfo.pri', + 'conanbuildinfo.gcc', 'conanbuildinfo.qbs', 'conanbuildinfo.pri', 'SConscript_conan', 'conanbuildinfo.txt', 'conanbuildinfo.props', 'conanbuildinfo.vsprops', 'conanbuildinfo.xcconfig', 'conan_ycm_flags.json', 'conan_ycm_extra_conf.py', diff --git a/conans/test/functional/generators/qbs_test.py b/conans/test/functional/generators/qbs_test.py index 42c5da0172e..52cf9b00b7a 100644 --- a/conans/test/functional/generators/qbs_test.py +++ b/conans/test/functional/generators/qbs_test.py @@ -17,6 +17,6 @@ def test(self): pkg = GenConanfile("pkg", "0.1").with_requires("dep/0.1@user/testing") client.save({"conanfile.py": pkg}, clean_first=True) client.run("create . user/testing") - client.run("install pkg/0.1@user/testing -g=qt") - qbs = client.load("conanbuildinfo.qt") + client.run("install pkg/0.1@user/testing -g=qbs") + qbs = client.load("conanbuildinfo.qbs") self.assertIn('Depends { name: "dep" }', qbs) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 78075a8b6b7..9af254a63ea 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -2,6 +2,7 @@ import conan.tools.qt.qbs as qbs from conans.client import tools +from conans.errors import ConanException from conans.test.utils.mocks import MockConanfile, MockSettings @@ -23,7 +24,7 @@ def __call__(self, command, output, win_bash=False, subsystem=None): class QbsTest(unittest.TestCase): def test_generating_config_command_line(self): name = 'default' - dict = { + flag_dict = { 'modules.cpp.cxxFlags': ['-frtti', '-fexceptions'], 'modules.cpp.ldFlags': '--defsym=hello_world', 'products.App.myIntProperty': 13, @@ -32,17 +33,15 @@ def test_generating_config_command_line(self): expected_config_line = [ 'config:%s' % name, ] - for key, value in dict.items(): + for key, value in flag_dict.items(): if type(value) is bool: if value: value = 'true' else: value = 'false' expected_config_line.append('%s:%s' % (key, value)) - print(qbs._configuration_dict_to_commandlist(name, dict)) - print(expected_config_line) self.assertEqual( - qbs._configuration_dict_to_commandlist(name, dict), + qbs._configuration_dict_to_commandlist(name, flag_dict), expected_config_line) def test_construct_build_helper_without_project_file(self): @@ -64,7 +63,7 @@ def test_construct_build_helper_with_project_file(self): def test_construct_build_helper_with_wrong_project_file_path(self): conanfile = MockConanfile( MockSettings({'os': 'Linux', 'compiler': 'gcc'})) - with self.assertRaises(qbs.QbsException): + with self.assertRaises(ConanException): qbs.Qbs(conanfile, project_file='random/file/path') def test_add_configuration(self): @@ -93,7 +92,7 @@ def test_build(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ('qt build --no-install --build-directory %s ' + ('qbs build --no-install --build-directory %s ' '--file %s --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -101,7 +100,7 @@ def test_build(self): build_helper.build(products=['app1', 'app2', 'lib']) self.assertEqual( conanfile.runner.command_called, - ('qt build --no-install --build-directory %s ' + ('qbs build --no-install --build-directory %s ' '--file %s --products app1,app2,lib --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -117,7 +116,7 @@ def test_build_all(self): build_helper.build_all() self.assertEqual( conanfile.runner.command_called, - ('qt build --no-install --build-directory %s ' + ('qbs build --no-install --build-directory %s ' '--file %s --all-products --jobs %s profile:%s') % ( conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) @@ -140,7 +139,7 @@ def test_build_with_custom_configuration(self): build_helper.build() self.assertEqual( conanfile.runner.command_called, - ('qt build --no-install --build-directory %s ' + ('qbs build --no-install --build-directory %s ' '--file %s --jobs %s profile:%s ' 'config:%s %s:%s %s:%s %s:%s %s:%s') % ( conanfile.build_folder, build_helper._project_file, diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index d5fbe4a2e5a..15ddc557bc2 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,7 +1,7 @@ import unittest import tempfile import textwrap -import conan.tools.qt.generictoolchain as qbs +import conan.tools.qt.qbstoolchain as qbs from conans import tools from conans.errors import ConanException @@ -14,9 +14,9 @@ def __init__(self, return_ok=True, output=None): self.return_ok = return_ok self.output = output - def __init__(self, expectations=[Expectation()]): + def __init__(self, expectations=None): self.command_called = [] - self.expectations = expectations + self.expectations = expectations or [RunnerMock.Expectation()] def __call__(self, command, output, win_bash=False, subsystem=None): self.command_called.append(command) @@ -53,7 +53,7 @@ def test_convert_build_variant(self): 'os': 'Linux', 'compiler': 'gcc'})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._build_variant, None) for build_type, build_variant in qbs._build_variant.items(): @@ -62,7 +62,7 @@ def test_convert_build_variant(self): 'compiler': 'gcc', 'build_type': build_type})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._build_variant, build_variant) def test_convert_architecture(self): @@ -70,7 +70,7 @@ def test_convert_architecture(self): 'os': 'Linux', 'compiler': 'gcc'})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._architecture, None) for arch, architecture in qbs._architecture.items(): @@ -79,7 +79,7 @@ def test_convert_architecture(self): 'compiler': 'gcc', 'arch': arch})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._architecture, architecture) def test_convert_optimization(self): @@ -87,7 +87,7 @@ def test_convert_optimization(self): 'os': 'Linux', 'compiler': 'gcc'})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._optimization, None) for build_type, optimization in qbs._optimization.items(): @@ -96,7 +96,7 @@ def test_convert_optimization(self): 'compiler': 'gcc', 'build_type': build_type})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._optimization, optimization) def test_use_sysroot_from_env(self): @@ -106,7 +106,7 @@ def test_use_sysroot_from_env(self): sysroot = '/path/to/sysroot/foo/bar' with tools.environment_append({'SYSROOT': sysroot}): - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._sysroot, sysroot) def test_detect_fpic_from_options(self): @@ -125,7 +125,7 @@ def test_detect_fpic_from_options(self): 'fPIC': option })) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._position_independent_code, value) def test_convert_cxx_language_version(self): @@ -133,14 +133,14 @@ def test_convert_cxx_language_version(self): 'os': 'Linux', 'compiler': 'gcc'})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._cxx_language_version, None) conanfile = MockConanfileWithFolders(MockSettings({ 'os': 'Linux', 'compiler': 'gcc', 'compiler.cppstd': 17})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._cxx_language_version, 'c++17') for cppstd, cxx_language_version in qbs._cxx_language_version.items(): @@ -149,7 +149,7 @@ def test_convert_cxx_language_version(self): 'compiler': 'gcc', 'compiler.cppstd': cppstd})) - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain._cxx_language_version, cxx_language_version) @@ -215,7 +215,7 @@ def test_setup_toolchain_without_any_env_values(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( + 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), settings['qbs_compiler'], qbs._profile_name)) @@ -229,7 +229,7 @@ def test_setup_toolchain_with_compiler_from_env(self): self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( conanfile.runner.command_called[0], - 'qt-setup-toolchains --settings-dir "%s" %s %s' % ( + 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( qbs._settings_dir(conanfile), compiler, qbs._profile_name)) @@ -302,10 +302,10 @@ def _generate_qbs_config_output(): profiles.conan.cpp.platformLinkerFlags: undefined profiles.conan.cpp.toolchainInstallPath: "/usr/bin" profiles.conan.cpp.toolchainPrefix: "arm-none-eabi-" - profiles.conan.qt.targetPlatform: "" - profiles.conan.qt.someBoolProp: "true" - profiles.conan.qt.someIntProp: "13" - profiles.conan.qt.toolchain: ["gcc"] + profiles.conan.qbs.targetPlatform: "" + profiles.conan.qbs.someBoolProp: "true" + profiles.conan.qbs.someIntProp: "13" + profiles.conan.qbs.toolchain: ["gcc"] ''') def test_read_qbs_toolchain_from_qbs_config_output(self): @@ -318,10 +318,10 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): 'cpp.platformLinkerFlags': 'undefined', 'cpp.toolchainInstallPath': '"/usr/bin"', 'cpp.toolchainPrefix': '"arm-none-eabi-"', - 'qt.targetPlatform': '""', - 'qt.someBoolProp': 'true', - 'qt.someIntProp': '13', - 'qt.toolchain': '["gcc"]' + 'qbs.targetPlatform': '""', + 'qbs.someBoolProp': 'true', + 'qbs.someIntProp': '13', + 'qbs.toolchain': '["gcc"]' } conanfile = MockConanfileWithFolders( @@ -331,19 +331,19 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): config = qbs._read_qbs_toolchain_from_config(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual(conanfile.runner.command_called[0], - 'qt-config --settings-dir "%s" --list' % ( + 'qbs-config --settings-dir "%s" --list' % ( qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) def test_toolchain_content(self): expected_content = textwrap.dedent('''\ - import qt + import qbs Project { Profile { name: "conan_toolchain_profile" - /* detected via qt-setup-toolchains */ + /* detected via qbs-setup-toolchains */ cpp.cCompilerName: "gcc" cpp.compilerName: "g++" cpp.cxxCompilerName: "g++" @@ -352,18 +352,18 @@ def test_toolchain_content(self): cpp.platformLinkerFlags: undefined cpp.toolchainInstallPath: "/usr/bin" cpp.toolchainPrefix: "arm-none-eabi-" - qt.targetPlatform: "" - qt.someBoolProp: true - qt.someIntProp: 13 - qt.toolchain: ["gcc"] + qbs.targetPlatform: "" + qbs.someBoolProp: true + qbs.someIntProp: 13 + qbs.toolchain: ["gcc"] /* deduced from environment */ - qt.sysroot: "/foo/bar/path" + qbs.sysroot: "/foo/bar/path" /* conan settings */ - qt.buildVariant: "release" - qt.architecture: "x86_64" - qt.optimization: "small" + qbs.buildVariant: "release" + qbs.architecture: "x86_64" + qbs.optimization: "small" cpp.cxxLanguageVersion: "c++17" /* package options */ @@ -390,6 +390,6 @@ def test_toolchain_content(self): ])) with tools.environment_append({'SYSROOT': '/foo/bar/path'}): - qbs_toolchain = qbs.QbsGenericToolchain(conanfile) + qbs_toolchain = qbs.QbsToolchain(conanfile) self.assertEqual(qbs_toolchain.content, expected_content) From 84081f1bd9701ab7a0f67aa1c870acc0b85eb283 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Thu, 17 Dec 2020 08:07:22 +0100 Subject: [PATCH 20/23] Fix MSVC+ClangCL compatibility --- conan/tools/qbs/generictoolchain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conan/tools/qbs/generictoolchain.py b/conan/tools/qbs/generictoolchain.py index b70e9747877..898d88ab838 100644 --- a/conan/tools/qbs/generictoolchain.py +++ b/conan/tools/qbs/generictoolchain.py @@ -97,7 +97,7 @@ def _default_compiler_name(conanfile): if compiler == 'gcc': return 'mingw' if compiler == 'Visual Studio': - if tools.msvs_toolset(conanfile) == 'ClangCl': + if tools.msvs_toolset(conanfile) == 'ClangCL': return 'clang-cl' return 'cl' if compiler == 'clang': @@ -120,7 +120,7 @@ def _setup_toolchains(conanfile): env_context = tools.no_op() if platform.system() == 'Windows': if compiler in ['cl', 'clang-cl']: - env_context = tools.vcvars() + env_context = tools.vcvars(conanfile) with env_context: cmd = 'qbs-setup-toolchains --settings-dir "%s" %s %s' % ( From 0ef5587a6c1beaacf245e300ed043366af73c427 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Thu, 17 Dec 2020 08:22:30 +0100 Subject: [PATCH 21/23] Adjusted test to last change Missed to change test according to change --- conans/test/unittests/client/toolchain/test_qbs_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index ea483565116..95024db77ec 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -188,7 +188,7 @@ def _settings_to_test_against(): {'os': 'Windows', 'compiler': 'Visual Studio', 'qbs_compiler': 'cl'}, {'os': 'Windows', 'compiler': 'Visual Studio', - 'compiler.toolset': 'ClangCl', 'qbs_compiler': 'clang-cl'}, + 'compiler.toolset': 'ClangCL', 'qbs_compiler': 'clang-cl'}, {'os': 'Linux', 'compiler': 'gcc', 'qbs_compiler': 'gcc'}, {'os': 'Linux', 'compiler': 'clang', 'qbs_compiler': 'clang'} ] From ac1901ca10d471fb498d057ac70fda43cecfe4ec Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 21 Dec 2020 12:11:16 +0100 Subject: [PATCH 22/23] returned back to qbs namespace --- conan/tools/qbs/__init__.py | 2 ++ conan/tools/{qt => qbs}/qbs.py | 0 conan/tools/{qt => qbs}/qbstoolchain.py | 0 conan/tools/qt/__init__.py | 2 -- conans/client/generators/__init__.py | 2 +- conans/test/unittests/client/build/qbs_test.py | 2 +- .../unittests/client/toolchain/test_qbs_generic.py | 10 +++++----- 7 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 conan/tools/qbs/__init__.py rename conan/tools/{qt => qbs}/qbs.py (100%) rename conan/tools/{qt => qbs}/qbstoolchain.py (100%) delete mode 100644 conan/tools/qt/__init__.py diff --git a/conan/tools/qbs/__init__.py b/conan/tools/qbs/__init__.py new file mode 100644 index 00000000000..102e73a682e --- /dev/null +++ b/conan/tools/qbs/__init__.py @@ -0,0 +1,2 @@ +from conan.tools.qbs.qbstoolchain import QbsToolchain +from conan.tools.qbs.qbs import Qbs diff --git a/conan/tools/qt/qbs.py b/conan/tools/qbs/qbs.py similarity index 100% rename from conan/tools/qt/qbs.py rename to conan/tools/qbs/qbs.py diff --git a/conan/tools/qt/qbstoolchain.py b/conan/tools/qbs/qbstoolchain.py similarity index 100% rename from conan/tools/qt/qbstoolchain.py rename to conan/tools/qbs/qbstoolchain.py diff --git a/conan/tools/qt/__init__.py b/conan/tools/qt/__init__.py deleted file mode 100644 index 22a8730f3f9..00000000000 --- a/conan/tools/qt/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from conan.tools.qt.qbstoolchain import QbsToolchain -from conan.tools.qt.qbs import Qbs diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py index 69791f56d26..b3b5df028c3 100644 --- a/conans/client/generators/__init__.py +++ b/conans/client/generators/__init__.py @@ -104,7 +104,7 @@ def _new_generator(self, generator_name, output): from conan.tools.microsoft import MSBuildDeps return MSBuildDeps elif generator_name == "QbsToolchain": - from conan.tools.qt.qbstoolchain import QbsToolchain + from conan.tools.qbs.qbstoolchain import QbsToolchain return QbsToolchain else: raise ConanException("Internal Conan error: Generator '{}' " diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 9af254a63ea..662f939e4c4 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -1,5 +1,5 @@ import unittest -import conan.tools.qt.qbs as qbs +import conan.tools.qbs.qbs as qbs from conans.client import tools from conans.errors import ConanException diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 7eeca885214..98e2e70ac0b 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,7 +1,7 @@ import unittest import tempfile import textwrap -import conan.tools.qt.qbstoolchain as qbs +import conan.tools.qbs.qbstoolchain as qbs from conans import tools from conans.errors import ConanException @@ -154,13 +154,13 @@ def test_convert_cxx_language_version(self): cxx_language_version) def test_split_env_var_into_list(self): - list = ['-p1', '-p2', '-p3_with_value=13', - '-p_with_space1="hello world"', - '"-p_with_space2=Hello World"'] + env_var_list = ['-p1', '-p2', '-p3_with_value=13', + '-p_with_space1="hello world"', + '"-p_with_space2=Hello World"'] expected_list = ['-p1', '-p2', '-p3_with_value=13', '-p_with_space1=hello world', '-p_with_space2=Hello World'] - env_var = ' '.join(list) + env_var = ' '.join(env_var_list) self.assertEqual(qbs._env_var_to_list(env_var), expected_list) def test_compiler_not_in_settings(self): From 828a836e273224c38e087a5330f6c576ddd29cb0 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 22 Dec 2020 01:02:51 +0100 Subject: [PATCH 23/23] fixing tests PY2 --- .../test/unittests/client/build/qbs_test.py | 7 +++++- .../client/toolchain/test_qbs_generic.py | 24 +++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/conans/test/unittests/client/build/qbs_test.py b/conans/test/unittests/client/build/qbs_test.py index 662f939e4c4..f18a58de811 100644 --- a/conans/test/unittests/client/build/qbs_test.py +++ b/conans/test/unittests/client/build/qbs_test.py @@ -1,9 +1,13 @@ import unittest + +import six + import conan.tools.qbs.qbs as qbs from conans.client import tools from conans.errors import ConanException from conans.test.utils.mocks import MockConanfile, MockSettings +from conans.test.utils.test_files import temp_folder class RunnerMock(object): @@ -56,7 +60,7 @@ def test_construct_build_helper_with_project_file(self): conanfile = MockConanfile( MockSettings({'os': 'Linux', 'compiler': 'gcc'})) # just asume that the test is called from repo root - profile_file_path = 'conans/client' + profile_file_path = temp_folder() build_helper = qbs.Qbs(conanfile, project_file=profile_file_path) self.assertEqual(build_helper._project_file, profile_file_path) @@ -121,6 +125,7 @@ def test_build_all(self): conanfile.build_folder, build_helper._project_file, build_helper.jobs, build_helper.use_toolchain_profile)) + @unittest.skipIf(six.PY2, "Order of qbs output is defined only for PY3") def test_build_with_custom_configuration(self): conanfile = MockConanfile( MockSettings({'os': 'Linux', 'compiler': 'gcc'}), diff --git a/conans/test/unittests/client/toolchain/test_qbs_generic.py b/conans/test/unittests/client/toolchain/test_qbs_generic.py index 98e2e70ac0b..7cbed695561 100644 --- a/conans/test/unittests/client/toolchain/test_qbs_generic.py +++ b/conans/test/unittests/client/toolchain/test_qbs_generic.py @@ -1,6 +1,9 @@ import unittest import tempfile import textwrap + +import six + import conan.tools.qbs.qbstoolchain as qbs from conans import tools @@ -12,6 +15,8 @@ class RunnerMock(object): class Expectation(object): def __init__(self, return_ok=True, output=None): self.return_ok = return_ok + if six.PY2 and output: + output = output.decode("utf-8") self.output = output def __init__(self, expectations=None): @@ -183,15 +188,15 @@ def test_valid_compiler(self): @staticmethod def _settings_to_test_against(): return [ - {'os': 'Windows', 'compiler': 'gcc', 'qbs_compiler': 'mingw'}, - {'os': 'Windows', 'compiler': 'clang', + {'os': 'Windows', 'compiler': 'gcc', 'compiler.version': '6', 'qbs_compiler': 'mingw'}, + {'os': 'Windows', 'compiler': 'clang', 'compiler.version': '3.9', 'qbs_compiler': 'clang-cl'}, - {'os': 'Windows', 'compiler': 'Visual Studio', + {'os': 'Windows', 'compiler': 'Visual Studio', 'compiler.version': '15', 'qbs_compiler': 'cl'}, - {'os': 'Windows', 'compiler': 'Visual Studio', + {'os': 'Windows', 'compiler': 'Visual Studio', 'compiler.version': '15', 'compiler.toolset': 'ClangCL', 'qbs_compiler': 'clang-cl'}, - {'os': 'Linux', 'compiler': 'gcc', 'qbs_compiler': 'gcc'}, - {'os': 'Linux', 'compiler': 'clang', 'qbs_compiler': 'clang'} + {'os': 'Linux', 'compiler': 'gcc', 'compiler.version': '6', 'qbs_compiler': 'gcc'}, + {'os': 'Linux', 'compiler': 'clang', 'compiler.version': '3.9', 'qbs_compiler': 'clang'} ] def test_convert_compiler_name_to_qbs_compiler_name(self): @@ -209,8 +214,7 @@ def test_settings_dir_location(self): def test_setup_toolchain_without_any_env_values(self): for settings in self._settings_to_test_against(): - conanfile = MockConanfileWithFolders(MockSettings(settings), - runner=RunnerMock()) + conanfile = MockConanfileWithFolders(MockSettings(settings), runner=RunnerMock()) qbs._setup_toolchains(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) self.assertEqual( @@ -222,8 +226,7 @@ def test_setup_toolchain_without_any_env_values(self): def test_setup_toolchain_with_compiler_from_env(self): compiler = 'compiler_from_env' for settings in self._settings_to_test_against(): - conanfile = MockConanfileWithFolders(MockSettings(settings), - runner=RunnerMock()) + conanfile = MockConanfileWithFolders(MockSettings(settings), runner=RunnerMock()) with tools.environment_append({'CC': compiler}): qbs._setup_toolchains(conanfile) self.assertEqual(len(conanfile.runner.command_called), 1) @@ -335,6 +338,7 @@ def test_read_qbs_toolchain_from_qbs_config_output(self): qbs._settings_dir(conanfile))) self.assertEqual(config, expected_config) + @unittest.skipIf(six.PY2, "Order of qbs output is defined only for PY3") def test_toolchain_content(self): expected_content = textwrap.dedent('''\ import qbs