You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用CMake为含多个main函数的C++源码生成独立可执行文件?

为多main函数的测试代码生成独立可执行文件的CMake方案

问题背景

我找到josuttis的jthread项目源码,直接执行make命令编译失败,报错如下:

Makefile:1: Makefile.h: No such file or directory
make: *** No rule to make target `Makefile.h'. Stop.

因不清楚Makefile.h相关情况,我编写了如下CMake文件:

cmake_minimum_required (VERSION 3.6.2)
project (JtTest)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(CMAKE_CXX_STANDARD 23)
else()
set(CMAKE_CXX_STANDARD 20)
endif()

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using Clang
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC
add_definitions("-Wall -Wextra -Wno-unused-function -pedantic -pthread")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
# using Intel C++
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
# add_compile_options("/std:c++latest")
add_compile_options("/W4" "/Zc:__cplusplus")
add_definitions(-MP -D_UNICODE)
endif()

find_package(Threads)

file(GLOB_RECURSE CPP_FILES ${CMAKE_SOURCE_DIR}/*.h ${CMAKE_SOURCE_DIR}/*.cpp)

add_executable(${PROJECT_NAME} ${CPP_FILES})

target_link_libraries (${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})

所有源码编译成功但链接失败,原因是CMAKE_SOURCE_DIR目录下存在多个包含main函数的cpp文件:

test_cv.cpp
test_cvcb.cpp
test_cvprodcons.cpp
test_cvrace.cpp
test_cvrace_hh.cpp
test_cvrace_pred.cpp
test_cvrace_stop.cpp
test_jthread1.cpp
test_jthread2.cpp
test_stoken.cpp
test_stokencb.cpp
test_stokenrace.cpp
test_stopcb.cpp

我希望为每个cpp文件生成独立的可执行文件,请问用CMake正确的编译方式是什么?

编辑1:
若将CMake中的*.cpp改为单个文件(如test_cv.cpp)可成功生成可执行文件:

file(GLOB_RECURSE CPP_FILES ${CMAKE_SOURCE_DIR}/*.h ${CMAKE_SOURCE_DIR}/test_cv.cpp)

但使用*.cpp时会出现如下链接错误:

duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_pred.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvcb.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvprodcons.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_hh.cpp.o
duplicate symbol 'testCVAnyMutex()' in:
    CMakeFiles/JtTest.dir/test_cvrace_hh.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_stop.cpp.o
duplicate symbol '_cv' in:
    CMakeFiles/JtTest.dir/test_cvrace_hh.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_stop.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_stop.cpp.o
duplicate symbol '_m' in:
    CMakeFiles/JtTest.dir/test_cvrace_hh.cpp.o
    CMakeFiles/JtTest.dir/test_cvrace_stop.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_jthread1.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_jthread2.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_stoken.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_stokencb.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_stokenrace.cpp.o
duplicate symbol '_main' in:
    CMakeFiles/JtTest.dir/test_cv.cpp.o
    CMakeFiles/JtTest.dir/test_stopcb.cpp.o
ld: 16 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [JtTest] Error 1
make[1]: *** [CMakeFiles/JtTest.dir/all] Error 2
make: *** [all] Error 2

解决方案

核心思路是遍历每个测试cpp文件,为每个文件单独创建可执行目标,避免多个main函数冲突。修改后的CMakeLists.txt如下:

cmake_minimum_required (VERSION 3.6.2)
project (JtTest)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 设置C++标准,确保严格遵循
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    set(CMAKE_CXX_STANDARD 23)
else()
    set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 编译器特定编译选项
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    add_compile_options(-Wall -Wextra -Wno-unused-function -pedantic -pthread)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    add_compile_options(/W4 /Zc:__cplusplus)
    add_definitions(-MP -D_UNICODE)
endif()

find_package(Threads REQUIRED)

# 精准匹配所有测试cpp文件
file(GLOB TEST_CPP_FILES ${CMAKE_SOURCE_DIR}/test_*.cpp)

# 遍历每个测试文件,生成独立可执行
foreach(TEST_FILE ${TEST_CPP_FILES})
    # 提取文件名(不含路径和后缀)作为可执行名称
    get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
    add_executable(${TEST_NAME} ${TEST_FILE})
    # 链接线程库
    target_link_libraries(${TEST_NAME} PRIVATE Threads::Threads)
endforeach()

关键修改说明

  • 用test_*.cpp精准匹配测试文件,避免意外包含其他无关cpp文件
  • 通过foreach循环为每个测试文件单独创建可执行目标,文件名直接作为可执行名(比如test_cv.cpp对应test_cv)
  • 优化标准设置:添加CMAKE_CXX_STANDARD_REQUIRED ON和CMAKE_CXX_EXTENSIONS OFF,强制编译器使用指定的C++标准
  • 改用Threads::Threads链接线程库,是CMake 3.1+推荐的现代用法
  • 调整编译器选项的设置方式,更符合CMake最佳实践

内容的提问来源于stack exchange,提问作者Alexey Starinsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:25:20