动态生成的cmake

时间:2016-06-08 13:12:02

标签: c++ cmake

我们有一个代码生成器,可以将通信协议定义生成为多个c ++文件,并希望切换我们的构建系统以使用cmake。 我已经制作了一个示例项目来展示我们面临的问题。

代码生成器接受一个输入文件,可能会生成数百个 输出文件,因此在CMakeLists.txt中枚举它们不是一个选项,特别是因为协议在开发过程中发生了变化。我们既不想使用通配符。

我们没有找到让cmake重新生成makefile的方法,如果其中一个输入文件发生了变化,根据文档,我们认为configure_file应该能够做到这一点,但显然失败了。

我们希望每当生成器(在示例中的main文件夹中)代码更改或协议定义文件(cmake)时,都会重新生成主项目的makefile(在示例中的gen文件夹中)在我们的示例中,这是in.txt)已更新。

我有以下文件结构:

src
├── CMakeLists.txt
├── gen
│   ├── CMakeLists.txt
│   └── gen.cpp
├── in.txt
└── main
    ├── CMakeLists.txt
    └── main.cpp

具有以下内容: 的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)

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)

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";

}

主/的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})

主/ main.cpp中:

int main(){}

gen使用input.txt生成src/in.txtinput.txt包含我要用于构建main的源文件列表:

set(SOURCES ${SOURCES} a.cpp)
set(SOURCES ${SOURCES} b.cpp)
set(SOURCES ${SOURCES} c.cpp)

我们正在寻找一种解决方案,它不需要引导cmake,也不需要在每次协议在开发过程中更改时重新运行它。这很容易实现,但是不可取,因为如果团队中的某个人没有意识到协议文件(或生成器)已经发生变化,那么最终会使用较旧的协议定义导致问题代码。

2 个答案:

答案 0 :(得分:0)

我认为您可以完全自动化该过程。 您需要一个可以处理文件参数列表的宏。 这是一个用于处理Zeroc Ice中间件的接口文件的示例,该中间件成为项目其余部分的源文件。 您还缺少的是&#34; MAIN_DEPENDENCY&#34;参数&#34; ADD_CUSTOM_COMMAND&#34;。

macro(sliceCpp outfiles)
    foreach(i ${ARGN})
        GET_FILENAME_COMPONENT(name ${i} NAME)
        GET_FILENAME_COMPONENT(name2 ${i} NAME_WE)
        SET(infile ${CMAKE_CURRENT_SOURCE_DIR}/${name})
        SET(out1 ${CMAKE_CURRENT_BINARY_DIR}/${name2}.cpp)
        SET(out2 ${CMAKE_CURRENT_BINARY_DIR}/${name2}.h)
        ADD_CUSTOM_COMMAND(
            OUTPUT ${out1} ${out2}
            COMMAND ${ICE_SLICE2CPP}
            ARGS -I${ICE_SLICE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR} --output-dir ${CMAKE_CURRENT_BINARY_DIR} ${infile}
            MAIN_DEPENDENCY ${infile}
        )
        SET(${outfiles} ${${outfiles}} ${out1} ${out2})
    endforeach(i)
    INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
endmacro(sliceCpp)

因此,CMake将了解依赖关系并仅重新构建必要的内容。为接口生成cpp文件的其他框架可能表现相似,您可以查看ROS generate_messages() here

答案 1 :(得分:0)

我们找到了一种方法。生成器gen放在一个单独的项目中,而不更改文件结构。在解析顶级CMakeLists.txt文件时构建并执行gen。当调用顶级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)

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
)

主/的CMakeLists.txt:

project(main)

set(SOURCES main.cpp)

include(${CMAKE_CURRENT_BINARY_DIR}/../gen/input.txt)

add_executable(main ${SOURCES})