我想知道如何为我的项目编译依赖项,同时为这些依赖项启用特定设置,例如将依赖项编译为静态或动态库或使用x64或x86设置,或者当项目将变量定义为确定如何构建项目(如使用Wayland或X.Org支持)。
我目前的设置如下:
root_project
|─── CMakeLists.txt
|─── Project 1
| |─── .h and .cpp files
| └─── CMakeLists.txt
|─── Dependency 1 (GLFW)
| |─── include directory
| |─── source directory
| |─── ...
| └─── CMakeLists.txt
└─── Dependency 2 (GLEW)
|─── build
| └─── cmake
| └─── CMakeLists.txt
|─── source directory
|─── include directory
└─── ...
我的root cmake文件:
cmake_minimum_required (VERSION 3.8)
project ("EbsiStaller")
add_subdirectory ("EbsiStaller")
# Adds the CMakeLists.txt file located in the specified directory
# as a build dependency.
add_subdirectory ("glfw")
include_directories("glfw/include")
add_subdirectory ("glew/build/cmake")
include_directories("glew/include")
我的项目cmake文件:
cmake_minimum_required (VERSION 3.8)
add_executable (EbsiStaller
"....cpp"
"....h"
)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
# Links the CMake build output against glfw.
target_link_libraries(EbsiStaller glfw ${GLFW_LIBRARIES} glew ${GLEW_LIBRARIES})
我在Windows下使用Visual Studio 2017进行此项目,而项目应该与平台无关。由于我对CMake没有太多经验,所以我总是对我的CMake文件的任何建议更改开放。
为依赖项定义特定于编译的设置时,我不想编辑它们的CMake文件。
答案 0 :(得分:1)
在CMake中这样做有很多困难,但我会尽我所能来回答它。
通常,您通过add_subdirectory
添加的任何项目都将继承当前范围内当前定义的所有设置。更改单个依赖项设置的最简单方法(IMO)是将ExternalProject_Add
与macros一起使用:
include(ExternalProject)
#
# Add external project.
#
# \param name Name of external project
# \param path Path to source directory
# \param external Name of the external target
#
macro(add_external_project name path)
# Create external project
set(${name}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${path})
set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${path})
ExternalProject_Add(${name}
SOURCE_DIR "${${name}_SOURCE_DIR}"
BINARY_DIR "${${name}_BINARY_DIR}"
CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
# These are only useful if you're cross-compiling.
# They, however, will not hurt regardless.
"-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}"
"-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}"
"-DCMAKE_AR=${CMAKE_AR}"
"-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}"
"-DCMAKE_COMPILER_PREFIX=${CMAKE_COMPILER_PREFIX}"
"-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}"
INSTALL_COMMAND ""
)
endmacro(add_external_project)
#
# Add external target to external project.
#
# \param name Name of external project
# \param includedir Path to include directory
# \param libdir Path to library directory
# \param build_type Build type {STATIC, SHARED}
# \param external Name of the external target
#
macro(add_external_target name includedir libdir build_type external)
# Configurations
set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${libdir})
# Create external library
add_library(${name} ${build_type} IMPORTED)
set(${name}_LIBRARY "${${name}_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_${build_type}_LIBRARY_PREFIX}${name}${CMAKE_${build_type}_LIBRARY_SUFFIX}")
# Find paths and set dependencies
add_dependencies(${name} ${external})
set(${name}_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${includedir}")
# Set interface properties
set_target_properties(${name} PROPERTIES IMPORTED_LOCATION ${${name}_LIBRARY})
set_target_properties(${name} PROPERTIES INCLUDE_DIRECTORIES ${${name}_INCLUDE_DIR})
endmacro(add_external_target)
宏基本上配置了一个具有非常相似的CMake变量定义的CMake的新实例。
第一个宏ExternalProject_Add
通知CMake它需要使用那些自定义CMake参数,源目录和输出二进制目录构建一次所需的外部项目。特别是,像"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
这样的选项告诉CMake使用与当前构建类型相同的构建类型(Debug,Release等),而"-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
指示CMake在构建共享库时使用相同的首选项(默认情况下,如果BUILD_SHARED_LIBS
设置为OFF
,则项目应构建静态依赖项。)
然后第二个宏创建一个导入的目标,CMake可能会链接到与本机CMake库类似的属性。
要默认使用这些宏,您可以执行以下操作:
add_external_project(googletest_external googletest)
add_external_target(gtest googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external)
add_external_target(gtest_main googletest/googletest/include googletest/googlemock/gtest STATIC googletest_external)
在此示例中,我配置了外部项目googletest
,然后创建了目标gtest
和gtest_main
,它们应该是静态库(由于Googletest强制静态链接的方式),可以像任何普通的CMake库一样链接。
现在您已经粗略地了解了这些宏的功能,修改它们以允许每个依赖项的自定义配置非常容易。比如说,无论我的实际项目设置如何,我都想要一个静态版本的glew。我们还假设我希望将GLEW_OSMESA
设置为ON
。
#
# Add external project.
#
macro(add_release_osmesa_glew)
# Create external project
set(${name}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glew)
set(${name}_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/glew)
ExternalProject_Add(glew_external
SOURCE_DIR "${${name}_SOURCE_DIR}"
BINARY_DIR "${${name}_BINARY_DIR}"
CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_BUILD_TYPE=Release"
"-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
# These are only useful if you're cross-compiling.
# They, however, will not hurt regardless.
"-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}"
"-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}"
"-DCMAKE_AR=${CMAKE_AR}"
"-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}"
"-DCMAKE_COMPILER_PREFIX=${CMAKE_COMPILER_PREFIX}"
"-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}"
"-DGLEW_OSMESA=ON"
INSTALL_COMMAND ""
)
然后,要使用使用这些配置选项构建的glew,我可以执行以下操作:
add_release_osmesa_glew()
add_external_target(
glew
glew/include
glew
SHARED
glew_external
)
add_external_target(
glew_s
glew/include
glew
STATIC
glew_external
)
最后,我可以使用以下选项链接它:
target_link_libraries(my_target
glew_s
...
)
答案 1 :(得分:1)
正确的方法是直接在目标上运作。例如(猜测目标名称,原谅我):
add_subdirectory ("glfw")
set_target_properties(glfw PROPERTIES
COMPILE_FLAGS "-m32 -O2" # Adjust as needed
)
target_link_libraries(glew INTERFACE
${GLFW_LIBRARIES}
)
add_subdirectory ("glew/build/cmake")
target_include_directories(glew PUBLIC
"glfw/include"
)
target_link_libraries(glew INTERFACE
${GLEW_LIBRARIES}
)
这使您可以按目标而不是全局调整内容(这是现代CMake使用的基础)。您可以使用这些函数及其朋友调整您喜欢的任何目标,包括调整编译器标志甚至添加新文件。
您正在使用的方法有效,但您正在影响之后声明的每个目标,包括稍后添加的子目录。
您的主要项目CMakeLists.txt
可能如下所示:
add_executable (EbsiStaller
"....cpp"
"....h"
)
target_compile_features(EbsiStaller PUBLIC
cxx_std_17 # might actually be a cmake 3.9 thing, but you get the idea
)
# Links the CMake build output against glfw.
target_link_libraries(EbsiStaller
glfw
glew
)
这里有太多的内容,但这一切都归结为你的CMake的现代化。在线文档太棒了。