如何使用任意shell命令获取CMake生成的构建系统来检索源文件并正确更新构建?
这样做的动机是从另一个构建系统迁移到CMake。中间目标是在构建系统之间共享一个源文件列表。源文件列表实际上可能存在于其他构建系统内部,但通常假设某些shell命令可以检索源文件列表。此问题与使用globbing获取源文件名的问题非常相似,但在这种情况下,手动列出CMakeLists.txt
文件中的所有源文件不是一个合理的替代方法。
即使没有办法让CMake自己这样做,提供任何自动化解决方案的答案也会没问题(例如,包装生成的构建系统的脚本)。
问题的非常简单的具体示例
我们有一个由两个源文件main.cpp
和foo.cpp
组成的应用。出于某种原因,需要使用一些shell命令获取源文件的名称,而不是将它们列在CMakeLists.txt
文件中。对于此示例,文件在files.txt
中每行列出一个,我们cat
此文件。通常,shell命令是一些以神秘的方式检索源文件列表的脚本。
main.cpp(ver 1)
#include "foo.h"
int main() {
foo();
}
foo.h中
#ifndef FOO_H
#define FOO_H
void foo();
#endif
Foo.cpp中
#include "foo.h"
#include <iostream>
void foo() {
std::cout << "foo()" << std::endl;
}
files.txt(ver 1)
main.cpp
foo.cpp
的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(ver 2)
#include "foo.h"
#include "bar.h"
int main() {
foo();
bar();
}
bar.h
#ifndef BAR_H
#define BAR_H
void bar();
#endif
bar.cpp
#include "bar.h"
#include <iostream>
void bar() {
std::cout << "bar()" << std::endl;
}
files.txt(ver 2)
main.cpp
foo.cpp
bar.cpp
以前由CMake生成的构建系统不再有效 - 尝试使用它会导致链接器错误,因为它不了解bar.cpp
。这可以通过触摸CMakeLists.txt
文件或重新运行cmake
命令来手动解决,但构建系统的目的是让我们摆脱这种艰巨而容易被遗忘的手工劳动。如何自动化?
答案 0 :(得分:1)
您可以使用touch
相关CMakeLists.txt
文件的makefile来解决此问题。
我将从OP的示例继续,并添加一个目录glob_us/
,我们希望将所有文件名与*.cpp
匹配。它包含baz.cpp
,类似于OP bar.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的示例中添加到files.txt
,无需人工干预。