Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix relativization of paths in CMake generators #16316

Merged
merged 6 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions conan/tools/cmake/cmakedeps/cmakedeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from conan.tools.cmake.cmakedeps.templates.target_data import ConfigDataTemplate
from conan.tools.cmake.cmakedeps.templates.targets import TargetsTemplate
from conan.tools.files import save
from conans.client.generators import relativize_generated_file
from conan.errors import ConanException
from conans.model.dependencies import get_transitive_requires

Expand Down Expand Up @@ -120,8 +119,7 @@ def _generate_files(self, require, dep, ret, find_module_mode):
ret[config_version.filename] = config_version.render()

data_target = ConfigDataTemplate(self, require, dep, find_module_mode)
data_content = relativize_generated_file(data_target.render(), self._conanfile,
"${CMAKE_CURRENT_LIST_DIR}")
data_content = data_target.render()
ret[data_target.filename] = data_content

target_configuration = TargetConfigurationTemplate(self, require, dep, find_module_mode)
Expand Down
5 changes: 4 additions & 1 deletion conan/tools/cmake/cmakedeps/templates/target_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
FIND_MODE_BOTH
from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate
from conan.errors import ConanException

from conans.client.generators import relativize_path

"""

Expand Down Expand Up @@ -57,6 +57,9 @@ def context(self):
# Make the root_folder relative to the generated xxx-data.cmake file
root_folder = self._root_folder
root_folder = root_folder.replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
# it is the relative path of the caller, not the dependency
root_folder = relativize_path(root_folder, self.cmakedeps._conanfile,
"${CMAKE_CURRENT_LIST_DIR}")

return {"global_cpp": global_cpp,
"has_components": self.conanfile.cpp_info.has_components,
Expand Down
32 changes: 23 additions & 9 deletions conan/tools/cmake/toolchain/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from conan.tools.cmake.utils import is_multi_configuration
from conan.tools.intel import IntelCC
from conan.tools.microsoft.visual import msvc_version_to_toolset_version
from conans.client.generators import relativize_path
from conans.client.subsystems import deduce_subsystem, WINDOWS
from conan.errors import ConanException
from conans.util.files import load
Expand Down Expand Up @@ -146,8 +147,9 @@ def context(self):
bin_dirs = [p for dep in host_deps for p in dep.cpp_info.aggregated_components().bindirs]
test_bindirs = [p for dep in test_deps for p in dep.cpp_info.aggregated_components().bindirs]
bin_dirs.extend(test_bindirs)
bin_dirs = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
for p in bin_dirs]
bin_dirs = [p.replace("\\", "/") for p in bin_dirs]

bin_dirs = ";".join(bin_dirs) if bin_dirs else None
if bin_dirs:
config_dict[build_type] = bin_dirs
Expand Down Expand Up @@ -238,6 +240,8 @@ def context(self):
if not linker_scripts:
return
linker_scripts = [linker_script.replace('\\', '/') for linker_script in linker_scripts]
linker_scripts = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
for p in linker_scripts]
linker_script_flags = ['-T"' + linker_script + '"' for linker_script in linker_scripts]
return {"linker_script_flags": " ".join(linker_script_flags)}

Expand Down Expand Up @@ -324,6 +328,8 @@ def context(self):
if not android_ndk_path:
raise ConanException('CMakeToolchain needs tools.android:ndk_path configuration defined')
android_ndk_path = android_ndk_path.replace("\\", "/")
android_ndk_path = relativize_path(android_ndk_path, self._conanfile,
"${CMAKE_CURRENT_LIST_DIR}")

use_cmake_legacy_toolchain = self._conanfile.conf.get("tools.android:cmake_legacy_toolchain",
check_type=bool)
Expand Down Expand Up @@ -430,6 +436,8 @@ def to_apple_archs(conanfile):
"enable_visibility": enable_visibility
}
if host_sdk_name:
host_sdk_name = relativize_path(host_sdk_name, self._conanfile,
"${CMAKE_CURRENT_LIST_DIR}")
ctxt_toolchain["cmake_osx_sysroot"] = host_sdk_name
# this is used to initialize the OSX_ARCHITECTURES property on each target as it is created
if host_architecture:
Expand Down Expand Up @@ -527,23 +535,22 @@ def _get_host_runtime_dirs(self, host_req):
host_runtime_dirs = {}
for k, v in matches:
host_runtime_dirs.setdefault(k, []).append(v)

# Calculate the dirs for the current build_type
runtime_dirs = []
for req in host_req:
cppinfo = req.cpp_info.aggregated_components()
runtime_dirs.extend(cppinfo.bindirs if is_win else cppinfo.libdirs)

build_type = settings.get_safe("build_type")
host_runtime_dirs[build_type] = [s.replace("\\", "/") for s in runtime_dirs]

return host_runtime_dirs

@staticmethod
def _join_paths(paths):
return " ".join(['"{}"'.format(p.replace('\\', '/')
.replace('$', '\\$')
.replace('"', '\\"')) for p in paths])
def _join_paths(self, paths):
paths = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}") for p in paths]
paths = [p.replace('\\', '/').replace('$', '\\$').replace('"', '\\"') for p in paths]
return " ".join([f'"{p}"' for p in paths])

def context(self):
# To find the generated cmake_find_package finders
Expand Down Expand Up @@ -630,7 +637,10 @@ def context(self):
# This is global [conf] injection of extra toolchain files
user_toolchain = self._conanfile.conf.get("tools.cmake.cmaketoolchain:user_toolchain",
default=[], check_type=list)
return {"paths": [ut.replace("\\", "/") for ut in user_toolchain]}
paths = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
for p in user_toolchain]
paths = [p.replace("\\", "/") for p in paths]
return {"paths": paths}


class ExtraFlagsBlock(Block):
Expand Down Expand Up @@ -867,6 +877,7 @@ def get_toolset(generator, conanfile):
toolset = toolset_arch if toolset is None else "{},{}".format(toolset, toolset_arch)
toolset_cuda = conanfile.conf.get("tools.cmake.cmaketoolchain:toolset_cuda")
if toolset_cuda is not None:
toolset_cuda = relativize_path(toolset_cuda, conanfile, "${CMAKE_CURRENT_LIST_DIR}")
toolset_cuda = f"cuda={toolset_cuda}"
toolset = toolset_cuda if toolset is None else f"{toolset},{toolset_cuda}"
return toolset
Expand Down Expand Up @@ -990,6 +1001,9 @@ def context(self):
# This is handled by the tools.apple:sdk_path and CMAKE_OSX_SYSROOT in Apple
cmake_sysroot = self._conanfile.conf.get("tools.build:sysroot")
cmake_sysroot = cmake_sysroot.replace("\\", "/") if cmake_sysroot is not None else None
if cmake_sysroot is not None:
cmake_sysroot = relativize_path(cmake_sysroot, self._conanfile,
"${CMAKE_CURRENT_LIST_DIR}")

result = self._get_winsdk_version(system_version, generator_platform)
system_version, winsdk_version, gen_platform_sdk_version = result
Expand Down
2 changes: 0 additions & 2 deletions conan/tools/cmake/toolchain/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from conan.tools.intel import IntelCC
from conan.tools.microsoft import VCVars
from conan.tools.microsoft.visual import vs_ide_version
from conans.client.generators import relativize_generated_file
from conan.errors import ConanException
from conans.model.options import _PackageOption
from conans.util.files import save
Expand Down Expand Up @@ -202,7 +201,6 @@ def content(self):
context = self._context()
content = Template(self._template, trim_blocks=True, lstrip_blocks=True,
keep_trailing_newline=True).render(**context)
content = relativize_generated_file(content, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
return content

@property
Expand Down
23 changes: 14 additions & 9 deletions conans/client/generators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,6 @@ def ps1_content(files):
conanfile.output.info(f"Generated aggregated env files: {generated}")


def relativize_generated_file(content, conanfile, placeholder):
abs_base_path, new_path = relativize_paths(conanfile, placeholder)
if abs_base_path is None:
return content
content = content.replace(abs_base_path, new_path)
content = content.replace(abs_base_path.replace("\\", "/"), new_path.replace("\\", "/"))
return content


def relativize_paths(conanfile, placeholder):
abs_base_path = conanfile.folders._base_generators
if not abs_base_path or not os.path.isabs(abs_base_path):
Expand All @@ -229,3 +220,17 @@ def relativize_paths(conanfile, placeholder):
new_path = placeholder if rel_path == "." else os.path.join(placeholder, rel_path)
new_path = os.path.join(new_path, "") # For the trailing / to dissambiguate matches
return abs_base_path, new_path


def relativize_path(path, conanfile, placeholder):
abs_base_path, new_path = relativize_paths(conanfile, placeholder)
if abs_base_path is None:
return path
if path.startswith(abs_base_path):
path = path.replace(abs_base_path, new_path, 1)
else:
abs_base_path = abs_base_path.replace("\\", "/")
new_path = new_path.replace("\\", "/")
if path.startswith(abs_base_path):
path = path.replace(abs_base_path, new_path, 1)
return path