From ad2631d2710aab500fbe4f9c9f74e1730bfb63c5 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 4 Apr 2024 14:36:23 +0200 Subject: [PATCH 1/6] presets relativize paths --- conan/tools/cmake/presets.py | 33 ++++++++++++++---------- conan/tools/cmake/toolchain/toolchain.py | 10 +++---- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index c6fd71bd851..7fb3ae29e3b 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -1,8 +1,9 @@ import json import os import platform +import textwrap -from conan.api.output import ConanOutput +from conan.api.output import ConanOutput, Color from conan.tools.cmake.layout import get_build_folder_custom_vars from conan.tools.cmake.toolchain.blocks import GenericSystemBlock from conan.tools.cmake.utils import is_multi_configuration @@ -28,6 +29,11 @@ class _CMakePresets: @staticmethod def generate(conanfile, toolchain_file, generator, cache_variables, preset_prefix, buildenv, runenv, cmake_executable): + toolchain_file = os.path.abspath(os.path.join(conanfile.generators_folder, toolchain_file)) + try: # Make it relative to the build dir if possible + toolchain_file = os.path.relpath(toolchain_file, conanfile.build_folder) + except ValueError: + pass cache_variables = cache_variables or {} if platform.system() == "Windows" and generator == "MinGW Makefiles": if "CMAKE_SH" not in cache_variables: @@ -74,7 +80,7 @@ def generate(conanfile, toolchain_file, generator, cache_variables, preset_prefi preset_content = json.dumps(data, indent=4) save(preset_path, preset_content) - ConanOutput(str(conanfile)).info("CMakeToolchain generated: CMakePresets.json") + ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {preset_path}") return preset_path, data @staticmethod @@ -172,13 +178,11 @@ def _format_val(val): except: is_consumer = False if is_consumer: - conanfile.output.info( - f"Preset '{name}' added to CMakePresets.json. Invoke it manually using " - f"'cmake --preset {name}' if using CMake>=3.23") - conanfile.output.info(f"If your CMake version is not compatible with " - f"CMakePresets (<3.23) call cmake like: 'cmake " - f"-G {_format_val(generator)} {add_toolchain_cache}" - f"{cache_variables_info}'") + msg = textwrap.dedent(f"""\ + CMakeToolchain: Preset '{name}' added to CMakePresets.json. + (cmake>=3.23) cmake --preset {name} + (cmake<3.23) cmake -G {_format_val(generator)} {add_toolchain_cache} {cache_variables_info}""") + conanfile.output.info(msg, fg=Color.CYAN) return ret @staticmethod @@ -283,14 +287,15 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da if inherited_user: _IncludingPresets._clean_user_inherits(data, preset_data) + + try: # Make it relative to the build dir if possible + preset_path = os.path.relpath(preset_path, output_dir) + except ValueError: + pass data = _IncludingPresets._append_user_preset_path(data, preset_path) data = json.dumps(data, indent=4) - try: - presets_path = os.path.relpath(user_presets_path, conanfile.generators_folder) - except ValueError: # in Windows this fails if in another drive - presets_path = user_presets_path - ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {presets_path}") + ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {user_presets_path}") save(user_presets_path, data) @staticmethod diff --git a/conan/tools/cmake/toolchain/toolchain.py b/conan/tools/cmake/toolchain/toolchain.py index 8391f93790c..22e8c38013e 100644 --- a/conan/tools/cmake/toolchain/toolchain.py +++ b/conan/tools/cmake/toolchain/toolchain.py @@ -227,16 +227,16 @@ def generate(self): check_duplicated_generator(self, self._conanfile) toolchain_file = self._conanfile.conf.get("tools.cmake.cmaketoolchain:toolchain_file") if toolchain_file is None: # The main toolchain file generated only if user dont define - save(os.path.join(self._conanfile.generators_folder, self.filename), self.content) - ConanOutput(str(self._conanfile)).info(f"CMakeToolchain generated: {self.filename}") + toolchain_file = self.filename + save(os.path.join(self._conanfile.generators_folder, toolchain_file), self.content) + ConanOutput(str(self._conanfile)).info(f"CMakeToolchain generated: {toolchain_file}") # If we're using Intel oneAPI, we need to generate the environment file and run it if self._conanfile.settings.get_safe("compiler") == "intel-cc": IntelCC(self._conanfile).generate() # Generators like Ninja or NMake requires an active vcvars elif self.generator is not None and "Visual" not in self.generator: VCVars(self._conanfile).generate() - toolchain = os.path.abspath(os.path.join(self._conanfile.generators_folder, - toolchain_file or self.filename)) + cache_variables = {} for name, value in self.cache_variables.items(): if isinstance(value, bool): @@ -266,7 +266,7 @@ def generate(self): cmake_executable = self._conanfile.conf.get("tools.cmake:cmake_program", None) or self._find_cmake_exe() - write_cmake_presets(self._conanfile, toolchain, self.generator, cache_variables, + write_cmake_presets(self._conanfile, toolchain_file, self.generator, cache_variables, self.user_presets_path, self.presets_prefix, buildenv, runenv, cmake_executable) From 6b6fa1db744a4fb20de034d7b104a241ec41936c Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 4 Apr 2024 19:19:15 +0200 Subject: [PATCH 2/6] fix --- conan/tools/cmake/cmake.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/conan/tools/cmake/cmake.py b/conan/tools/cmake/cmake.py index 3ac9760fb3c..02a80b39cd7 100644 --- a/conan/tools/cmake/cmake.py +++ b/conan/tools/cmake/cmake.py @@ -95,11 +95,8 @@ def configure(self, variables=None, build_script_folder=None, cli_args=None, if self._generator: arg_list.append('-G "{}"'.format(self._generator)) if self._toolchain_file: - if os.path.isabs(self._toolchain_file): - toolpath = self._toolchain_file - else: - toolpath = os.path.join(generator_folder, self._toolchain_file) - arg_list.append('-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolpath.replace("\\", "/"))) + toolpath = self._toolchain_file.replace("\\", "/") + arg_list.append('-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolpath)) if self._conanfile.package_folder: pkg_folder = self._conanfile.package_folder.replace("\\", "/") arg_list.append('-DCMAKE_INSTALL_PREFIX="{}"'.format(pkg_folder)) From 8aa9d2e64d3c126e41e79fa1cd53e8f581da4fd4 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 5 Apr 2024 00:20:39 +0200 Subject: [PATCH 3/6] wip --- .../test/functional/toolchains/cmake/test_cmake.py | 14 ++++---------- .../toolchains/cmake/test_cmake_toolchain.py | 8 ++++---- .../cmake/test_cmake_toolchain_win_clang.py | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/conans/test/functional/toolchains/cmake/test_cmake.py b/conans/test/functional/toolchains/cmake/test_cmake.py index d98610e4ade..4e3dfb7a827 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake.py +++ b/conans/test/functional/toolchains/cmake/test_cmake.py @@ -216,13 +216,9 @@ def test_toolchain_win(self, compiler, build_type, runtime, version, cppstd, arc } options = {"shared": shared} save(self.client.cache.new_config_path, "tools.build:jobs=1") - install_out = self._run_build(settings, options) - - # FIXME: Hardcoded VS version and partial toolset check - toolchain_path = os.path.join(self.client.current_folder, "build", - "conan_toolchain.cmake").replace("\\", "/") + self._run_build(settings, options) self.assertIn('cmake -G "Visual Studio 15 2017" ' - '-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolchain_path), self.client.out) + '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) if toolset == "v140": self.assertIn("Microsoft Visual Studio 14.0", self.client.out) else: @@ -312,12 +308,10 @@ def test_toolchain_mingw_win(self, build_type, libcxx, version, cppstd, arch, sh "build_type": build_type, } options = {"shared": shared} - install_out = self._run_build(settings, options) + self._run_build(settings, options) self.assertIn("The C compiler identification is GNU", self.client.out) - toolchain_path = os.path.join(self.client.current_folder, "build", - "conan_toolchain.cmake").replace("\\", "/") self.assertIn('cmake -G "MinGW Makefiles" ' - '-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolchain_path), self.client.out) + '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) assert '-DCMAKE_SH="CMAKE_SH-NOTFOUND"' in self.client.out def _verify_out(marker=">>"): diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py index 2463c2f9710..4ee2a78f19a 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py +++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py @@ -693,7 +693,7 @@ def test_cmake_presets_multiple_settings_single_config(): assert os.path.exists(user_presets_path) user_presets = json.loads(load(user_presets_path)) assert len(user_presets["include"]) == 1 - presets = json.loads(load(user_presets["include"][0])) + presets = json.loads(client.load(user_presets["include"][0])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 @@ -710,7 +710,7 @@ def test_cmake_presets_multiple_settings_single_config(): assert os.path.exists(user_presets_path) user_presets = json.loads(load(user_presets_path)) assert len(user_presets["include"]) == 2 - presets = json.loads(load(user_presets["include"][0])) + presets = json.loads(client.load(user_presets["include"][0])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 @@ -887,7 +887,7 @@ def test_cmake_presets_multiple_settings_multi_config(): assert os.path.exists(user_presets_path) user_presets = json.loads(load(user_presets_path)) assert len(user_presets["include"]) == 1 - presets = json.loads(load(user_presets["include"][0])) + presets = json.loads(client.load(user_presets["include"][0])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 @@ -904,7 +904,7 @@ def test_cmake_presets_multiple_settings_multi_config(): assert os.path.exists(user_presets_path) user_presets = json.loads(load(user_presets_path)) assert len(user_presets["include"]) == 1 - presets = json.loads(load(user_presets["include"][0])) + presets = json.loads(client.load(user_presets["include"][0])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 2 assert len(presets["testPresets"]) == 2 diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py index c2fcd265e39..1261ea73189 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py +++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py @@ -155,7 +155,7 @@ def test_clang_visual_studio_generator(self, client): '-c tools.cmake.cmaketoolchain:generator="{}"'.format(generator)) assert 'cmake -G "{}"'.format(generator) in client.out assert "MSVC-like command-line" in client.out - assert "main __clang_major__16" in client.out + assert "main __clang_major__17" in client.out # Check this! Clang compiler in Windows is reporting MSC_VER and MSVC_LANG! assert "main _MSC_VER193" in client.out assert "main _MSVC_LANG2017" in client.out From f0b05f188f159fc65195dac5a4935e2695167250 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 5 Apr 2024 10:19:25 +0200 Subject: [PATCH 4/6] fixes --- conan/tools/cmake/presets.py | 7 ++++--- .../functional/toolchains/cmake/test_cmake_toolchain.py | 6 +++--- conans/test/functional/toolchains/test_basic.py | 4 +--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 7fb3ae29e3b..050265c9efc 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -292,7 +292,7 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da preset_path = os.path.relpath(preset_path, output_dir) except ValueError: pass - data = _IncludingPresets._append_user_preset_path(data, preset_path) + data = _IncludingPresets._append_user_preset_path(data, preset_path, output_dir) data = json.dumps(data, indent=4) ConanOutput(str(conanfile)).info(f"CMakeToolchain generated: {user_presets_path}") @@ -331,7 +331,7 @@ def _clean_user_inherits(data, preset_data): other[:] = [p for p in other if p["name"] not in presets_names] @staticmethod - def _append_user_preset_path(data, preset_path): + def _append_user_preset_path(data, preset_path, output_dir): """ - Appends a 'include' to preset_path if the schema supports it. - Otherwise it merges to "data" all the configurePresets, buildPresets etc from the read preset_path. @@ -339,7 +339,8 @@ def _append_user_preset_path(data, preset_path): if "include" not in data: data["include"] = [] # Clear the folders that have been deleted - data["include"] = [i for i in data.get("include", []) if os.path.exists(i)] + data["include"] = [i for i in data.get("include", []) + if os.path.exists(os.path.join(output_dir, i))] if preset_path not in data["include"]: data["include"].append(preset_path) return data diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py index 4ee2a78f19a..17ded05c24f 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py +++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py @@ -720,7 +720,7 @@ def test_cmake_presets_multiple_settings_single_config(): assert presets["testPresets"][0]["name"] == "conan-apple-clang-12.0-gnu17-release" assert presets["testPresets"][0]["configurePreset"] == "conan-apple-clang-12.0-gnu17-release" - presets = json.loads(load(user_presets["include"][1])) + presets = json.loads(client.load(user_presets["include"][1])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 @@ -741,7 +741,7 @@ def test_cmake_presets_multiple_settings_single_config(): user_presets = json.loads(load(user_presets_path)) # The [0] is the apple-clang 12 the [1] is the apple-clang 13 assert len(user_presets["include"]) == 3 - presets = json.loads(load(user_presets["include"][2])) + presets = json.loads(client.load(user_presets["include"][2])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 @@ -928,7 +928,7 @@ def test_cmake_presets_multiple_settings_multi_config(): user_presets = json.loads(load(user_presets_path)) # The [0] is the msvc dynamic/14 the [1] is the static/17 assert len(user_presets["include"]) == 2 - presets = json.loads(load(user_presets["include"][1])) + presets = json.loads(client.load(user_presets["include"][1])) assert len(presets["configurePresets"]) == 1 assert len(presets["buildPresets"]) == 1 assert len(presets["testPresets"]) == 1 diff --git a/conans/test/functional/toolchains/test_basic.py b/conans/test/functional/toolchains/test_basic.py index 54fad8c3605..314b44e7907 100644 --- a/conans/test/functional/toolchains/test_basic.py +++ b/conans/test/functional/toolchains/test_basic.py @@ -102,9 +102,7 @@ def build(self): client = TestClient() client.save({"conanfile.py": conanfile}) client.run("build .", assert_error=True) # No CMakeLists.txt - toolchain_path = os.path.join(client.current_folder, - "conan_toolchain.cmake").replace("\\", "/") - self.assertIn('-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolchain_path), client.out) + self.assertIn('-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', client.out) self.assertIn("ERROR: conanfile.py: Error in build() method", client.out) @pytest.mark.tool("visual_studio") From fd9af20baa1641e14477594790d5be88da1756c8 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 5 Apr 2024 11:00:21 +0200 Subject: [PATCH 5/6] fix --- conans/test/functional/toolchains/cmake/test_cmake.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/conans/test/functional/toolchains/cmake/test_cmake.py b/conans/test/functional/toolchains/cmake/test_cmake.py index 4e3dfb7a827..7743cc9464a 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake.py +++ b/conans/test/functional/toolchains/cmake/test_cmake.py @@ -364,10 +364,8 @@ def test_toolchain_linux(self, build_type, cppstd, arch, libcxx, shared): "arch": arch, "build_type": build_type} self._run_build(settings, {"shared": shared}) - toolchain_path = os.path.join(self.client.current_folder, "build", - "conan_toolchain.cmake").replace("\\", "/") self.assertIn('cmake -G "Unix Makefiles" ' - '-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolchain_path), self.client.out) + '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) extensions_str = "ON" if "gnu" in cppstd else "OFF" arch_str = "-m32" if arch == "x86" else "-m64" @@ -424,10 +422,8 @@ def test_toolchain_apple(self, build_type, cppstd, shared): "build_type": build_type} self._run_build(settings, {"shared": shared}) - toolchain_path = os.path.join(self.client.current_folder, "build", - "conan_toolchain.cmake").replace("\\", "/") self.assertIn('cmake -G "Unix Makefiles" ' - '-DCMAKE_TOOLCHAIN_FILE="{}"'.format(toolchain_path), self.client.out) + '-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"', self.client.out) extensions_str = "OFF" if cppstd else "" vals = {"CMAKE_CXX_STANDARD": cppstd, From d788f6c4bb8244ae45cd35ff92a5f29686f02a6a Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 8 Apr 2024 11:06:37 +0200 Subject: [PATCH 6/6] wip --- conan/tools/cmake/presets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 050265c9efc..d50bfdea228 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -288,7 +288,7 @@ def generate(conanfile, preset_path, user_presets_path, preset_prefix, preset_da if inherited_user: _IncludingPresets._clean_user_inherits(data, preset_data) - try: # Make it relative to the build dir if possible + try: # Make it relative to the CMakeUserPresets.json if possible preset_path = os.path.relpath(preset_path, output_dir) except ValueError: pass