Cmake 使用shell命令或globbing检索源,相应地更新生成
如何让CMake生成的生成系统使用任意shell命令检索源文件并正确更新生成 这样做的动机是从另一个构建系统迁移到CMake。中间目标是在构建系统之间共享一个源文件列表。源文件列表实际上可能存在于另一个生成系统中,但通常假设某个shell命令可以检索源文件列表。这个问题与使用globbing获取源文件名的问题非常相似,但在这种情况下,手动在Cmake 使用shell命令或globbing检索源,相应地更新生成,cmake,glob,Cmake,Glob,如何让CMake生成的生成系统使用任意shell命令检索源文件并正确更新生成 这样做的动机是从另一个构建系统迁移到CMake。中间目标是在构建系统之间共享一个源文件列表。源文件列表实际上可能存在于另一个生成系统中,但通常假设某个shell命令可以检索源文件列表。这个问题与使用globbing获取源文件名的问题非常相似,但在这种情况下,手动在CMakeLists.txt文件中列出所有源文件不是一个合理的选择 即使无法让CMake自己做到这一点,提供任何自动化解决方案的答案也可以(例如,封装生成的构
CMakeLists.txt
文件中列出所有源文件不是一个合理的选择
即使无法让CMake自己做到这一点,提供任何自动化解决方案的答案也可以(例如,封装生成的构建系统的脚本)
问题的非常简单的具体例子 我们有一个由两个源文件组成的应用程序,
main.cpp
和foo.cpp
。出于某种原因,最好使用一些shell命令获取源文件的名称,而不是将它们列在CMakeLists.txt
文件中。对于本例,文件在files.txt
中每行列出一个,我们cat
此文件。通常,shell命令是以神秘的方式检索源文件列表的脚本
main.cpp(第1版)
福安
foo.cpp
#include "foo.h"
#include <iostream>
void foo() {
std::cout << "foo()" << std::endl;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.1)
project(SourcesFromCommand)
# run some external command that retrieves our source files
execute_process(COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/files.txt OUTPUT_VARIABLE files)
# turn newline separated relative filenames into cmake list of absolute filenames
string(REPLACE "\n" ";${CMAKE_CURRENT_SOURCE_DIR}/" file_list ${files})
# print filenames to make sure the list came out right
foreach(file ${file_list})
message(${file})
endforeach()
add_executable(main ${file_list})
CMake为包含上述文件的项目生成一个工作构建系统。后来,我们的应用程序成功流行,所以我们决定为ver添加新功能。2.0. main.cpp
现在调用bar()
,它位于bar.h
和bar.cpp
中。我们相应地更新了files.txt
main.cpp(第2版)
酒吧
bar.cpp
#include "bar.h"
#include <iostream>
void bar() {
std::cout << "bar()" << std::endl;
}
以前由CMake生成的构建系统不再工作——尝试使用它会导致链接器错误,因为它不知道
bar.cpp
。这可以通过触摸CMakeLists.txt
文件或重新运行cmake
命令手动解决,但构建系统的目的是将我们从如此繁重且容易忘记的手工劳动中解放出来。如何实现自动化?您可以使用一个makefile来解决此问题,该makefile可以触摸相关的CMakeLists.txt
文件
我将从OP的示例继续,并添加一个目录,glob\u us/
,我们希望从中对所有匹配*.cpp
的文件名进行全局搜索。它包含类似于OP的bar.cpp
的baz.cpp
相关文件:
- 生成文件
- CMakeLists.txt
- files.txt
- main.cpp
- main.h
- foo.cpp
- 福安
- bar.cpp
- 酒吧
- 环球美国/巴兹h
- glob_us/baz.cpp
CMakeLists.txt的底部变为:
file(GLOB globbed_files glob_us/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glob_us)
add_executable(main ${file_list} ${globbed_files})
Makefile
包含以下内容:
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
GLOBBED := $(wildcard $(MAKEFILE_DIR)/glob_us/*cpp)
# phony target that depends on whatever files we need to touch
cmake: $(MAKEFILE_DIR)/CMakeLists.txt
$(MAKEFILE_DIR)/CMakeLists.txt: $(MAKEFILE_DIR)/files.txt $(GLOBBED)
@touch $(MAKEFILE_DIR)/CMakeLists.txt
.PHONY: cmake
生成生成系统:
mkdir build
cd build
cmake -G $MY_FAVORITE_GENERATOR ..
然后构建:
make -f ../Makefile && $MY_FAVORITE_BUILD_SYSTEM_COMMAND
可以将文件添加到glob_us
,或像OP的示例一样,从glob_us添加到Files.txt
,无需手动干预
#include "bar.h"
#include <iostream>
void bar() {
std::cout << "bar()" << std::endl;
}
main.cpp
foo.cpp
bar.cpp
file(GLOB globbed_files glob_us/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glob_us)
add_executable(main ${file_list} ${globbed_files})
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
GLOBBED := $(wildcard $(MAKEFILE_DIR)/glob_us/*cpp)
# phony target that depends on whatever files we need to touch
cmake: $(MAKEFILE_DIR)/CMakeLists.txt
$(MAKEFILE_DIR)/CMakeLists.txt: $(MAKEFILE_DIR)/files.txt $(GLOBBED)
@touch $(MAKEFILE_DIR)/CMakeLists.txt
.PHONY: cmake
mkdir build
cd build
cmake -G $MY_FAVORITE_GENERATOR ..
make -f ../Makefile && $MY_FAVORITE_BUILD_SYSTEM_COMMAND