forked from conan-io/conan
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Non-intrusive integration with CMake (conan-io#2875)
* mac passing * Fixed runtime windows * Tested priority * fixed zlib find test * Fixed test and added interface_compile_definitions * Removed priority of the cmake install folder from the install_folder * Fixed test, added _LIBS var * PENDING WORK TO MAKE IT TRANSITIVE * Transitive targets * Removed msg * Force CI * Automatic module path * Add new priorize test * Fixed test * Replace * Fixed win
- Loading branch information
Showing
7 changed files
with
450 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from conans.client.generators.cmake import DepsCppCmake | ||
from conans.model import Generator | ||
|
||
|
||
generic_find_package_template = """ | ||
message(STATUS "Conan: Using autogenerated Find{name}.cmake") | ||
# Global approach | ||
SET({name}_FOUND 1) | ||
SET({name}_INCLUDE_DIRS {deps.include_paths}) | ||
SET({name}_INCLUDES {deps.include_paths}) | ||
SET({name}_DEFINITIONS {deps.defines}) | ||
SET({name}_LIBRARIES "") # Will be filled later | ||
SET({name}_LIBRARIES_TARGETS "") # Will be filled later, if CMake 3 | ||
SET({name}_LIBS "") # Same as {name}_LIBRARIES | ||
mark_as_advanced({name}_FOUND {name}_INCLUDE_DIRS {name}_INCLUDES | ||
{name}_DEFINITIONS {name}_LIBRARIES {name}_LIBS) | ||
# Find the real .lib/.a and add them to {name}_LIBS and {name}_LIBRARY_LIST | ||
SET({name}_LIBRARY_LIST {deps.libs}) | ||
SET({name}_LIB_DIRS {deps.lib_paths}) | ||
foreach(_LIBRARY_NAME ${{{name}_LIBRARY_LIST}}) | ||
unset(CONAN_FOUND_LIBRARY CACHE) | ||
find_library(CONAN_FOUND_LIBRARY NAME ${{_LIBRARY_NAME}} PATHS ${{{name}_LIB_DIRS}} | ||
NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) | ||
if(CONAN_FOUND_LIBRARY) | ||
if(${{CMAKE_VERSION}} VERSION_LESS "3.0") | ||
list(APPEND {name}_LIBRARIES ${{CONAN_FOUND_LIBRARY}}) | ||
else() # Create a micro-target for each lib/a found | ||
set(_LIB_NAME CONAN_LIB::{name}_${{_LIBRARY_NAME}}) | ||
add_library(${{_LIB_NAME}} UNKNOWN IMPORTED) | ||
set_target_properties(${{_LIB_NAME}} PROPERTIES IMPORTED_LOCATION ${{CONAN_FOUND_LIBRARY}}) | ||
list(APPEND {name}_LIBRARIES_TARGETS ${{_LIB_NAME}}) | ||
endif() | ||
message(STATUS "Found: ${{CONAN_FOUND_LIBRARY}}") | ||
else() | ||
message(STATUS "Library ${{_LIBRARY_NAME}} not found in package, might be system one") | ||
endif() | ||
endforeach() | ||
set({name}_LIBS ${{{name}_LIBRARIES}}) | ||
if(NOT ${{CMAKE_VERSION}} VERSION_LESS "3.0") | ||
# Target approach | ||
if(NOT TARGET {name}::{name}) | ||
add_library({name}::{name} INTERFACE IMPORTED) | ||
if({name}_INCLUDE_DIRS) | ||
set_target_properties({name}::{name} PROPERTIES | ||
INTERFACE_INCLUDE_DIRECTORIES "${{{name}_INCLUDE_DIRS}}") | ||
endif() | ||
set_property(TARGET {name}::{name} PROPERTY INTERFACE_LINK_LIBRARIES ${{{name}_LIBRARIES_TARGETS}}) | ||
set_property(TARGET {name}::{name} PROPERTY INTERFACE_COMPILE_DEFINITIONS {deps.defines}) | ||
endif() | ||
{find_dependencies} | ||
endif() | ||
""" | ||
|
||
|
||
class CMakeFindPackageGenerator(Generator): | ||
|
||
@property | ||
def filename(self): | ||
pass | ||
|
||
@property | ||
def content(self): | ||
ret = {} | ||
for depname, cpp_info in self.deps_build_info.dependencies: | ||
ret["Find%s.cmake" % depname] = self._single_find_package(depname, cpp_info) | ||
return ret | ||
|
||
@staticmethod | ||
def _single_find_package(name, cpp_info): | ||
deps = DepsCppCmake(cpp_info) | ||
lines = [] | ||
if cpp_info.public_deps: | ||
lines = CMakeFindPackageGenerator._transitive_lines(name, cpp_info) | ||
tmp = generic_find_package_template.format(name=name, deps=deps, | ||
find_dependencies="\n".join(lines)) | ||
return tmp | ||
|
||
@staticmethod | ||
def _transitive_lines(name, cpp_info): | ||
lines = ["# Library dependencies", "include(CMakeFindDependencyMacro)"] | ||
for dep in cpp_info.public_deps: | ||
def property_lines(prop): | ||
lib_t = "%s::%s" % (name, name) | ||
dep_t = "%s::%s" % (dep, dep) | ||
return ["get_target_property(tmp %s %s)" % (dep_t, prop), | ||
"if(tmp)", | ||
" set_property(TARGET %s APPEND PROPERTY %s ${tmp})" % (lib_t, prop), | ||
' message("${tmp}")', | ||
'endif()'] | ||
|
||
lines.append("find_dependency(%s REQUIRED)" % dep) | ||
lines.extend(property_lines("INTERFACE_LINK_LIBRARIES")) | ||
lines.extend(property_lines("INTERFACE_COMPILE_DEFINITIONS")) | ||
lines.extend(property_lines("INTERFACE_INCLUDE_DIRECTORIES")) | ||
return lines |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from conans.client.generators.cmake import DepsCppCmake | ||
from conans.model import Generator | ||
|
||
|
||
class CMakePathsGenerator(Generator): | ||
|
||
@property | ||
def filename(self): | ||
return "conan_paths.cmake" | ||
|
||
@property | ||
def content(self): | ||
deps = DepsCppCmake(self.deps_build_info) | ||
# We want to prioritize the FindXXX.cmake files: | ||
# 1. First the files found in the packages | ||
# 2. The previously set (by default CMAKE_MODULE_PATH is empty) | ||
# 3. The "install_folder" ones, in case there is no FindXXX.cmake, try with the install dir | ||
# if the user used the "cmake_find_package" will find the auto-generated | ||
# 4. The CMake installation dir/Modules ones. | ||
return """set(CMAKE_MODULE_PATH {deps.build_paths} ${{CMAKE_MODULE_PATH}} ${{CMAKE_CURRENT_LIST_DIR}}) | ||
set(CMAKE_PREFIX_PATH {deps.build_paths} ${{CMAKE_PREFIX_PATH}} ${{CMAKE_CURRENT_LIST_DIR}}) | ||
""".format(deps=deps) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import unittest | ||
from conans.test.utils.cpp_test_files import cpp_hello_conan_files | ||
from conans.test.utils.tools import TestClient | ||
from nose.plugins.attrib import attr | ||
|
||
|
||
@attr('slow') | ||
class CMakeFindPathGeneratorTest(unittest.TestCase): | ||
|
||
def cmake_find_package_test(self): | ||
"""First package without custom find_package""" | ||
client = TestClient() | ||
files = cpp_hello_conan_files(name="Hello0", | ||
settings='"os", "compiler", "arch", "build_type"') | ||
client.save(files) | ||
client.run("create . user/channel -s build_type=Release") | ||
|
||
# Consume the previous Hello0 with auto generated FindHello0.cmake | ||
# The module path will point to the "install" folder automatically (CMake helper) | ||
files = cpp_hello_conan_files(name="Hello1", deps=["Hello0/0.1@user/channel"], | ||
settings='"os", "compiler", "arch", "build_type"') | ||
files["conanfile.py"] = files["conanfile.py"].replace( | ||
'generators = "cmake", "gcc"', | ||
'generators = "cmake_find_package"') | ||
files["CMakeLists.txt"] = """ | ||
set(CMAKE_CXX_COMPILER_WORKS 1) | ||
set(CMAKE_CXX_ABI_COMPILED 1) | ||
project(MyHello CXX) | ||
cmake_minimum_required(VERSION 2.8) | ||
find_package(Hello0 REQUIRED) | ||
add_library(helloHello1 hello.cpp) | ||
target_link_libraries(helloHello1 PUBLIC Hello0::Hello0) | ||
add_executable(say_hello main.cpp) | ||
target_link_libraries(say_hello helloHello1) | ||
""" | ||
client.save(files, clean_first=True) | ||
client.run("create . user/channel -s build_type=Release") | ||
self.assertIn("Conan: Using autogenerated FindHello0.cmake", client.out) | ||
|
||
# Now link with old cmake | ||
files["CMakeLists.txt"] = """ | ||
set(CMAKE_VERSION "2.8") | ||
set(CMAKE_CXX_COMPILER_WORKS 1) | ||
set(CMAKE_CXX_ABI_COMPILED 1) | ||
project(MyHello CXX) | ||
cmake_minimum_required(VERSION 2.8) | ||
message(${CMAKE_BINARY_DIR}) | ||
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) | ||
find_package(Hello0 REQUIRED) | ||
add_library(helloHello1 hello.cpp) | ||
if(NOT DEFINED Hello0_FOUND) | ||
message(FATAL_ERROR "Hello0_FOUND not declared") | ||
endif() | ||
if(NOT DEFINED Hello0_INCLUDE_DIRS) | ||
message(FATAL_ERROR "Hello0_INCLUDE_DIRS not declared") | ||
endif() | ||
if(NOT DEFINED Hello0_INCLUDES) | ||
message(FATAL_ERROR "Hello0_INCLUDES not declared") | ||
endif() | ||
if(NOT DEFINED Hello0_LIBRARIES) | ||
message(FATAL_ERROR "Hello0_LIBRARIES not declared") | ||
endif() | ||
include_directories(${Hello0_INCLUDE_DIRS}) | ||
target_link_libraries(helloHello1 PUBLIC ${Hello0_LIBS}) | ||
add_executable(say_hello main.cpp) | ||
target_link_libraries(say_hello helloHello1) | ||
""" | ||
client.save(files, clean_first=True) | ||
client.run("create . user/channel -s build_type=Release") | ||
self.assertIn("Conan: Using autogenerated FindHello0.cmake", client.out) | ||
|
||
# Now a transitive consumer, but the consumer only find_package the first level Hello1 | ||
files = cpp_hello_conan_files(name="Hello2", deps=["Hello1/0.1@user/channel"], | ||
settings='"os", "compiler", "arch", "build_type"') | ||
files["CMakeLists.txt"] = """ | ||
set(CMAKE_CXX_COMPILER_WORKS 1) | ||
set(CMAKE_CXX_ABI_COMPILED 1) | ||
project(MyHello CXX) | ||
cmake_minimum_required(VERSION 2.8) | ||
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH}) | ||
find_package(Hello1 REQUIRED) # We don't need to find Hello0, it is transitive | ||
add_library(helloHello2 hello.cpp) | ||
target_link_libraries(helloHello2 PUBLIC Hello1::Hello1) | ||
add_executable(say_hello main.cpp) | ||
target_link_libraries(say_hello helloHello2) | ||
""" | ||
files["conanfile.py"] = files["conanfile.py"].replace( | ||
'generators = "cmake", "gcc"', | ||
'generators = "cmake_find_package"') | ||
client.save(files, clean_first=True) | ||
client.run("create . user/channel -s build_type=Release") | ||
self.assertIn("Conan: Using autogenerated FindHello0.cmake", client.out) | ||
self.assertIn("Conan: Using autogenerated FindHello1.cmake", client.out) |
Oops, something went wrong.