Skip to content

Commit

Permalink
Add build_modules to cpp_info and manage CMake modules (#5940)
Browse files Browse the repository at this point in the history
* Add build_modules to cpp_info and manage CMake modules

* Add CMAKE_MODULE_PATH and CMAKE_PREFIX_PATH

* cleaned code, moved and completed test

* test for find package generator

* add includes to cmake generator and more tests

* support multi generators

* Support cmake_find_package_multi and improve cmake_find_package

* fix test

* set CONAN_BUILD_MODULES_PATHS

* cmake macro

* store paths in cmake variables

* fix extend and add mock for filter_empty

* fix test

* remove not used function

* Filter not cmake modules

* _filter_file_paths

* fix cmake_find_package_multi

* remove message

* remove append and join

* fixes

* do not filter build modules
  • Loading branch information
danimtb authored and lasote committed Oct 30, 2019
1 parent 9b6028e commit 7482b02
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 6 deletions.
2 changes: 2 additions & 0 deletions conans/client/generators/cmake.py
Expand Up @@ -65,6 +65,8 @@ def join_defines(values, prefix=""):
self.exelinkflags_list = join_flags(";", cpp_info.exelinkflags)

self.rootpath = join_paths([cpp_info.rootpath])
self.build_modules_paths = join_paths([path for path in cpp_info.build_modules_paths if
path.endswith(".cmake")])


class CMakeGenerator(Generator):
Expand Down
21 changes: 21 additions & 0 deletions conans/client/generators/cmake_common.py
Expand Up @@ -10,6 +10,7 @@
set(CONAN_PKG_LIBS_{dep}{build_type} {deps.libs})
set(CONAN_SYSTEM_LIBS_{dep}{build_type} {deps.system_libs})
set(CONAN_DEFINES_{dep}{build_type} {deps.defines})
set(CONAN_BUILD_MODULES_PATHS_{dep}{build_type} {deps.build_modules_paths})
# COMPILE_DEFINITIONS are equal to CONAN_DEFINES without -D, for targets
set(CONAN_COMPILE_DEFINITIONS_{dep}{build_type} {deps.compile_definitions})
Expand Down Expand Up @@ -88,6 +89,7 @@ def cmake_dependencies(dependencies, build_type=""):
set(CONAN_LIBS{build_type} {deps.libs_system_frameworks} ${{CONAN_LIBS{build_type}}})
set(CONAN_SYSTEM_LIBS{build_type} {deps.system_libs} ${{CONAN_SYSTEM_LIBS{build_type}}})
set(CONAN_DEFINES{build_type} {deps.defines} ${{CONAN_DEFINES{build_type}}})
set(CONAN_BUILD_MODULES_PATHS{build_type} {deps.build_modules_paths} ${{CONAN_BUILD_MODULES_PATHS{build_type}}})
set(CONAN_CMAKE_MODULE_PATH{build_type} {deps.build_paths} ${{CONAN_CMAKE_MODULE_PATH{build_type}}})
set(CONAN_CXX_FLAGS{build_type} "{deps.cxxflags} ${{CONAN_CXX_FLAGS{build_type}}}")
Expand Down Expand Up @@ -555,6 +557,24 @@ def generate_targets_section(dependencies):
endforeach()
endif()
endmacro()
macro(conan_include_build_modules)
if(CMAKE_BUILD_TYPE)
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_DEBUG} ${CONAN_BUILD_MODULES_PATHS})
elseif(${CMAKE_BUILD_TYPE} MATCHES "Release")
set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_RELEASE} ${CONAN_BUILD_MODULES_PATHS})
elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo")
set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_RELWITHDEBINFO} ${CONAN_BUILD_MODULES_PATHS})
elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel")
set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_MINSIZEREL} ${CONAN_BUILD_MODULES_PATHS})
endif()
endif()
foreach(_BUILD_MODULE_PATH ${CONAN_BUILD_MODULES_PATHS})
include(${_BUILD_MODULE_PATH})
endforeach()
endmacro()
"""


Expand Down Expand Up @@ -616,6 +636,7 @@ def _conan_basic_setup_common(addtional_macros, cmake_multi=False):
conan_set_libcxx()
conan_set_vs_runtime()
conan_set_find_paths()
conan_include_build_modules()
%%INVOKE_MACROS%%
endmacro()
"""
Expand Down
8 changes: 8 additions & 0 deletions conans/client/generators/cmake_find_package_common.py
Expand Up @@ -9,6 +9,7 @@
set({name}_LIBRARIES{build_type_suffix} "") # Will be filled later
set({name}_LIBS{build_type_suffix} "") # Same as {name}_LIBRARIES
set({name}_SYSTEM_LIBS{build_type_suffix} {deps.system_libs})
set({name}_BUILD_MODULES_PATHS{build_type_suffix} {deps.build_modules_paths})
{deps.find_frameworks}
Expand Down Expand Up @@ -51,4 +52,11 @@
endif()
endforeach()
set({name}_LIBS{build_type_suffix} ${{{name}_LIBRARIES{build_type_suffix}}})
set(CMAKE_MODULE_PATH {deps.build_paths} ${{CMAKE_MODULE_PATH}})
set(CMAKE_PREFIX_PATH {deps.build_paths} ${{CMAKE_PREFIX_PATH}})
foreach(_BUILD_MODULE_PATH ${{{name}_BUILD_MODULES_PATHS{build_type_suffix}}})
include(${{_BUILD_MODULE_PATH}})
endforeach()
"""
3 changes: 1 addition & 2 deletions conans/client/generators/cmake_find_package_multi.py
Expand Up @@ -74,10 +74,10 @@ def content(self):
depname = cpp_info.name
deps = DepsCppCmake(cpp_info)
ret["{}Config.cmake".format(depname)] = self._find_for_dep(depname, cpp_info)
ret["{}Targets.cmake".format(depname)] = self.targets_file.format(name=depname)

find_lib = target_template.format(name=depname, deps=deps,
build_type_suffix=build_type_suffix)
ret["{}Targets.cmake".format(depname)] = self.targets_file.format(name=depname)
ret["{}Target-{}.cmake".format(depname, build_type.lower())] = find_lib
return ret

Expand All @@ -97,5 +97,4 @@ def _find_for_dep(self, name, cpp_info):
version=cpp_info.version,
find_dependencies_block="\n".join(lines),
target_props_block=targets_props)

return tmp
1 change: 1 addition & 0 deletions conans/client/generators/cmake_multi.py
Expand Up @@ -27,6 +27,7 @@ def add_lists(seq1, seq2):
result.sharedlinkflags = cpp_info.sharedlinkflags + config_info.sharedlinkflags
result.exelinkflags = cpp_info.exelinkflags + config_info.exelinkflags
result.system_libs = add_lists(cpp_info.system_libs, config_info.system_libs)
result.build_modules = add_lists(cpp_info.build_modules, config_info.build_modules)
return result
return cpp_info

Expand Down
14 changes: 14 additions & 0 deletions conans/model/build_info.py
Expand Up @@ -35,8 +35,10 @@ def __init__(self):
self.cxxflags = [] # C++ compilation flags
self.sharedlinkflags = [] # linker flags
self.exelinkflags = [] # linker flags
self.build_modules = []
self.rootpath = ""
self.sysroot = ""
self._build_modules_paths = None
self._include_paths = None
self._lib_paths = None
self._bin_paths = None
Expand All @@ -57,6 +59,13 @@ def _filter_paths(self, paths):
else:
return abs_paths

@property
def build_modules_paths(self):
if self._build_modules_paths is None:
self._build_modules_paths = [os.path.join(self.rootpath, p) if not os.path.isabs(p)
else p for p in self.build_modules]
return self._build_modules_paths

@property
def include_paths(self):
if self._include_paths is None:
Expand Down Expand Up @@ -174,10 +183,15 @@ def merge_lists(seq1, seq2):
self.cflags = merge_lists(dep_cpp_info.cflags, self.cflags)
self.sharedlinkflags = merge_lists(dep_cpp_info.sharedlinkflags, self.sharedlinkflags)
self.exelinkflags = merge_lists(dep_cpp_info.exelinkflags, self.exelinkflags)
self.build_modules = merge_lists(self.build_modules, dep_cpp_info.build_modules_paths)

if not self.sysroot:
self.sysroot = dep_cpp_info.sysroot

@property
def build_modules_paths(self):
return self.build_modules

@property
def include_paths(self):
return self.includedirs
Expand Down
70 changes: 68 additions & 2 deletions conans/test/functional/generators/cmake_find_package_multi_test.py
Expand Up @@ -5,8 +5,8 @@

from nose.plugins.attrib import attr

from conans.client.tools import replace_in_file
from conans.test.utils.tools import TestClient
from conans.model.ref import ConanFileReference, PackageReference
from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID, replace_in_file
from conans.util.files import load


Expand Down Expand Up @@ -78,6 +78,72 @@ def test_native_export_multi(self):
self.assertIn("bye World {}!".format(bt), c.out)
os.remove(os.path.join(c.current_folder, "example"))

def build_modules_test(self):
conanfile = textwrap.dedent("""
import os
from conans import ConanFile, CMake
class Conan(ConanFile):
name = "test"
version = "1.0"
exports_sources = ["my-module.cmake", "FindFindModule.cmake"]
def package(self):
self.copy("*.cmake", dst="share/cmake")
def package_info(self):
# Only first module is defined
# (the other one should be found by CMAKE_MODULE_PATH in builddirs)
builddir = os.path.join("share", "cmake")
module = os.path.join(builddir, "my-module.cmake")
self.cpp_info.build_modules.append(module)
self.cpp_info.builddirs = [builddir]
""")
# This is a module that has other find_package() calls
my_module = textwrap.dedent("""
find_package(FindModule REQUIRED)
""")
# This is a module that defines some functionality
find_module = textwrap.dedent("""
function(conan_message MESSAGE_OUTPUT)
message(${ARGV${0}})
endfunction()
""")
client = TestClient()
client.save({"conanfile.py": conanfile, "my-module.cmake": my_module,
"FindFindModule.cmake": find_module})
client.run("create .")
ref = ConanFileReference("test", "1.0", None, None)
pref = PackageReference(ref, NO_SETTINGS_PACKAGE_ID, None)
package_path = client.cache.package_layout(ref).package(pref)
modules_path = os.path.join(package_path, "share", "cmake")
self.assertListEqual(os.listdir(modules_path), ["FindFindModule.cmake", "my-module.cmake"])
consumer = textwrap.dedent("""
from conans import ConanFile, CMake
class Conan(ConanFile):
name = "consumer"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
exports_sources = ["CMakeLists.txt"]
generators = "cmake_find_package_multi"
requires = "test/1.0"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
""")
cmakelists = textwrap.dedent("""
cmake_minimum_required(VERSION 3.0)
project(test)
find_package(test)
conan_message("Printing using a external module!")
""")
client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
client.run("create .")
self.assertIn("Printing using a external module!", client.out)

def cmake_find_package_system_libs_test(self):
conanfile = textwrap.dedent("""
from conans import ConanFile, tools
Expand Down
71 changes: 70 additions & 1 deletion conans/test/functional/generators/cmake_find_package_test.py
@@ -1,14 +1,17 @@
import os
import platform
import textwrap

import six
import textwrap
import unittest

from nose.plugins.attrib import attr

from conans.client.tools import replace_in_file
from conans.model.ref import ConanFileReference, PackageReference
from conans.test.utils.cpp_test_files import cpp_hello_conan_files
from conans.test.utils.tools import TestClient
from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID


@attr('slow')
Expand Down Expand Up @@ -303,6 +306,72 @@ def build(self):
six.assertRegex(self, str(client.out), "Target libs: .*Foundation\\.framework")
self.assertIn("Version: 0.1", client.out)

def build_modules_test(self):
conanfile = textwrap.dedent("""
import os
from conans import ConanFile, CMake
class Conan(ConanFile):
name = "test"
version = "1.0"
exports_sources = ["my-module.cmake", "FindFindModule.cmake"]
def package(self):
self.copy("*.cmake", dst="share/cmake")
def package_info(self):
# Only first module is defined
# (the other one should be found by CMAKE_MODULE_PATH in builddirs)
builddir = os.path.join("share", "cmake")
module = os.path.join(builddir, "my-module.cmake")
self.cpp_info.build_modules.append(module)
self.cpp_info.builddirs = [builddir]
""")
# This is a module that has other find_package() calls
my_module = textwrap.dedent("""
find_package(FindModule REQUIRED)
""")
# This is a module that defines some functionality
find_module = textwrap.dedent("""
function(conan_message MESSAGE_OUTPUT)
message(${ARGV${0}})
endfunction()
""")
client = TestClient()
client.save({"conanfile.py": conanfile, "my-module.cmake": my_module,
"FindFindModule.cmake": find_module})
client.run("create .")
ref = ConanFileReference("test", "1.0", None, None)
pref = PackageReference(ref, NO_SETTINGS_PACKAGE_ID, None)
package_path = client.cache.package_layout(ref).package(pref)
modules_path = os.path.join(package_path, "share", "cmake")
self.assertListEqual(os.listdir(modules_path), ["FindFindModule.cmake", "my-module.cmake"])
consumer = textwrap.dedent("""
from conans import ConanFile, CMake
class Conan(ConanFile):
name = "consumer"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
exports_sources = ["CMakeLists.txt"]
generators = "cmake_find_package"
requires = "test/1.0"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
""")
cmakelists = textwrap.dedent("""
cmake_minimum_required(VERSION 3.0)
project(test)
find_package(test)
conan_message("Printing using a external module!")
""")
client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
client.run("create .")
self.assertIn("Printing using a external module!", client.out)

def cpp_info_name_test(self):
client = TestClient()
client.run("new hello/1.0 -s")
Expand Down

0 comments on commit 7482b02

Please sign in to comment.