CMake如何将子目录源文件正确编译到主目录可执行目标中?
解决CMake子目录文件编译进主可执行文件的问题
这个问题我太熟悉了,核心坑点就是CMake的变量作用域规则——你在子目录subdir里定义的EXTRA_SOURCES默认是局部变量,只能在子目录的CMakeLists.txt里生效,主目录根本拿不到这个变量的内容。不管你调换add_executable和add_subdirectory的顺序,主目录里的${EXTRA_SOURCES}都是空的,自然会出现链接错误。
下面给你两种可行的解决方案,优先推荐第二种,更符合CMake的工程化最佳实践:
方法一:通过PARENT_SCOPE传递源文件列表
这种方法是直接把变量的作用域提升到父目录,适合简单的小型项目:
- 修改子目录
subdir/CMakeLists.txt,在set命令后加上PARENT_SCOPE:
# subdir/CMakeLists.txt set(EXTRA_SOURCES file1.c file2.c PARENT_SCOPE)
- 主目录的CMakeLists.txt保持先加子目录、再定义可执行文件的顺序:
# 主目录CMakeLists.txt cmake_minimum_required(VERSION 3.10) project(main_project) add_subdirectory(subdir) add_executable(main main.c ${EXTRA_SOURCES})
这样子目录的EXTRA_SOURCES就会被传递到主目录,编译时就能包含file1.c和file2.c了。
方法二:把子目录编译为静态库(推荐)
这种方式更规范,适合后续需要扩展的项目,也能避免变量作用域带来的潜在问题:
- 修改子目录
subdir/CMakeLists.txt,创建一个静态库:
# subdir/CMakeLists.txt add_library(subdir_lib STATIC file1.c file2.c) # 如果file1.c/file2.c有对应的头文件,还可以用下面的命令暴露头文件路径 # target_include_directories(subdir_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
- 主目录的CMakeLists.txt中,链接这个静态库到主可执行文件:
# 主目录CMakeLists.txt cmake_minimum_required(VERSION 3.10) project(main_project) add_subdirectory(subdir) add_executable(main main.c) # 链接子目录的静态库 target_link_libraries(main PRIVATE subdir_lib)
CMake会自动处理静态库的编译和链接依赖,后续子目录新增源文件,只需要修改子目录的CMakeLists.txt,主目录完全不用改动,维护起来非常方便。
为什么原来的方法不行?
不管你怎么调换add_executable和add_subdirectory的顺序,只要子目录的变量没有传递到父目录,主目录里的${EXTRA_SOURCES}都是空值。CMake的变量默认是目录局部作用域,子目录的变量不会自动向上传递,这是很多初学者容易踩的坑。
内容的提问来源于stack exchange,提问作者On Demand
相关产品推荐
相关产品推荐

