CMake和寻找其他项目,它们的依赖(CMake and finding other project

2019-09-02 01:59发布

想象以下情形:项目A是其中有几个依赖(LIBA,LibB,的LibC)一个共享库。 项目B是对一个项目的依赖可执行的,因此,要求所有项目A的依赖也是为了打造。

此外,这两个项目都是使用CMake的建成,项目A不应该需要安装(通过“安装”的目标),以便项目B使用它,因为这可能成为滋扰给开发者。

所以,问题是,什么是解决使用CMake的这些依赖关系的最佳方式? 理想的解决办法是尽可能(虽然没有简单)一样简单,只需要最少的维护。

Answer 1:

简单。 这是从我头顶的例子:

顶级CMakeLists.txt

cmake_minimum_required(VERSION 2.8.10)

# You can tweak some common (for all subprojects) stuff here. For example:

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES  ON)

if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
  message(SEND_ERROR "In-source builds are not allowed.")
endif ()

set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_COLOR_MAKEFILE   ON)

# Remove 'lib' prefix for shared libraries on Windows
if (WIN32)
  set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif ()

# When done tweaking common stuff, configure the components (subprojects).
# NOTE: The order matters! The most independent ones should go first.
add_subdirectory(components/B) # B is a static library (depends on Boost)
add_subdirectory(components/C) # C is a shared library (depends on B and external XXX)
add_subdirectory(components/A) # A is a shared library (depends on C and B)

add_subdirectory(components/Executable) # Executable (depends on A and C)

CMakeLists.txtcomponents/B

cmake_minimum_required(VERSION 2.8.10)

project(B C CXX)

find_package(Boost
             1.50.0
             REQUIRED)

file(GLOB CPP_FILES source/*.cpp)

include_directories(${Boost_INCLUDE_DIRS})

add_library(${PROJECT_NAME} STATIC ${CPP_FILES})

# Required on Unix OS family to be able to be linked into shared libraries.
set_target_properties(${PROJECT_NAME}
                      PROPERTIES POSITION_INDEPENDENT_CODE ON)

target_link_libraries(${PROJECT_NAME})

# Expose B's public includes (including Boost transitively) to other
# subprojects through cache variable.
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include
                                 ${Boost_INCLUDE_DIRS}
    CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)

CMakeLists.txtcomponents/C

cmake_minimum_required(VERSION 2.8.10)

project(C C CXX)

find_package(XXX REQUIRED)

file(GLOB CPP_FILES source/*.cpp)

add_definitions(${XXX_DEFINITIONS})

# NOTE: Boost's includes are transitively added through B_INCLUDE_DIRS.
include_directories(${B_INCLUDE_DIRS}
                    ${XXX_INCLUDE_DIRS})

add_library(${PROJECT_NAME} SHARED ${CPP_FILES})

target_link_libraries(${PROJECT_NAME} B
                                      ${XXX_LIBRARIES})

# Expose C's definitions (in this case only the ones of XXX transitively)
# to other subprojects through cache variable.
set(${PROJECT_NAME}_DEFINITIONS ${XXX_DEFINITIONS}
    CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)

# Expose C's public includes (including the ones of C's dependencies transitively)
# to other subprojects through cache variable.
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include
                                 ${B_INCLUDE_DIRS}
                                 ${XXX_INCLUDE_DIRS}
    CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)

CMakeLists.txtcomponents/A

cmake_minimum_required(VERSION 2.8.10)

project(A C CXX)

file(GLOB CPP_FILES source/*.cpp)

# XXX's definitions are transitively added through C_DEFINITIONS.
add_definitions(${C_DEFINITIONS})

# NOTE: B's and Boost's includes are transitively added through C_INCLUDE_DIRS.
include_directories(${C_INCLUDE_DIRS})

add_library(${PROJECT_NAME} SHARED ${CPP_FILES})

# You could need `${XXX_LIBRARIES}` here too, in case if the dependency 
# of A on C is not purely transitive in terms of XXX, but A explicitly requires
# some additional symbols from XXX. However, in this example, I assumed that 
# this is not the case, therefore A is only linked against B and C.
target_link_libraries(${PROJECT_NAME} B
                                      C)

# Expose A's definitions (in this case only the ones of C transitively)
# to other subprojects through cache variable.
set(${PROJECT_NAME}_DEFINITIONS ${C_DEFINITIONS}
    CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE)

# Expose A's public includes (including the ones of A's dependencies
# transitively) to other subprojects through cache variable.
set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include
                                 ${C_INCLUDE_DIRS}
    CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)

CMakeLists.txtcomponents/Executable

cmake_minimum_required(VERSION 2.8.10)

project(Executable C CXX)

file(GLOB CPP_FILES source/*.cpp)

add_definitions(${A_DEFINITIONS})

include_directories(${A_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} ${CPP_FILES})

target_link_libraries(${PROJECT_NAME} A C)

要清楚,这里是相应的源树结构:

Root of the project
├───components
│   ├───Executable
│   │   ├───resource
│   │   │   └───icons
│   │   ├───source
|   |   └───CMakeLists.txt
│   ├───A
│   │   ├───include
│   │   │   └───A
│   │   ├───source
|   |   └───CMakeLists.txt
│   ├───B
│   │   ├───include
│   │   │   └───B
│   │   ├───source
|   |   └───CMakeLists.txt
│   └───C
│       ├───include
│       │   └───C
│       ├───source
|       └───CMakeLists.txt
└───CMakeLists.txt

有许多点哪里,这可能进行调整/定制或修改,以满足特定的需求,但至少应该让你开始。

注:我已经成功地采用了这样的结构在几个中型和大型项目。



Answer 2:

亚历山大Shukaev的得到了一个很好的开始,但也有许多事情可以做的更好:

  1. 不要使用include_directories。 最起码,使用target_include_directories 。 不过,你可能甚至都不需要做,如果你使用了进口的目标。
  2. 采用进口的目标。 例如,对于升压:

     find_package(Boost 1.56 REQUIRED COMPONENTS date_time filesystem iostreams) add_executable(foo foo.cc) target_link_libraries(foo PRIVATE Boost::date_time Boost::filesystem Boost::iostreams ) 

    如果您在B您的头,使用升压则替代PRIVATE,使用公共和这些相关性将被传递地添加到任何依赖于B.这需要在包括目录,图书馆等的护理

  3. 不要使用文件globing(除非你使用3.12)。 直到最近,文件寻找在配置的时候才能正常运行,因此,如果您添加文件和构建,它无法检测到更改,直到您明确地重新生成项目。 不过,如果你直接列出文件,并试图建立,应该认识到配置过时,在构建步骤自动重新生成。

这里有很好的会谈(YouTube)的: C ++现在2017年:丹尼尔·普法伊费尔“有效的CMake”

其中涵盖了包管理器的想法,让你的根级别的CMake一起工作find_packagesubdirectory ,不过,我一直在试图采取这种意识形态和我有使用大问题find_package的一切,有像你这样的目录结构。



Answer 3:

这也可以使用CMake的做Cache机制来实现相同的(即项目特定变量的共享):

集(VAR “值” CACHE INTERNAL "")

请参阅堆栈溢出问题, 如何共享不同的CMake文件之间的变量



文章来源: CMake and finding other projects and their dependencies
标签: cmake