【发布时间】:2017-04-20 20:43:42
【问题描述】:
我最近开始使用 CMake(2.8.12.2,包含在 CentOS 6.8 中的那个),我认为它足够强大,可以帮助完成我想要的,但我无法弄清楚如何 :-) ,所以我呼吁您的智慧来帮助我找到缺失的点。
我有一个这样的项目布局:
BaseDir
|
+-->bin (generated by the process)
| |
| +-->Debug
| +-->Release
|
+-->lib (generated by the process)
| |
| +-->Debug
| +-->Release
|
+-->CMakeLists.txt
|
+-->Library_A
| |
| +-->CMakeLists.txt
| +-->include
| +-->src
| | |
| | +-->CMakeLists.txt
| |
| +-->test # Small binary to test solely the library functions
| |
| +-->CMakeLists.txt
|
+-->Library_B (depends on Library_A)
| |
| +-->CMakeLists.txt
| +-->include
| +-->src
| | |
| | +-->CMakeLists.txt
| |
| +-->test # Small binary to test solely the library functions
| |
| +-->CMakeLists.txt
|
+-->Application_1 (depends on Library_B, hence transitivitely depends on Library_A)
| |
| +-->CMakeLists.txt
| +-->include
| +-->src
| |
| +-->CMakeLists.txt
|
+-->Application_2 (depends on Library_A)
|
+-->CMakeLists.txt
+-->include
+-->src
|
+-->CMakeLists.txt
当我将自己置于 BaseDir 下并运行“cmake .”时,它就像一个魅力。 Application_1、Application_2、Library_A 和 Libray_B 都以正确的顺序构建、链接等。
但是,我的想法是也能够在任何子目录(Application_、Library_)下进行构建,并且在这种情况下,只构建与其相关的代码(即自身,它的测试及其依赖项)。例如,当站在 Library_A 中时,仅构建该文件夹,而从 Library_B 中,也会构建 Library_A,当站在 Application_1 或 Application_2 下时发生的等效情况。另外,独立于我站在哪里触发 cmake 过程,构建结果(库或 bin)必须始终放在 BaseDir/{lib|bin}/{Debug/Release/etc} 下,永远不要放在库或应用程序子目录下.例如,这意味着 Library_B(依赖于 Library_A)或 Application_1(依赖于 Library_A 和 B)的链接必须查看 BaseDir/lib/{Debug/Release}。
我的目标是在 BaseDir 下拥有许多应用程序,因此如果不是真的需要,我希望避免每次都构建它们,只需要我想要的单个应用程序。
我查看了CMakeLists.txt files for multiple libraries and executables 和CMake and finding other projects and their dependencies,但这与我在这里尝试实现的情况并不完全相同。
我尝试过类似以下的方法:
BaseDir/CMakeLists.txt
|
| cmake_minimum_required (VERSION 2.8)
| project (BASE_DIR)
|
| add_subdirectory (Library_A) # No local dependencies
| add_subdirectory (Library_B) # Depends on A
| add_subdirectory (Application_1) # Depends on A and B
| add_subdirectory (Application_2) # Depends on A
|
| # I want all binary outputs (executables and libraries) placed under BaseDir/{lib|bin}/{Debug|Release}
| set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}") # For the executables
| set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/${CMAKE_BUILD_TYPE}") # For the static libraries
| set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
|
+-->BaseDir/Library_A/CMakeLists.txt (again, no dependencies)
| |
| | cmake_minimum_required (VERSION 2.8)
| | project (LIB_A)
| |
| | # In case CMake is run from within BaseDir/Library_A and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
| | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}") # For the test executables
| | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the static libraries
| | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
| |
| | include_directories(include)
| | add_subdirectory (src)
| | add_subdirectory (test)
| | set(${PROJECT_NAME}_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
| |
| +-->BaseDir/Library_A/src/CMakeLists.txt
| |
| | cmake_minimum_required (VERSION 2.8)
| |
| | # add all files in the current directory
| | file(GLOB LIB_A_SRCS "*.h" "*.cpp")
| |
| | # Create a library called libA.a
| | add_library(A ${LIB_A_SRCS})
| |
| +-->BaseDir/Library_A/test/CMakeLists.txt
|
| cmake_minimum_required (VERSION 2.8)
|
| # add all files in the current directory
| file(GLOB TEST_A_SRCS "*.h" "*.cpp")
|
| # Create an executable file from sources
| add_executable(TEST_A ${TEST_A_SRCS})
|
| # Link this executable to the library it's testing
| target_link_libraries(TEST_A A)
|
+-->BaseDir/Library_B/CMakeLists.txt (dependency on A)
| |
| | cmake_minimum_required (VERSION 2.8)
| | project (LIB_B)
| |
| | # In case CMake is run from within BaseDir/Library_B and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
| | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}") # For the test executables
| | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the static libraries
| | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
| |
| | include_directories(include)
| | add_subdirectory (src)
| | add_subdirectory (test)
| | set(${PROJECT_NAME}_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
| |
| +-->BaseDir/Library_B/src/CMakeLists.txt
| |
| | cmake_minimum_required (VERSION 2.8)
| |
| | # add all files in the current directory
| | file(GLOB LIB_B_SRCS "*.h" "*.c")
| |
| | # Create a library called libB.a
| | add_library(B ${LIB_B_SRCS})
| |
| | # Add a dependency to Library_A
| | find_library(LIBRARY_A A PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../Library_A)
| | include_directories("$LIB_A_INCLUDE_DIRECTORIES")
| | target_link_libraries(B ${LIBRARY_A})
| |
| +-->BaseDir/Library_B/test/CMakeLists.txt
|
| cmake_minimum_required (VERSION 2.8)
|
| # add all files in the current directory
| file(GLOB TEST_B_SRCS "*.h" "*.cpp")
|
| # Create an executable file from sources, for both versions of the library
| add_executable(TEST_B ${TEST_B_SRCS})
|
| # Link this executable to the library it's testing
| target_link_libraries(TEST_B B)
|
+-->BaseDir/Application_1/CMakeLists.txt
| |
| | cmake_minimum_required (VERSION 2.8)
| | project (APP_1)
| |
| | # In case CMake is run from within BaseDir/Application_1 and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
| | # In this case, only executables are generated.
| | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}")
| |
| | include_directories(include)
| | add_subdirectory (src)
| |
| +-->BaseDir/Application_1/src/CMakeLists.txt
|
| cmake_minimum_required (VERSION 2.8)
|
| # add all files in the current directory
| file(GLOB APP_1_SRCS "*.cpp")
|
| # Create an executable file from sources
| add_executable(EXE_1 ${APP_1_SRCS})
|
| # This should automatically bring Library_A
| find_library(LIBRARY_B B PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../Library_B)
| include_directories(${LIB_B_INCLUDE_DIRECTORIES})
| target_link_libraries(EXE_1 ${LIBRARY_B})
|
+-->BaseDir/Application_2/CMakeLists/CMakeLists.txt
|
| cmake_minimum_required (VERSION 2.8)
| project (APP_2)
|
| # In case CMake is run from within BaseDir/Application_2 and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
| # In this case, only executables are generated.
| set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}")
|
| include_directories(include)
| add_subdirectory (src)
|
+-->BaseDir/Application_2/src/CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
# add all files in the current directory
file(GLOB APP_2_SRCS "*.cpp")
# Create an executable file from sources
add_executable(EXE_2 ${APP_2_SRCS})
# Link this executable to the library it needs
find_library(LIBRARY_A A PATHS ${CMAKE_CURRENT_SOURCE_DIR}../../Library_A)
include_directories(${LIB_A_INCLUDE_DIRECTORIES})
target_link_libraries(EXE_2 ${LIBRARY_A})
但没有运气,因为当我从子目录(例如,BaseDir/Application_1)运行时,我只得到:
CMake 错误:此项目中使用了以下变量,但它们设置为 NOTFOUND。 请设置它们或确保它们在 CMake 文件中正确设置和测试: LIBRARY_B
我猜 "find_library()" 调用不足以满足我的要求,它基本上是加载库项目中包含的所有设置,不仅包括库本身,还包括该库添加的包含目录。 find_library() 的具体用法是什么,将其指向创建库的项目的位置,或实际生成的库(“.a”或“.so”)?
所以,我的主要疑问是:这种布局可行吗?如果是这样,我错过了什么?我应该使用 find_package() 还是 find_path() 之类的东西?如何从另一个“相同级别”CMakeLists.txt 触发解析 CMakeLists.txt 配置文件?
PS:我真的需要考虑在任何时候使用 "add_dependencies()" 吗?如果不是,该命令有什么意义?
【问题讨论】:
-
find_library搜索 实际 库文件。与find_path类似。 “对于我想要的,这基本上是加载库项目中包含的所有设置,不仅包括库本身,还包括该库添加的包含目录。” - CMake 能够导出 项目的二进制或安装树作为一个包。请参阅documentation guide 了解更多信息。 -
谢谢。所以我想 "find_package()" 是我要走的路。
标签: cmake dependencies subdirectory