diff --git a/conan/api/subapi/new.py b/conan/api/subapi/new.py index 573ce75d49d..23eaab4fb8a 100644 --- a/conan/api/subapi/new.py +++ b/conan/api/subapi/new.py @@ -29,6 +29,7 @@ def get_builtin_template(template_name): from conan.internal.api.new.autotools_lib import autotools_lib_files from conan.internal.api.new.autoools_exe import autotools_exe_files from conan.internal.api.new.local_recipes_index import local_recipes_index_files + from conan.internal.api.new.qbs_lib import qbs_lib_files new_templates = {"basic": basic_file, "cmake_lib": cmake_lib_files, "cmake_exe": cmake_exe_files, @@ -41,7 +42,8 @@ def get_builtin_template(template_name): "autotools_lib": autotools_lib_files, "autotools_exe": autotools_exe_files, "alias": alias_file, - "local_recipes_index": local_recipes_index_files} + "local_recipes_index": local_recipes_index_files, + "qbs_lib": qbs_lib_files} template_files = new_templates.get(template_name) return template_files diff --git a/conan/internal/api/new/qbs_lib.py b/conan/internal/api/new/qbs_lib.py new file mode 100644 index 00000000000..2c71e8ff5a9 --- /dev/null +++ b/conan/internal/api/new/qbs_lib.py @@ -0,0 +1,103 @@ +from conan.internal.api.new.cmake_lib import source_cpp, source_h, test_main + + +conanfile_sources = ''' +import os + +from conan import ConanFile +from conan.tools.qbs import Qbs + + +class {{package_name}}Recipe(ConanFile): + name = "{{name}}" + version = "{{version}}" + + exports_sources = "*.cpp", "*.h", "*.qbs" + settings = "os", "compiler", "arch" + options = {"shared": [True, False]} + default_options = {"shared": False} + + def build(self): + qbs = Qbs(self) + qbs.profile = "" + qbs_config = {"products.{{name}}.isShared": "true" if self.options.shared else "false"} + qbs.add_configuration("default", qbs_config) + qbs.build() + + def package(self): + qbs = Qbs(self) + qbs.profile = "" + qbs.install() + + def package_info(self): + self.cpp_info.libs = ["{{name}}"] +''' + +qbs_lib_file = ''' + Library { + property bool isShared: true + name: "{{name}}" + type: isShared ? "dynamiclibrary" : "staticlibrary" + files: [ "{{name}}.cpp" ] + Group { + name: "headers" + files: [ "{{name}}.h" ] + qbs.install: true + qbs.installDir: "include" + } + Depends { name: "cpp" } + Depends { name: "bundle" } + bundle.isBundle: false + install: true + qbs.installPrefix: "" + } +''' + +test_conanfile_v2 = """import os + +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.qbs import Qbs +from conan.tools.build import cmd_args_to_string + +class {{package_name}}TestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "PkgConfigDeps" + + def requirements(self): + self.requires(self.tested_reference_str) + + def build(self): + qbs = Qbs(self) + qbs.profile = "" + qbs.build() + qbs.install() + + def test(self): + if can_run(self): + cmd = os.path.join(self.package_folder, "bin", "example") + self.run(cmd_args_to_string([cmd]), env="conanrun") +""" + +qbs_test_file = ''' + Application { + name: "example" + consoleApplication: true + files: [ "example.cpp" ] + Depends { name: "cpp" } + install: true + qbs.installPrefix: "" + // external dependency via pkg-config + qbsModuleProviders: ["qbspkgconfig"] + moduleProviders.qbspkgconfig.libDirs: path + Depends { name: "{{name}}" } + } +''' + +qbs_lib_files = {"conanfile.py": conanfile_sources, + "{{name}}.qbs": qbs_lib_file, + "{{name}}.cpp": source_cpp, + "{{name}}.h": source_h, + "test_package/conanfile.py": test_conanfile_v2, + "test_package/example.cpp": test_main, + "test_package/example.qbs": qbs_test_file} diff --git a/conan/tools/qbs/qbs.py b/conan/tools/qbs/qbs.py index db4bb87e079..d65a91b3f44 100644 --- a/conan/tools/qbs/qbs.py +++ b/conan/tools/qbs/qbs.py @@ -1,6 +1,6 @@ import os -from conan.tools.build import build_jobs +from conan.tools.build import build_jobs, cmd_args_to_string from conan.errors import ConanException @@ -59,7 +59,7 @@ def build(self, products=None): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qbs build %s' % (' '.join(args)) + cmd = 'qbs build %s' % cmd_args_to_string(args) self._conanfile.run(cmd) def build_all(self): @@ -79,7 +79,7 @@ def build_all(self): config = self._configuration[name] args.extend(_configuration_dict_to_commandlist(name, config)) - cmd = 'qbs build %s' % (' '.join(args)) + cmd = 'qbs build %s' % cmd_args_to_string(args) self._conanfile.run(cmd) def install(self): @@ -92,5 +92,5 @@ def install(self): for name in self._configuration: args.append('config:%s' % name) - cmd = 'qbs install %s' % (' '.join(args)) + cmd = 'qbs install %s' % cmd_args_to_string(args) self._conanfile.run(cmd) diff --git a/test/conftest.py b/test/conftest.py index a85c2b2af01..bc148aabefd 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -181,6 +181,7 @@ "path": {'Darwin': f'{homebrew_root}/share/android-ndk'} } }, + "qbs": {"disabled": True}, # TODO: Intel oneAPI is not installed in CI yet. Uncomment this line whenever it's done. # "intel_oneapi": { # "default": "2021.3", diff --git a/test/functional/toolchains/qbs/test_qbs.py b/test/functional/toolchains/qbs/test_qbs.py new file mode 100644 index 00000000000..c61439f21ef --- /dev/null +++ b/test/functional/toolchains/qbs/test_qbs.py @@ -0,0 +1,14 @@ +import pytest + +from conan.test.utils.tools import TestClient + +@pytest.mark.parametrize('shared', [ + ('False'), + ('True'), +]) +@pytest.mark.tool("qbs") +def test_api_qbs_create_lib(shared): + client = TestClient() + client.run("new qbs_lib -d name=hello -d version=1.0") + client.run("create . -o:h &:shared={shared}".format(shared=shared)) + assert "compiling hello.cpp" in client.out \ No newline at end of file