我们有一个代码生成器,可以将通信协议定义生成为多个c ++文件,并希望切换我们的构建系统以使用cmake.我做了一个示例项目来展示我们面临的问题.
代码生成器接收输入文件并可能生成数百个输出文件,因此枚举它们CMakeLists.txt不是一个选项,特别是因为协议在开发期间发生了变化.我们既不想使用通配符.
如果其中一个输入文件发生变化,我们没有找到让cmake重新生成makefile的方法,根据文档我们认为configure_file应该能够做到这一点,但它显然无法完成它的工作.
我们希望main每当生成器(gen在示例中的文件夹中)代码更改或协议定义文件(在我们的示例中in.txt)更新时,cmake都会重新生成主项目的makefile(在示例中的文件夹中).
我有以下文件结构:
src
??? CMakeLists.txt
??? gen
? ??? CMakeLists.txt
? ??? gen.cpp
??? in.txt
??? main
??? CMakeLists.txt
??? main.cpp
Run Code Online (Sandbox Code Playgroud)
具有以下内容:src/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(cmake-config)
add_subdirectory(main)
add_subdirectory(gen)
add_dependencies(main gen run_gen)
Run Code Online (Sandbox Code Playgroud)
GEN /的CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(gen)
add_executable(gen gen.cpp)
add_custom_target(
run_gen
COMMAND ./gen ${CMAKE_SOURCE_DIR}/in.txt
COMMENT running gen
)
add_dependencies(run_gen gen)
Run Code Online (Sandbox Code Playgroud)
GEN/gen.cpp:
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[]){
ifstream inf(argv[1]);
ofstream outf("input.txt");
string word;
while(inf >> word)
outf << "set(SOURCES ${SOURCES} " << word << ")\n";
}
Run Code Online (Sandbox Code Playgroud)
主/的CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(main)
if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/../gen/input.txt)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/../gen/input.txt "")
endif()
configure_file(${CMAKE_CURRENT_BINARY_DIR}/../gen/input.txt ${CMAKE_CURRENT_BINARY_DIR}/input.txt COPYONLY)
set(SOURCES main.cpp)
include(${CMAKE_CURRENT_BINARY_DIR}/input.txt)
message(${SOURCES})
add_executable(main ${SOURCES})
Run Code Online (Sandbox Code Playgroud)
主/ main.cpp中:
int main(){}
Run Code Online (Sandbox Code Playgroud)
gen生成input.txt使用src/in.txt.input.txt包含我要用于构建的源文件列表main:
set(SOURCES ${SOURCES} a.cpp)
set(SOURCES ${SOURCES} b.cpp)
set(SOURCES ${SOURCES} c.cpp)
Run Code Online (Sandbox Code Playgroud)
我们正在寻找一种解决方案,无需cmake 每次协议在开发过程中更改时都需要自举或需要重新运行.这很容易实现,但是不合需要,因为如果团队中的某个人没有意识到协议文件(或生成器)已经发生变化,那么最终会使用较旧的协议定义会导致问题代码.
我们已经找到了一种方法来做到这一点。生成器gen被放置在一个单独的项目中,而不改变文件结构。gen在解析顶级 CMakeLists.txt 文件时构建并执行。当调用顶层时make,它会修改 CMakeLists.txt,因此下次make调用时会cmake自动运行。项目gen有一个自定义命令,如果发生更改,它会重新生成输出in.txt。
src/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5.1)
project(cmake-config)
if(NOT EXISTS ${CMAKE_BINARY_DIR}/gen/Makefile)
execute_process(COMMAND cmake -B${CMAKE_BINARY_DIR}/gen -H${CMAKE_SOURCE_DIR}/gen)
endif()
execute_process(COMMAND make -C ${CMAKE_BINARY_DIR}/gen)
add_custom_target(touch_cmakelists.txt ALL
COMMAND touch ${CMAKE_SOURCE_DIR}/CMakeLists.txt
)
add_subdirectory(main)
Run Code Online (Sandbox Code Playgroud)
gen/CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(gen)
add_executable(gen gen.cpp)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gen ${CMAKE_SOURCE_DIR}/../in.txt
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gen ${CMAKE_SOURCE_DIR}/../in.txt
COMMENT "Running gen"
)
add_custom_target(run_generator ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/input.txt
)
Run Code Online (Sandbox Code Playgroud)
主/CMakeLists.txt:
project(main)
set(SOURCES main.cpp)
include(${CMAKE_CURRENT_BINARY_DIR}/../gen/input.txt)
add_executable(main ${SOURCES})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2983 次 |
| 最近记录: |