CMake:如何对多个文件运行自定义命令以生成源文件?

CMake:如何对多个文件运行自定义命令以生成源文件?,c,cmake,scheme,C,Cmake,Scheme,我有以下情况:我想将多个Scheme文件编译成一个可执行文件。为此,我使用gambit将所有Scheme文件转换/生成为C和对象文件,然后编译并链接到可执行文件中 假设我有以下三个文件(示例取自Gambit文档): EDIT:记住最后一个命令,这不是打字错误,最后一步是使用gcc进行链接 现在,我希望使用CMake为我做这件事。下面是我的CMakeLists.txt的概要: cmake_minimum_required( VERSION 3.8...3.18 ) if( ${CMAKE_VER

我有以下情况:我想将多个Scheme文件编译成一个可执行文件。为此,我使用gambit将所有Scheme文件转换/生成为C和对象文件,然后编译并链接到可执行文件中

假设我有以下三个文件(示例取自Gambit文档):

EDIT:记住最后一个命令,这不是打字错误,最后一步是使用
gcc
进行链接

现在,我希望使用CMake为我做这件事。下面是我的
CMakeLists.txt
的概要:

cmake_minimum_required( VERSION 3.8...3.18 )

if( ${CMAKE_VERSION} VERSION_LESS 3.12 )
    cmake_policy( VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} )
endif()

# Give this project a name 
project( schemetemplate VERSION 0.0.1 )

# compile all .scm files into *.c files 
# the C files as target
add_custom_target( 
    compiledSchemeFiles ALL 
    SOURCES m2.scm 
            m3.scm 
    COMMAND # this is where I call gsc(?)
    VERBATIM )

# or do I use custom command?
add_custom_command( ... )

# the final executable, how to tell add_executable I want all generated files as dependency?
add_exectuable( finalexec m1.c ...) 

除了纯C/C++项目,我从未与CMake合作过。最聪明的方法是什么?最终,我希望有一个
CMakeLists.txt
,我可以把我所有的Scheme文件放在一个子目录中,让它生成所有的C和object文件,并让父目录中的CMake使用它们创建可执行文件和库,使用
add_executable
add_library
可以定义scm源文件,然后为每个源文件创建自定义_命令。这将为每个.scm文件创建一个.c文件。可以将创建的文件添加到列表中(例如,命名的scm_c_文件),并在“添加可执行文件”命令中使用。最后,可以使用目标链接库定义所使用的库

我不知道gsc和相应的增量链接文件是如何工作的,但如果您可以为增量链接文件指定一个自定义名称(是否有某种-o选项?),它将只是另一个add_custom_命令,它仅依赖于从.scm文件生成的.c文件

例如,类似这样的事情:

add_custom_command(
        OUTPUT incLink.c
        gsc -link ${scm_c_files} -o incLink.c
        DEPENDS ${scm_c_files}
)
cmake_minimum_required(VERSION 3.17)
project(finalexec C)

set(CMAKE_C_STANDARD 99)

set(SCM_SOURCES m2.scm m3.scm)

set(scm_c_files)
foreach(scm_source ${SCM_SOURCES})
    get_filename_component(file_c ${scm_source} NAME_WE)
    set(file_c "${file_c}.c")
    add_custom_command(
            OUTPUT ${file_c}
            COMMAND gsc -c ${CMAKE_CURRENT_SOURCE_DIR}/${scm_source}
            DEPENDS ${scm_source}
            VERBATIM
    )
    list(APPEND scm_c_files ${file_c})
endforeach()

add_custom_command(
        OUTPUT incLink.c
        COMMAND gsc -link ${scm_c_files} -o incLink.c
        DEPENDS ${scm_c_files}
)


add_executable(finalexec m1.c ${scm_c_files} incLink.c)

target_link_libraries(finalexec gambit m dl util)
完整的CMakeLists.txt可能如下所示:

add_custom_command(
        OUTPUT incLink.c
        gsc -link ${scm_c_files} -o incLink.c
        DEPENDS ${scm_c_files}
)
cmake_minimum_required(VERSION 3.17)
project(finalexec C)

set(CMAKE_C_STANDARD 99)

set(SCM_SOURCES m2.scm m3.scm)

set(scm_c_files)
foreach(scm_source ${SCM_SOURCES})
    get_filename_component(file_c ${scm_source} NAME_WE)
    set(file_c "${file_c}.c")
    add_custom_command(
            OUTPUT ${file_c}
            COMMAND gsc -c ${CMAKE_CURRENT_SOURCE_DIR}/${scm_source}
            DEPENDS ${scm_source}
            VERBATIM
    )
    list(APPEND scm_c_files ${file_c})
endforeach()

add_custom_command(
        OUTPUT incLink.c
        COMMAND gsc -link ${scm_c_files} -o incLink.c
        DEPENDS ${scm_c_files}
)


add_executable(finalexec m1.c ${scm_c_files} incLink.c)

target_link_libraries(finalexec gambit m dl util)
测试

因为我没有gsc,我只是用一个echo和一个touch替换了自定义命令。如果我跑

cmake .
make 
我得到的结果是:

[ 12%] Generating m3.c
gsc -c /Users/stephan/kk/m3.scm
[ 25%] Generating m2.c
gsc -c /Users/stephan/kk/m2.scm
[ 37%] Generating incLink.c
gsc -link m2.c m3.c -o incLink.c
[ 50%] Building C object CMakeFiles/finalexec.dir/m1.c.o
[ 62%] Building C object CMakeFiles/finalexec.dir/m2.c.o
[ 75%] Building C object CMakeFiles/finalexec.dir/m3.c.o
[ 87%] Building C object CMakeFiles/finalexec.dir/incLink.c.o
[100%] Linking C executable finalexec
[100%] Built target finalexec

这似乎就是你要找的。

你真的需要一个单独的
-obj
步骤吗?谢谢,这很有效!我在掌握CMake book中找到了类似的解决方案,但更好!