动态生成的cmake源文件列表

rob*_*ert 6 c++ cmake

我们有一个代码生成器,可以将通信协议定义生成为多个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 每次协议在开发过程中更改时都需要自举或需要重新运行.这很容易实现,但是不合需要,因为如果团队中的某个人没有意识到协议文件(或生成器)已经发生变化,那么最终会使用较旧的协议定义会导致问题代码.

rob*_*ert 1

我们已经找到了一种方法来做到这一点。生成器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)