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

feat: Add CONAN_RUNTIME_LIB_DIRS to the conan_toolchain.cmake #15914

Merged
merged 20 commits into from May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions conan/tools/cmake/toolchain/blocks.py
Expand Up @@ -480,6 +480,9 @@ class FindFiles(Block):
{% if cmake_include_path %}
list(PREPEND CMAKE_INCLUDE_PATH {{ cmake_include_path }})
{% endif %}
{% if host_runtime_dirs %}
list(PREPEND CONAN_RUNTIME_LIB_DIRS {{ host_runtime_dirs }} )
{% endif %}

{% if cross_building %}
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE OR CMAKE_FIND_ROOT_PATH_MODE_PACKAGE STREQUAL "ONLY")
Expand All @@ -502,6 +505,36 @@ class FindFiles(Block):
{% endif %}
""")

@staticmethod
def _multiconfig_generator(prop):
return ''.join(f'$<$<CONFIG:{c}>:{v}>' for c, v in prop.items())

def _get_host_runtime_dirs_mc(self, host_req):
settings = self._conanfile.settings
host_runtime_dirs = {}
is_win = self._conanfile.settings.get_safe("os") == "Windows"

# Get the previous configuration
if os.path.exists(CONAN_TOOLCHAIN_FILENAME):
jcar87 marked this conversation as resolved.
Show resolved Hide resolved
existing_include = load(CONAN_TOOLCHAIN_FILENAME)
pattern_lib_dris = r"list\(PREPEND CONAN_RUNTIME_LIB_DIRS ([^)]*)\)"
jcar87 marked this conversation as resolved.
Show resolved Hide resolved
msvc_runtime_value = re.search(pattern_lib_dris, existing_include)
jcar87 marked this conversation as resolved.
Show resolved Hide resolved
if msvc_runtime_value:
capture = msvc_runtime_value.group(1)
matches = re.findall(r"\$<\$<CONFIG:(.*)>:(.*)>", capture)
host_runtime_dirs = dict(matches)
build_type = settings.get_safe("build_type")

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

host_runtime_dirs[build_type] = self._join_paths(build_type_runtime_dirs)

return host_runtime_dirs

@staticmethod
def _join_paths(paths):
return " ".join(['"{}"'.format(p.replace('\\', '/')
Expand All @@ -524,6 +557,7 @@ def context(self):
host_req = self._conanfile.dependencies.filter({"build": False}).values()
build_paths = []
host_lib_paths = []
host_runtime_dirs = self._get_host_runtime_dirs_mc(host_req)
host_framework_paths = []
host_include_paths = []
for req in host_req:
Expand Down Expand Up @@ -552,6 +586,7 @@ def context(self):
"cmake_include_path": self._join_paths(host_include_paths),
"is_apple": is_apple_,
"cross_building": cross_building(self._conanfile),
"host_runtime_dirs": self._multiconfig_generator(host_runtime_dirs)
}


Expand Down
Expand Up @@ -132,20 +132,20 @@ def requirements(self):
client.run("install consumer --lockfile=consumer.lock -s os=Windows -s:b os=Windows")
assert "REV1!!!" in client.out
assert "REV2!!!" not in client.out
assert "nix" not in client.out
assert "nix/0.1" not in client.out
client.run("install consumer -s os=Windows -s:b os=Windows")
assert "REV2!!!" in client.out
assert "REV1!!!" not in client.out
assert "nix" not in client.out
assert "nix/0.1" not in client.out

client.run("install consumer --lockfile=consumer.lock -s os=Linux -s:b os=Linux")
assert "REV1!!!" in client.out
assert "REV2!!!" not in client.out
assert "win" not in client.out
assert "win/0.1" not in client.out
client.run("install consumer -s os=Linux -s:b os=Linux")
assert "REV2!!!" in client.out
assert "REV1!!!" not in client.out
assert "win" not in client.out
assert "win/0.1" not in client.out


@pytest.mark.parametrize("requires", ["requires", "tool_requires"])
Expand Down
62 changes: 62 additions & 0 deletions conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -1,6 +1,7 @@
import json
import os
import platform
import re
import textwrap

import pytest
Expand Down Expand Up @@ -352,6 +353,67 @@ def generate(self):
assert "/path/to/builddir" in contents


@pytest.fixture
def lib_dir_setup():
client = TestClient()
conanfile = textwrap.dedent("""
from conan import ConanFile

class Conan(ConanFile):

def package_info(self):
self.cpp_info.builddirs = ["/path/to/builddir"]
""")
client.save({"conanfile.py": conanfile})
client.run("create . --name=dep --version=1.0")

conanfile = (GenConanfile().with_requires("dep/1.0").with_generator("CMakeToolchain")
.with_settings("os", "arch", "compiler", "build_type"))

client.save({"conanfile.py": conanfile})
client.run("install . -s build_type=Release")
return client


@pytest.mark.skipif(platform.system() != "Windows", reason="Only Windows")
def test_lib_dirs_windows(lib_dir_setup):
jcar87 marked this conversation as resolved.
Show resolved Hide resolved
client = lib_dir_setup

contents = client.load("conan_toolchain.cmake")
pattern_lib_path = r'list\(PREPEND CMAKE_LIBRARY_PATH "(.*)"\)'
pattern_lib_dirs = r'PREPEND CONAN_RUNTIME_LIB_DIRS \$<\$<CONFIG:Release>:"(.*)">'
lib_path_group = re.search(pattern_lib_path, contents).groups()
lib_dirs_group = re.search(pattern_lib_dirs, contents).groups()

assert len(lib_path_group) == len(lib_dirs_group)
assert all(lib_dir[-3:] == "bin" for lib_dir in lib_dirs_group)


@pytest.mark.skipif(platform.system() == "Windows", reason="Only Linux and OSX")
def test_lib_dirs_no_windows(lib_dir_setup):
client = lib_dir_setup

contents = client.load("conan_toolchain.cmake")
pattern_lib_path = r'list\(PREPEND CMAKE_LIBRARY_PATH "(.*)"\)'
pattern_lib_dirs = r'PREPEND CONAN_RUNTIME_LIB_DIRS \$<\$<CONFIG:Release>:"(.*)">'
lib_path = re.search(pattern_lib_path, contents).group(1)
lib_dirs = re.search(pattern_lib_dirs, contents).group(1)

assert lib_path == lib_dirs


def test_lib_dirs_multiconf(lib_dir_setup):
client = lib_dir_setup
client.run("install . -s build_type=Debug")

contents = client.load("conan_toolchain.cmake")
pattern_lib_dris = r"list\(PREPEND CONAN_RUNTIME_LIB_DIRS ([^)]*)\)"
msvc_runtime_value = re.search(pattern_lib_dris, contents).group(1)

assert "<CONFIG:Release>" in msvc_runtime_value
assert "<CONFIG:Debug>" in msvc_runtime_value


@pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
def test_cmaketoolchain_cmake_system_processor_cross_apple():
"""
Expand Down