From f38d6bdbd86e11b616d5eb222a8ac7dcca50d80d Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Sat, 1 Jun 2024 19:10:24 +0300 Subject: [PATCH 1/3] Qbs: fix handling spaces Also add a simple static lib functional test as well as api to create libs. --- conan/api/subapi/new.py | 4 +- conan/internal/api/new/qbs_lib.py | 46 ++++++++++++++++++++++ conan/tools/qbs/qbs.py | 8 ++-- test/functional/toolchains/qbs/test_qbs.py | 40 +++++++++++++++++++ 4 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 conan/internal/api/new/qbs_lib.py create mode 100644 test/functional/toolchains/qbs/test_qbs.py 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..2557905141c --- /dev/null +++ b/conan/internal/api/new/qbs_lib.py @@ -0,0 +1,46 @@ +from conan.internal.api.new.cmake_lib import source_cpp, source_h + + +conanfile_sources = ''' +import os + +from conan import ConanFile, tools +from conan.tools.qbs import Qbs +from conan.tools.files import copy, collect_libs + +class {{package_name}}Recipe(ConanFile): + name = "{{name}}" + version = "{{version}}" + + exports_sources = "*.cpp", "*.h", "*.qbs" + settings = "os", "compiler", "arch" + + def build(self): + qbs = Qbs(self) + qbs.profile = "" + qbs.build() + + def package(self): + qbs = Qbs(self) + qbs.profile = "" + qbs.install() + + def package_info(self): + self.cpp_info.libs = collect_libs(self) +''' + +qbs_file = ''' + Library { + type: "staticlibrary" + files: [ "{{name}}.h", "{{name}}.cpp" ] + Depends { name: "cpp" } + Depends { name: "bundle" } + bundle.isBundle: false + install: true + } +''' + +qbs_lib_files = {"conanfile.py": conanfile_sources, + "{{name}}.qbs": qbs_file, + "{{name}}.cpp": source_cpp, + "{{name}}.h": source_h} 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/functional/toolchains/qbs/test_qbs.py b/test/functional/toolchains/qbs/test_qbs.py new file mode 100644 index 00000000000..50e56097da1 --- /dev/null +++ b/test/functional/toolchains/qbs/test_qbs.py @@ -0,0 +1,40 @@ +import pytest + +from conan.internal.api.new.cmake_lib import source_cpp, source_h +from conan.internal.api.new.qbs_lib import qbs_file, conanfile_sources +from conan.test.utils.tools import TestClient +from jinja2 import Template + + +def gen_file(template, **context): + t = Template(template) + return t.render(**context) + + +@pytest.mark.tool("qbs") +def test_qbs_static_lib(): + client = TestClient() + + context = { + "name": "hello", + "version": "2.0", + "package_name": "hello" + } + + client.save({ + "conanfile.py": gen_file(conanfile_sources, **context), + "hello.cpp": gen_file(source_cpp, **context), + "hello.h": gen_file(source_h, **context), + "hello.qbs": gen_file(qbs_file, **context), + }, clean_first=True) + + client.run("create .") + assert "compiling hello.cpp" in client.out + + +@pytest.mark.tool("qbs") +def test_api_qbs_create_lib(): + client = TestClient() + client.run("new qbs_lib -d name=hello -d version=1.0") + client.run("create .") + assert "compiling hello.cpp" in client.out From d53bd9eda2e8d4514cd4a561b85b987f2d94f492 Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Sun, 2 Jun 2024 01:17:26 +0300 Subject: [PATCH 2/3] implement shared libs in api/new --- conan/internal/api/new/qbs_lib.py | 8 ++++- test/conftest.py | 1 + test/functional/toolchains/qbs/test_qbs.py | 40 ++++------------------ 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/conan/internal/api/new/qbs_lib.py b/conan/internal/api/new/qbs_lib.py index 2557905141c..46ba8285c8e 100644 --- a/conan/internal/api/new/qbs_lib.py +++ b/conan/internal/api/new/qbs_lib.py @@ -14,10 +14,14 @@ class {{package_name}}Recipe(ConanFile): 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): @@ -31,7 +35,9 @@ def package_info(self): qbs_file = ''' Library { - type: "staticlibrary" + property bool isShared: true + name: "{{name}}" + type: isShared ? "dynamiclibrary" : "staticlibrary" files: [ "{{name}}.h", "{{name}}.cpp" ] Depends { name: "cpp" } Depends { name: "bundle" } 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 index 50e56097da1..c61439f21ef 100644 --- a/test/functional/toolchains/qbs/test_qbs.py +++ b/test/functional/toolchains/qbs/test_qbs.py @@ -1,40 +1,14 @@ import pytest -from conan.internal.api.new.cmake_lib import source_cpp, source_h -from conan.internal.api.new.qbs_lib import qbs_file, conanfile_sources from conan.test.utils.tools import TestClient -from jinja2 import Template - - -def gen_file(template, **context): - t = Template(template) - return t.render(**context) - - -@pytest.mark.tool("qbs") -def test_qbs_static_lib(): - client = TestClient() - - context = { - "name": "hello", - "version": "2.0", - "package_name": "hello" - } - - client.save({ - "conanfile.py": gen_file(conanfile_sources, **context), - "hello.cpp": gen_file(source_cpp, **context), - "hello.h": gen_file(source_h, **context), - "hello.qbs": gen_file(qbs_file, **context), - }, clean_first=True) - - client.run("create .") - assert "compiling hello.cpp" in client.out - +@pytest.mark.parametrize('shared', [ + ('False'), + ('True'), +]) @pytest.mark.tool("qbs") -def test_api_qbs_create_lib(): +def test_api_qbs_create_lib(shared): client = TestClient() client.run("new qbs_lib -d name=hello -d version=1.0") - client.run("create .") - assert "compiling hello.cpp" in client.out + client.run("create . -o:h &:shared={shared}".format(shared=shared)) + assert "compiling hello.cpp" in client.out \ No newline at end of file From 55da7d6273034cefac2131ec856ea3f165d77d9e Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Sun, 2 Jun 2024 18:40:15 +0300 Subject: [PATCH 3/3] Properly test qbs lib package --- conan/internal/api/new/qbs_lib.py | 67 +++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/conan/internal/api/new/qbs_lib.py b/conan/internal/api/new/qbs_lib.py index 46ba8285c8e..2c71e8ff5a9 100644 --- a/conan/internal/api/new/qbs_lib.py +++ b/conan/internal/api/new/qbs_lib.py @@ -1,12 +1,12 @@ -from conan.internal.api.new.cmake_lib import source_cpp, source_h +from conan.internal.api.new.cmake_lib import source_cpp, source_h, test_main conanfile_sources = ''' import os -from conan import ConanFile, tools +from conan import ConanFile from conan.tools.qbs import Qbs -from conan.tools.files import copy, collect_libs + class {{package_name}}Recipe(ConanFile): name = "{{name}}" @@ -30,23 +30,74 @@ def package(self): qbs.install() def package_info(self): - self.cpp_info.libs = collect_libs(self) + self.cpp_info.libs = ["{{name}}"] ''' -qbs_file = ''' +qbs_lib_file = ''' Library { property bool isShared: true name: "{{name}}" type: isShared ? "dynamiclibrary" : "staticlibrary" - files: [ "{{name}}.h", "{{name}}.cpp" ] + 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_file, + "{{name}}.qbs": qbs_lib_file, "{{name}}.cpp": source_cpp, - "{{name}}.h": source_h} + "{{name}}.h": source_h, + "test_package/conanfile.py": test_conanfile_v2, + "test_package/example.cpp": test_main, + "test_package/example.qbs": qbs_test_file}