Skip to content

Commit

Permalink
Fix relativization of paths in CMake generators (#16316)
Browse files Browse the repository at this point in the history
* fix relativize paths in generated files

* wip

* wip

* more paths relative
  • Loading branch information
memsharded authored May 28, 2024
1 parent 7771c1b commit 87e586d
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 24 deletions.
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 @@ -868,6 +878,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 @@ -991,6 +1002,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

0 comments on commit 87e586d

Please sign in to comment.