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

CMakeDeps. global target: from merging cppinfo to link component targets #11673

Merged
merged 3 commits into from Jul 26, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion conan/tools/cmake/cmakedeps/templates/target_configuration.py
Expand Up @@ -112,7 +112,7 @@ def template(self):
{%- endfor %}



{% if not components_names %}
########## GLOBAL TARGET PROPERTIES {{ configuration }} ########################################
set_property(TARGET {{root_target_name}}
PROPERTY INTERFACE_LINK_LIBRARIES
Expand All @@ -139,6 +139,9 @@ def template(self):
PROPERTY INTERFACE_LINK_DIRECTORIES
$<$<CONFIG:{{configuration}}>:${{'{'}}{{pkg_name}}_LIB_DIRS{{config_suffix}}}> APPEND)
{%- endif %}

{%- else %}

########## COMPONENTS TARGET PROPERTIES {{ configuration }} ########################################

{%- for comp_variable_name, comp_target_name in components_names %}
Expand Down Expand Up @@ -168,6 +171,15 @@ def template(self):
{%- endfor %}


########## AGGREGATED GLOBAL TARGET WITH THE COMPONENTS #####################
{%- for comp_variable_name, comp_target_name in components_names %}

target_link_libraries({{root_target_name}} INTERFACE {{ comp_target_name }})

{%- endfor %}

{%- endif %}

""")

def get_declared_components_targets_names(self):
Expand Down
16 changes: 10 additions & 6 deletions conan/tools/cmake/cmakedeps/templates/target_data.py
Expand Up @@ -49,6 +49,7 @@ def context(self):
package_folder = package_folder.replace('\\', '/').replace('$', '\\$').replace('"', '\\"')

return {"global_cpp": global_cpp,
"has_components": self.conanfile.cpp_info.has_components,
"pkg_name": self.pkg_name,
"file_name": self.file_name,
"package_folder": package_folder,
Expand Down Expand Up @@ -84,6 +85,10 @@ def template(self):
########### VARIABLES #######################################################################
#############################################################################################
set({{ pkg_name }}_PACKAGE_FOLDER{{ config_suffix }} "{{ package_folder }}")
set({{ pkg_name }}_BUILD_MODULES_PATHS{{ config_suffix }} {{ global_cpp.build_modules_paths }})

{% if not has_components %}

set({{ pkg_name }}_INCLUDE_DIRS{{ config_suffix }} {{ global_cpp.include_paths }})
set({{ pkg_name }}_RES_DIRS{{ config_suffix }} {{ global_cpp.res_paths }})
set({{ pkg_name }}_DEFINITIONS{{ config_suffix }} {{ global_cpp.defines }})
Expand All @@ -98,13 +103,11 @@ def template(self):
set({{ pkg_name }}_SYSTEM_LIBS{{ config_suffix }} {{ global_cpp.system_libs }})
set({{ pkg_name }}_FRAMEWORK_DIRS{{ config_suffix }} {{ global_cpp.framework_paths }})
set({{ pkg_name }}_FRAMEWORKS{{ config_suffix }} {{ global_cpp.frameworks }})
set({{ pkg_name }}_BUILD_MODULES_PATHS{{ config_suffix }} {{ global_cpp.build_modules_paths }})
set({{ pkg_name }}_BUILD_DIRS{{ config_suffix }} {{ global_cpp.build_paths }})
{% else %}

set({{ pkg_name }}_COMPONENTS{{ config_suffix }} {{ components_names }})

{%- for comp_variable_name, comp_target_name, cpp in components_cpp %}

########### COMPONENT {{ comp_target_name }} VARIABLES #############################################
set({{ pkg_name }}_{{ comp_variable_name }}_INCLUDE_DIRS{{ config_suffix }} {{ cpp.include_paths }})
set({{ pkg_name }}_{{ comp_variable_name }}_LIB_DIRS{{ config_suffix }} {{ cpp.lib_paths }})
Expand All @@ -126,15 +129,16 @@ def template(self):
$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>{{ ':${' }}{{ pkg_name }}_{{ comp_variable_name }}_SHARED_LINK_FLAGS{{ config_suffix }}}>
$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>{{ ':${' }}{{ pkg_name }}_{{ comp_variable_name }}_EXE_LINK_FLAGS{{ config_suffix }}}>
)
list(APPEND {{ pkg_name }}_BUILD_MODULES_PATHS{{ config_suffix }} {{ cpp.build_modules_paths }})
{%- endfor %}

{%- endif %}
""")
return ret

def _get_global_cpp_cmake(self):
global_cppinfo = self.conanfile.cpp_info.aggregated_components()
pfolder_var_name = "{}_PACKAGE_FOLDER{}".format(self.pkg_name, self.config_suffix)
return _TargetDataContext(global_cppinfo, pfolder_var_name, self.conanfile.package_folder)
return _TargetDataContext(self.conanfile.cpp_info, pfolder_var_name,
self.conanfile.package_folder)

def _get_required_components_cpp(self):
"""Returns a list of (component_name, DepsCppCMake)"""
Expand Down
Expand Up @@ -6,8 +6,7 @@


@pytest.mark.tool_cmake
@pytest.mark.parametrize("use_components", [False, True])
def test_build_modules_alias_target(use_components):
def test_build_modules_alias_target():
client = TestClient()
conanfile = textwrap.dedent("""
import os
Expand All @@ -24,21 +23,13 @@ def package(self):

def package_info(self):
module = os.path.join("share", "cmake", "target-alias.cmake")
{}
self.cpp_info.set_property("cmake_build_modules", [module])
""")
if use_components:
info = """
self.cpp_info.components["comp"].set_property("cmake_build_modules", [module])
"""
else:
info = """
self.cpp_info.set_property("cmake_build_modules", [module])
"""

target_alias = textwrap.dedent("""
add_library(otherhello INTERFACE IMPORTED)
target_link_libraries(otherhello INTERFACE {target_name})
""").format(target_name="namespace::comp" if use_components else "hello::hello")
conanfile = conanfile.format(info)
target_link_libraries(otherhello INTERFACE hello::hello)
""")
client.save({"conanfile.py": conanfile, "target-alias.cmake": target_alias})
client.run("create .")

Expand Down Expand Up @@ -66,20 +57,13 @@ def build(self):
""")
client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
client.run("create .")
if use_components:
assert "otherhello link libraries: namespace::comp" in client.out
else:
assert "otherhello link libraries: hello::hello" in client.out
assert "otherhello link libraries: hello::hello" in client.out


@pytest.mark.tool_cmake
def test_build_modules_components_selection_is_not_possible():
def test_build_modules_components_is_not_possible():
"""
If openssl declares different cmake_build_modules on ssl and crypto, in the consumer both
are included even if the cpp_info of the consumer declares:
def package_info(self):
self.cpp_info.requires = ["openssl::crypto"]
Because that information is defined later, not at "generate" time (building time).
The "cmake_build_module" property declared in the components is useless
"""
client = TestClient()
conanfile = textwrap.dedent("""
Expand All @@ -90,27 +74,19 @@ class Conan(ConanFile):
name = "openssl"
version = "1.0"
settings = "os", "arch", "compiler", "build_type"
exports_sources = ["ssl.cmake", "crypto.cmake", "root.cmake"]
exports_sources = ["crypto.cmake", "root.cmake"]

def package(self):
self.copy("*.cmake", dst="share/cmake")

def package_info(self):
ssl_module = os.path.join("share", "cmake", "ssl.cmake")
self.cpp_info.components["ssl"].set_property("cmake_build_modules", [ssl_module])

crypto_module = os.path.join("share", "cmake", "crypto.cmake")
self.cpp_info.components["crypto"].set_property("cmake_build_modules", [crypto_module])

root_module = os.path.join("share", "cmake", "root.cmake")
self.cpp_info.set_property("cmake_build_modules", [root_module])
""")

ssl_cmake = textwrap.dedent("""
function(ssl_message MESSAGE_OUTPUT)
message("SSL MESSAGE:${ARGV${0}}")
endfunction()
""")
crypto_cmake = textwrap.dedent("""
function(crypto_message MESSAGE_OUTPUT)
message("CRYPTO MESSAGE:${ARGV${0}}")
Expand All @@ -122,7 +98,6 @@ def package_info(self):
endfunction()
""")
client.save({"conanfile.py": conanfile,
"ssl.cmake": ssl_cmake,
"crypto.cmake": crypto_cmake,
"root.cmake": root_cmake})
client.run("create .")
Expand Down Expand Up @@ -151,14 +126,15 @@ def package_info(self):
project(test)
find_package(openssl CONFIG)
crypto_message("hello!")
ssl_message("hello!")
root_message("hello!")
""")
client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
# As we are requiring only "crypto" but it doesn't matter, it is not possible to include
# only crypto build_modules
client.run("create .")
assert "SSL MESSAGE:hello!" in client.out
assert "CRYPTO MESSAGE:hello!" in client.out
assert "ROOT MESSAGE:hello!" in client.out
client.run("create .", assert_error=True)
assert 'Unknown CMake command "crypto_message"' in client.out

# Comment the function call
client.save({"CMakeLists.txt": cmakelists.replace("crypto", "#crypto")})
assert "ROOT MESSAGE:hello!" not in client.out

Expand Up @@ -107,15 +107,22 @@ def package_info(self):
assert """set_property(TARGET hello::say PROPERTY INTERFACE_LINK_LIBRARIES
$<$<CONFIG:Release>:${hello_hello_say_OBJECTS_RELEASE}
${hello_hello_say_LINK_LIBS_RELEASE}> APPEND)""" in content
# If there are componets, there is not a global cpp so this is not generated
assert """set_property(TARGET hello::hello
PROPERTY INTERFACE_LINK_LIBRARIES
$<$<CONFIG:Release>:${hello_OBJECTS_RELEASE}
${hello_LIBRARIES_TARGETS_RELEASE}> APPEND)""" in content
${hello_LIBRARIES_TARGETS_RELEASE}> APPEND)""" not in content
# But the global target is linked with the targets from the components
assert "target_link_libraries(hello::hello INTERFACE hello::say)" in content

with open(os.path.join(client.current_folder, "hello-release-x86_64-data.cmake")) as f:
content = f.read()
assert 'set(hello_OBJECTS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/mycomponent.o")' in content
assert 'set(hello_hello_say_OBJECTS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/mycomponent.o")' in content
# Not global variables
assert 'set(hello_OBJECTS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/mycomponent.o")' \
not in content
# But component variables
assert 'set(hello_hello_say_OBJECTS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/' \
'mycomponent.o")' in content


def test_cpp_info_component_error_aggregate():
Expand Down
12 changes: 7 additions & 5 deletions conans/test/unittests/tools/cmake/test_cmakedeps.py
Expand Up @@ -61,8 +61,8 @@ def test_cpp_info_name_cmakedeps_components():
conanfile.settings.arch = "x64"

cpp_info = CppInfo("mypkg", "dummy_root_folder1")
cpp_info.set_property("cmake_target_name", "GlobakPkgName1::GlobakPkgName1")
cpp_info.components["mycomp"].set_property("cmake_target_name", "GlobakPkgName1::MySuperPkg1")
cpp_info.set_property("cmake_target_name", "GlobalPkgName1::GlobalPkgName1")
cpp_info.components["mycomp"].set_property("cmake_target_name", "GlobalPkgName1::MySuperPkg1")
cpp_info.set_property("cmake_file_name", "ComplexFileName1")

conanfile_dep = ConanFile(Mock(), None)
Expand All @@ -81,11 +81,13 @@ def test_cpp_info_name_cmakedeps_components():

cmakedeps = CMakeDeps(conanfile)
files = cmakedeps.content
assert "TARGET GlobakPkgName1::MySuperPkg1" in files["ComplexFileName1-Target-debug.cmake"]
assert "TARGET GlobalPkgName1::MySuperPkg1" in files["ComplexFileName1-Target-debug.cmake"]
# No global variables for the packages
assert 'set(OriginalDepName_INCLUDE_DIRS_DEBUG ' \
'"${OriginalDepName_PACKAGE_FOLDER_DEBUG}/include")' \
in files["ComplexFileName1-debug-x64-data.cmake"]
assert 'set(OriginalDepName_GlobakPkgName1_MySuperPkg1_INCLUDE_DIRS_DEBUG ' \
not in files["ComplexFileName1-debug-x64-data.cmake"]
# But components
assert 'set(OriginalDepName_GlobalPkgName1_MySuperPkg1_INCLUDE_DIRS_DEBUG ' \
'"${OriginalDepName_PACKAGE_FOLDER_DEBUG}/include")' \
in files["ComplexFileName1-debug-x64-data.cmake"]

Expand Down