C++ CMake:使用静态库在一个项目中构建多个可执行文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23684789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:31:23  来源:igfitidea点击:

CMake: Build Multiple Executables in one Project with Static Library

c++cmake

提问by drodman

I'm working on a project that consists of 3 server executables and one library for shared code. I want it to be cross-platform, so I'm using CMake (since Xcode is being a pain anyway) to handle the build process. I'm having trouble with setting up the CMakeLists so that I can include the library from a directory at the same level when I'm building the executable.

我正在开发一个由 3 个服务器可执行文件和一个共享代码库组成的项目。我希望它是跨平台的,所以我使用 CMake(因为 Xcode 无论如何都很痛苦)来处理构建过程。我在设置 CMakeLists 时遇到问题,以便在构建可执行文件时可以包含同一级别目录中的库。

Here's the directory structure (and the CMake files):

这是目录结构(和 CMake 文件):

tethealla2.0/
    CMakeLists.txt
    libtethealla/
        CMakeLists.txt
        encryption/
        utils/
    patch_server/
        CMakeLists.txt
    login_server/
        CMakeLists.txt
    ship_server/
        CMakeLists.txt

My top-level CMake (tethealla2.0/CMakeLists.txt, only includes the sub-project that should compile):

我的顶级CMake(tethealla2.0/CMakeLists.txt,只包含应该编译的子项目):

project(tethealla CXX)
cmake_minimum_required(VERSION 2.6)

add_subdirectory(libtethealla)
add_subdirectory(patch_server)

tethealla2.0/libtethealla/CMakeLists.txt, which generates a static library:

tethealla2.0/libtethealla/CMakeLists.txt,生成静态库:

project(Libtethealla C)
cmake_minimum_required(VERSION 2.6)

include_directories(encryption)

set(ENC_DR encryption/)

set(ENCRYPTION_SOURCES 
  ${ENC_DR}/psobb-crypt.c
  ${ENC_DR}/psogc-crypt.c
  ${ENC_DR}/psobb-crypt.c
  ${ENC_DR}/encryption.c
  )

add_library(tethealla STATIC ${ENCRYPTION_SOURCES})

tethealla2.0/patch_server/CMakeLists.txt thus far:

tethealla2.0/patch_server/CMakeLists.txt 到目前为止:

project(patch_server CXX)
cmake_minimum_required(VERSION 2.6)

add_executable(server main.cc)
target_link_libraries(server tethealla)

So it makes more sense if I build it from the top level since tethealla2.0/CMakeLists.txt will inherit the targets from each of the subdirectories and the one in patch_server will have access to the tethealla library. However what I want is to be able to build from within these subdirectories to generate Xcode projects so that I can work on/recompile them individually. To do so I need to be able to get to the libtethealla/build directory (where CMake outputs) to access the libtethealla.a library from patch_server. Is this possible?

因此,如果我从顶层构建它更有意义,因为 tethealla2.0/CMakeLists.txt 将从每个子目录继承目标,而 patch_server 中的目标将可以访问 tethealla 库。但是,我想要的是能够从这些子目录中构建以生成 Xcode 项目,以便我可以单独处理/重新编译它们。为此,我需要能够进入 libtethealla/build 目录(CMake 输出的位置)以从 patch_server 访问 libtethealla.a 库。这可能吗?

On kind of another note, even in building from the top-level directory my source in patch_server can't include "encryption.h", the header file for the library in encryption. Which seems to be building fine. Any thoughts on that are also greatly appreciated!

另一种注意,即使是从顶级目录构建,我在 patch_server 中的源也不能包含“encryption.h”,即加密库的头文件。这似乎建设得很好。对此的任何想法也非常感谢!

回答by luantkow

My solution is to use add_subdirectory with relative patch to shared_lib directory. I don't think that this is a perfect solution it has its caveats:

我的解决方案是使用 add_subdirectory 和 shared_lib 目录的相对补丁。我不认为这是一个完美的解决方案,它有其警告:

  • Logic very similar to a header guard must be added to library CMakeLists.txt to prevent from defining targets multiple times.
  • Each CMakeList.txt file must know the relative path to the library, if one want to move library all CMakeLists must be updated.
  • 必须将非常类似于标题保护的逻辑添加到库 CMakeLists.txt 中,以防止多次定义目标。
  • 每个 CMakeList.txt 文件必须知道库的相对路径,如果要移动库,则必须更新所有 CMakeLists。

Let's assume that the directory structure looks like this:

让我们假设目录结构如下所示:

root/
    CMakeLists.txt
    shared_lib/
        CMakeLists.txt
        inc/
            foo.h
        src/
            foo.c
    exec1/
       CMakeLists.txt
       main.c
    exec2/
       CMakeLists.txt
       main.c

root/CMakeList.txt

根/CMakeList.txt

cmake_minimum_required(VERSION 2.6)

add_subdirectory(shared_lib)

add_subdirectory(exec1)
add_subdirectory(exec2)

I have decided that shared_lib/CMakeLists.txt will export a variable named SHARED_DIR_INCLUDE_DIR. This approach helps to decouple things a little bit.

我已经决定 shared_lib/CMakeLists.txt 将导出一个名为SHARED_DIR_INCLUDE_DIR. 这种方法有助于将事情稍微解耦。

root/exec1/CMakeLists.txt

root/exec1/CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

add_subdirectory(./../shared_lib shared_lib)

include_directories(${SHARED_LIB_INCLUDE_DIR})

set(SRCS main.c)
add_executable(exec1 ${SRCS})
target_link_libraries(exec1 shared_lib)

if()in the fourth line solves the issue with target's multiple definition in case the CMakeLists file is added multiple times. The second and the third lines exports the include directory for library in SHARED_LIB_INCLUDE_DIR

if()在第四行中解决了目标多重定义的问题,以防 CMakeLists 文件被多次添加。第二行和第三行导出库的包含目录SHARED_LIB_INCLUDE_DIR

root/shared_lib/CMakeLists.txt

root/shared_lib/CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

set(SHARED_LIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)

set(SHARED_LIB_INCLUDE_DIR ${SHARED_LIB_INCLUDE_DIR} PARENT_SCOPE)

if(TARGET shared_lib)

message("shared_lib is already defined")

else()

include_directories(${SHARED_LIB_INCLUDE_DIR})

set(LIB_SRCS ./src/foo.c)

add_library(shared_lib STATIC ${LIB_SRCS})

endif()