CMake 中库之间的重叠依赖关系



假设有以下目录结构:

projects
   |
   +--lib1
   |   |
   |   +-CMakeFiles.txt
   |
   +--lib2
   |   |
   |   +-CMakeFiles.txt
   |
   +--test
       |
       +-CMakeFiles.txt

lib1/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)
add_library(lib1 STATIC lib1.cpp)

lib2/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)

test/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)
project(test)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)

lib2取决于lib1test取决于两者。(我知道技术上静态库不会"链接",但这只是一个示例。

问题是在当前设置下,lib1 编译两次 - 第一次在"test"构建目录中,第二次在"test/build_directory/lib2/build_directory"中。我想避免这种情况。

我希望能够将 lib1、lib2 或两者(使用 add_subdirectory(的依赖项添加到位于其他地方的任何项目中。因此,移动CMakeFiles不是一种选择。我还想避免多次编译任何库。

我该怎么做?

平台:CMake v. 2.8.4 和 Windows XP SP3

顶级 CMakeLists.txt 文件不是一个选项,因为我想保持一个干净的顶级目录,并能够在其他项目中包含可以位于其他地方的库。因为它是Windows,所以我不能"在系统范围内安装软件包" - 我不想失去即时切换编译器的能力。使用不同编译器构建的实用程序库将使用不同的 C 运行时库/ABI,因此将不兼容。

另一种解决方案是在子目录CMakeLists的顶部添加一个保护.txt:

if(TARGET targetname)
    return()
endif(TARGET targetname)

这将导致 cmake 在第二次添加子目录时不执行任何操作(当然,如果在该文件中定义了 targetname(。

这将导致lib beeing构建在build/树中的任意位置(取决于哪个模块首先添加它(,但它只会构建一次并链接到任何地方。

在您的示例中,您将添加

if(TARGET lib1)
    return()
endif(TARGET lib1)

在lib1/CMakeFiles的顶部.txt

使用 CMake,库依赖项是可传递的,因此您不应该在 test/CMakeFiles.txt 中调用 add_subdirectory 两次(也不需要将lib1列为test的依赖项,因为它已经是 lib2 的依赖项(。

因此,您可以将test的CMakeFiles.txt修改为:

cmake_minimum_required(VERSION 2.8.7)  # Prefer the most current version possible
project(test)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib2)

此外,您可能应该从非项目 CMakeFiles .txt 文件(lib 文件(中删除 cmake_minimum_required 调用。 有关详细信息,请运行:

cmake --help-policy CMP0000


如果您添加类似的 test2 子目录和项目,这取决于 lib1lib2,此设置仍会导致所有库被重新编译。 如果您真的不想在 projects/ 中拥有顶级 CMakeFiles.txt,那么您将坚持您正在做的事情,或者您可以使用 exportinstall 命令。

export将创建一个文件,该文件可由其他项目include,并将目标导入调用include的项目。

install可以将库安装到projects/的另一个公共子目录中。 根据您的源目录结构,这样做的好处是仅使预期的库 API 标头可供依赖项目使用。

但是,这两个选项都需要在修改依赖库项目时重新生成(并安装它们(,而当前设置包括项目中的所有依赖目标,因此对依赖库中源文件的任何更改都将导致test目标过期。

有关exportinstall的更多详细信息,请运行:

cmake --help-command export
cmake --help-command install

也许在你的项目目录中添加一个顶级CMakeLists.txt像这样:

project( YourProjects )
add_subdirectory( lib1 )
add_subdirectory( lib2 )
add_subdirectory( test )

这应该足够了,并且会在顶级构建目录中为您提供解决方案文件或生成文件。然后,您应该从 lib1 和 lib2 项目中删除add_subdirectory( ../lib1 ...,而只需链接到它们。CMake 在编译测试时会知道如何找到 lib1 和 lib2。

即在 lib2 中:

project( lib2) 
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)

并在测试中:

project( test )
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)

额外的好处:您将在lib2目录中获得用于构建lib2(使用依赖lib1(的makefiles/解决方案文件...

最新更新