【问题标题】:Adding multiple executables in CMake在 CMake 中添加多个可执行文件
【发布时间】:2012-12-27 17:11:22
【问题描述】:

我在一个 C++ 项目中的代码组织如下

  • 我有几个 .cpp.h 文件,其中包含我的课程
  • 我有几个 .cxx 文件必须针对 .cpp 文件和一些外部库进行编译。

现在,每个.cxx 文件都有一个main() 方法,所以我需要为每个与文件同名的文件添加不同的可执行文件。

此外,这些.cxx 文件可能不会链接到相同的外部库。

我想在 CMake 中编写这个构建,我是一个新手,我该怎么做?

【问题讨论】:

    标签: c++ build cmake executable


    【解决方案1】:

    我的建议是分两个阶段解决这个问题:

    1. .cpp.h 文件构建一个库,使用add_library
    2. 遍历所有.cxx 文件并使用add_executableforeach 从每个文件创建一个可执行文件

    构建库

    这可能很简单

    file( GLOB LIB_SOURCES lib/*.cpp )
    file( GLOB LIB_HEADERS lib/*.h )
    add_library( YourLib ${LIB_SOURCES} ${LIB_HEADERS} )
    

    构建所有可执行文件

    只需遍历所有 .cpp 文件并创建单独的可执行文件。

    # If necessary, use the RELATIVE flag, otherwise each source file may be listed 
    # with full pathname. RELATIVE may makes it easier to extract an executable name
    # automatically.
    # file( GLOB APP_SOURCES RELATIVE app/*.cxx )
    file( GLOB APP_SOURCES app/*.cxx )
    foreach( testsourcefile ${APP_SOURCES} )
        # I used a simple string replace, to cut off .cpp.
        string( REPLACE ".cpp" "" testname ${testsourcefile} )
        add_executable( ${testname} ${testsourcefile} )
        # Make sure YourLib is linked to each app
        target_link_libraries( ${testname} YourLib )
    endforeach( testsourcefile ${APP_SOURCES} )
    

    一些警告:

    • file( GLOB ) 通常不推荐,因为如果添加新文件,CMake 不会自动重建。我在这里使用它,因为我不知道你的源文件。
    • 在某些情况下,可以找到带有完整路径名的源文件。如有必要,请使用RELATIVE flag for find( GLOB ... )
    • 手动设置源文件需要更改 CMakeLists.txt,这会触发重建。请参阅 this question 了解通配符的(不利)优势。
    • 我使用string( REPLACE ... ) 生成了测试名称。我可以将get_filename_componentNAME_WE 标志一起使用。

    关于“一般”CMake 信息,我建议您阅读一些已在 stackoverflow 上提出的广泛的“CMake 概述”问题。例如:

    【讨论】:

    • +1 不错的答案。可执行文件会全部构建到同一个顶级build/ 目录中,还是会尊重底层源代码树的目录结构?另见this question
    • 我没有测试过,但假设它会在类似于 source-dir 的目录结构中生成可执行文件。无耻插件:看看stackoverflow.com/questions/13556885如何修改输出路径...
    • 如果你使用较新的cmake(3.0.2是我发现的最早的),你可以使用get_filename_component(testname ${testsourcefile} NAME_WE)而不是string(REPLACE...来获取文件名。好处是这也会删除路径的其余部分,如果您使用EXECUTABLE_OUTPUT_PATH 设置二进制文件的位置,这很方便。
    • @André 有什么替代 file( GLOB APP_SOURCES app/*.cxx )
    • 在使用它之前,我必须进行相当多的修改。我的配置如下:file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) foreach( sourcefile ${APP_SOURCES} ) file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile}) string( REPLACE ".cpp" "" file ${filename} ) add_executable( ${file} ${sourcefile} ) target_link_libraries( ${file} ndn-cxx boost_system ) endforeach( sourcefile ${APP_SOURCES} )
    【解决方案2】:

    我发现自己在组织一个包含多个示例文件的 OpenGL 项目时遇到了类似的情况,其中每个文件都包含一个 main 方法。

    以下设置将为每个 c/cpp 文件生成一个单独的可执行文件,并将所需的依赖项复制到目标 bin 文件夹。

    文件夹结构

    my-project
    │── ch01_01.c
    │── ch02_01.cpp
    │── CMakeLists.txt
    │── Resources
    │   │── Libraries
    │   │   │── glew
    │   │   │   │── bin
    │   │   │   │── include
    │   │   │   │── lib
    │   │   │── glfw    
    │   │   │   │── include 
    │   │   │   │── lib 
    

    CMakeLists.txt

    cmake_minimum_required (VERSION 3.9)
    
    project ("my-project")
    
    include_directories(Resources/Libraries/glew/include
                        Resources/Libraries/glfw/include)
    
    link_directories(Resources/Libraries/glew/lib
                     Resources/Libraries/glfw/lib)
    
    link_libraries(opengl32.lib
                   glew32.lib
                   glfw3.lib)
    
    set(CMAKE_EXE_LINKER_FLAGS "/NODEFAULTLIB:MSVCRT")
    
    file(GLOB SOURCE_FILES *.c *.cpp)
    
    foreach(SOURCE_PATH ${SOURCE_FILES})
    
        get_filename_component(EXECUTABLE_NAME ${SOURCE_PATH} NAME_WE)
    
        add_executable(${EXECUTABLE_NAME} ${SOURCE_PATH})
    
        # Copy required DLLs to the target folder
        add_custom_command(TARGET ${EXECUTABLE_NAME} POST_BUILD
                           COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/Resources/Libraries/glew/bin/glew32.dll" 
                                                                         "${CMAKE_BINARY_DIR}/glew32.dll")
    
    endforeach(SOURCE_PATH ${SOURCE_FILES})
    

    可选步骤

    在 Visual Studio 中

    • 在开始窗口中使用“打开本地文件夹”选项打开项目

    • 添加新文件时,您可以:

      • 取消要求自动将add_executable 发送到CMakeLists.txt 的对话框
      • 通过取消选中Tools > Options > CMake 中的“为文件夹视图中的文件操作启用自动 CMake 脚本修改”来禁用此行为

    由于 CMakeLists.txt 永远不会更改,因此不会自动拾取新添加的文件,因此只需像这样重新生成缓存:

    • Project > CMake Cache (x64-Debug) > Delete Cache
    • Project > Generate Cache for my-project

    现在您只需右键单击给定的 c/cpp 文件和 Set as Startup Item 即可使用 F5 对其进行调试。

    环境

    • cmake 版本 3.18.20081302-MSVC_2
    • Microsoft Visual Studio Community 2019 版本 16.8.3

    入门模板

    我把这个starter template放在GitHub上,以防你感兴趣。

    【讨论】:

      【解决方案3】:

      这个CMakeLists.txt 适用于我的 OpenCV 项目
      假设*.cpp 文件与CMakeLists.txt 位于同一目录中

      cmake_minimum_required(VERSION 3.5)
      
      project(opencv LANGUAGES CXX)
      
      set(CMAKE_CXX_STANDARD 11)
      set(CMAKE_CXX_STANDARD_REQUIRED ON)
      
      find_package(OpenCV REQUIRED)
      include_directories( ${OpenCV_INCLUDE_DIRS} )
      
      file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
      foreach( sourcefile ${APP_SOURCES} )
          file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
          string( REPLACE ".cpp" "" file ${filename} )
          add_executable( ${file} ${sourcefile} )
          target_link_libraries( ${file} ${OpenCV_LIBS} )
      endforeach( sourcefile ${APP_SOURCES} )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 2016-01-31
        • 2014-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多