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

CMake中为何add_executable可链接对象文件却无法直接链接库?

问题描述

我写了下面这个简单的CMakeLists.txt:

project(MyProject)

# Create the library from server.cpp
add_library(server OBJECT tcp_server.cpp tcp_server_priv.cpp)
# Add the current directory to the include path for this target
target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

# Create the executable from main.cpp and link it to the library
add_executable(my_server main.cpp $<TARGET_OBJECTS:server>)

我知道add_library(x OBJECT y z ...)不会生成静态或共享库(.a或.so),只是对目标文件做逻辑分组,能通过$<TARGET_OBJECTS:server>引用tcp_server.o和tcp_server_priv.o这两个目标文件,上面的add_executable语句会编译main.cpp并链接这些对象文件生成my_server可执行文件。

我想让可执行文件链接libpthread,于是把add_executable语句改成这样:

add_executable(my_server main.cpp $<TARGET_OBJECTS:server> pthread)

但CMake报错了:

-- Configuring done
CMake Error at src/CMakeLists.txt:9 (add_executable):
  Cannot find source file:

    pthread

  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
  .hpp .hxx .in .txx


CMake Error at src/CMakeLists.txt:9 (add_executable):
  No SOURCES given to target: med_server


CMake Generate step failed.  Build files cannot be regenerated correctly.
make: *** [Makefile:160: cmake_check_build_system] Error 1

而用g++命令可以在同一个调用里编译源文件、链接对象文件和库:

tcp_server.cpp代码:

#include <iostream>

extern void private_func();

void public_func() {
  std::cout << __FUNCTION__ << std::endl;
  private_func();
}

tcp_server_priv.cpp代码:

#include <iostream>

void private_func() {
  std::cout << __FUNCTION__ << std::endl;
}

main.cpp代码:

#include <semaphore.h>

extern void public_func();

int main(int argc, char* argv[]) {
  sem_t my_sem;

  public_func();
  sem_init(&my_sem, 0, 0);
  sem_destroy(&my_sem);

  return 0;
}

执行的g++命令和结果:

$ g++ -c ./tcp_server.cpp \
> && g++ -c ./tcp_server_priv.cpp \
> && g++ main.cpp tcp_server.o tcp_server_priv.o -lpthread \
> && ./a.out
public_func
private_func
$

我有两个疑问:

  • 为什么add_executable语句能链接对象文件,却不能直接链接库?
  • 我尝试的add_executable写法和上面的g++命令等效吗?
解答

问题1:为什么add_executable不能直接链接库?

CMake的add_executable命令逻辑和g++完全不同:

  • add_executable的参数里,除目标名外只能放源文件(.cpp/.c等)或对象文件引用(比如$<TARGET_OBJECTS:server>),它的核心是定义要编译的目标,不负责处理链接依赖。
  • 库文件(如pthread)属于链接阶段的依赖,CMake专门用target_link_libraries命令管理这类依赖,这是模块化设计的结果,把编译目标定义和链接依赖管理分开,保证配置清晰易维护。
  • 你写的pthread会被CMake当成待编译的源文件查找,自然找不到对应后缀的文件,所以报错。

问题2:尝试的add_executable写法和g++命令不等效

两者逻辑完全无关:

  • g++命令里的-lpthread是告诉编译器链接阶段要关联libpthread库;
  • 你在add_executable里加pthread,是让CMake寻找名为pthread的源文件,和链接库的需求完全不沾边。

正确的CMake写法

要实现和给出的g++命令等效的效果,应该用target_link_libraries添加pthread依赖:

project(MyProject)

add_library(server OBJECT tcp_server.cpp tcp_server_priv.cpp)
target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

add_executable(my_server main.cpp $<TARGET_OBJECTS:server>)
# 添加pthread链接依赖
target_link_libraries(my_server PRIVATE pthread)

另外,对于pthread,更推荐用FindThreads模块,兼容性更好:

project(MyProject)

# 引入FindThreads模块
find_package(Threads REQUIRED)

add_library(server OBJECT tcp_server.cpp tcp_server_priv.cpp)
target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

add_executable(my_server main.cpp $<TARGET_OBJECTS:server>)
# 使用Threads::Threads目标来链接
target_link_libraries(my_server PRIVATE Threads::Threads)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:01:19