CMake:如何在多个文件上运行自定义命令来生成源文件?

2024-04-21

我有以下情况:我想编译一些Scheme文件Gambit https://github.com/gambit/gambit成可执行文件。为此,我使用 gambit 将所有计划文件翻译/生成为 C 和目标文件,然后将其编译并链接为可执行文件。

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

/* File: "m1.c" */
int power_of_2 (int x) { return 1<<x; }

; File: "m2.scm"
(c-declare "extern int power_of_2 ();")
(define pow2 (c-lambda (int) int "power_of_2"))
(define (twice x) (cons x x))

; File: "m3.scm"
(write (map twice (map pow2 '(1 2 3 4)))) (newline)

如果我要手动编译它,则需要执行以下步骤:

    
$ gsc -c m2.scm        # create m2.c (note: .scm is optional)
$ gsc -c m3.scm        # create m3.c (note: .scm is optional)
$ gsc -link m2.c m3.c  # create the incremental link file m3_.c
$ gsc -obj m1.c m2.c m3.c m3_.c # create all object files *.o
m1.c:
m2.c:
m3.c:
m3_.c:
$ gcc m1.o m2.o m3.o m3_.o -lgambit -lm -ldl -lutil # link object files
$ ./a.out
((2 . 2) (4 . 4) (8 . 8) (16 . 16))

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我可以将其放置在包含所有计划文件的子目录中,让它生成所有 C 和对象文件,并让 CMake 在父目录中使用它们来创建可执行文件和库add_executable and add_library.


您可以定义 scm 源文件,然后为每个文件创建一个 custom_command。这将为每个 .scm 文件创建一个 .c 文件。创建的文件可以添加到列表中(例如名为 scm_c_files)并在 add_executable 命令中使用。最后,可以使用 target_link_libraries 定义所使用的库。

我不确切知道 gsc 和相应的增量链接文件是如何工作的,但是如果您可以为增量链接文件指定一个自定义名称(是否有某种 -o 选项?),那么它只是另一个取决于的 add_custom_command仅适用于从 .scm 文件生成的 .c 文件。

例如这样的事情:

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

完整的 CMakeLists.txt 可能如下所示:

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)

Test

由于我没有 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

这似乎就是你正在寻找的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake:如何在多个文件上运行自定义命令来生成源文件? 的相关文章

  • 打击垃圾邮件机器人

    我的网站中有 C 表单 希望防止垃圾邮件机器人填写它 诀窍是 我想避免 CAPTHA 或任何其他用户输入 以避免丢失单个注册 以下是我心中的一些技巧 隐藏输入栏 问题 这还有效吗 跟踪时间 从第一个用户输入 关注名字 到发布表单 人类需要
  • 分层架构中的异常处理

    我们正在分层设计中重构 当然还有重新设计 我们的服务 我们有服务操作层 BLL 网络抽象层 gt 处理网络代理 数据抽象层 但我们对我们的异常处理策略有点困惑 我们不想向外界透露太多 BLL 的信息 从其他层到bll就可以了 我们不想让 t
  • 如何动态加载包含非托管代码的原始程序集?(绕过“无法验证的代码失败策略检查”异常)

    我将举一个使用的例子系统 Data SQLite DLL http sqlite phxsoftware com 这是一个包含非托管代码的混合程序集 如果我执行这个 var assembly Assembly LoadFrom System
  • 在调用堆栈中看到大量 clr!CLR Semaphore::Wait

    我们看到很多像下面这样的调用堆栈 我可以知道什么条件 情况会发生这种情况吗 OS Thread Id 0x48654 559 Current frame ntdll NtWaitForSingleObject 0xa Child SP Re
  • 如何启动异步任务对象

    我想开始收集Task同时处理对象并等待所有对象完成 下面的代码显示了我想要的行为 public class Program class TaskTest private Task createPauseTask int ms works w
  • 在 C# 中调用事件处理程序

    我一直在尝试学习如何在 C 中使用事件处理程序 但我无法弄清楚 handler this e 在以下代码中的作用 public event EventHandler ThresholdReached protected virtual vo
  • C++ 错误:从“char”到“const char*”的转换无效

    我对 C 完全陌生 我创建了这个函数 bool guessWord string compWord cout lt lt Guess a letter string userLetter cin gt gt userLetter for u
  • 带双重检查锁的单例设计模式

    假设您有以下代码 1 为什么我们使用双重检查锁 为什么单锁不够好 请提供详细的例子 2 这种实施方式的主要缺点是什么 我该如何证明呢 Thanks public sealed class SomeSingleton5 private sta
  • 使用 QGraphicsScene 实现流畅的动画

    我希望我的问题并不总是同样的问题 我有一个 QGraphicsScene 它的项目是一些 QGraphicsPixmap 我用一个计时器来移动它们 每秒 SetX 10 我设置 10是因为窗口大100 使用这个解决方案我的动画不流畅 我想我
  • 将一个整数从 C 客户端发送到 Java 服务器

    我使用此代码将一个整数从我的 Java 客户端发送到我的 Java 服务器 int n rand nextInt 50 1 DataOutputStream dos new DataOutputStream socket getOutput
  • 按值返回的函数的返回语句中的初始化

    我的问题源于深入研究std move in return语句 例如以下示例 struct A A std cout lt lt Constructed lt lt this lt lt std endl A A noexcept std c
  • 使用宏计算源文件行数?

    是否可以使用 C C 预处理器将源文件中的行数计算为宏或某种编译时可用值 例如 我可以更换吗MAGIC1 MAGIC2 and MAGIC3在下面 并在使用时以某种方式获取值 4MAGIC3 MAGIC1 can be placed whe
  • 带有自定义鉴别器的 EntityFramework Code First 继承

    我正在尝试在 EntityFramework Code First 中映射以下继承 public class Member public string ProjectName get set public string AssemblyNa
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • 如何使用 xamarin 表单提示用户进行地理定位

    我正在 Xamarin Forms 应用程序中开发一个应用程序 需要请求地理位置权限 如果获得许可 它需要从设备获取地理位置数据 然后将地理位置坐标放入 Forecast io URL 我正在使用 James 的 Geolocator 插件
  • 如何在给定点停止线程?

    我试图停止一些线程 阅读一些有关优雅地执行此操作的正确方法的内容 但我一定做错了什么 因为它根本不起作用 起初我尝试不使用lock with IsRunning不稳定 然后尝试使用锁 这是我所拥有的 private volatile boo
  • 在 C# WinForms 中预览文档(Word、Excel、PDF、文本文件等)?

    我正在开发一个 C WinForms 应用程序 我希望能够 预览 其中的各种文档类型 也就是说 当用户从列表中选择文件名时 它会在下面以相同的形式显示所选文件的预览 这很像 Outlook 允许您无需双击即可预览选定邮件的方式 有没有什么方
  • 扔掉挥发物安全吗?

    大多数时候 我都是这样做的 class a public a i 100 OK delete int j Compiler happy But is it safe The following code will lead compilat
  • 从 STL 列表中删除项目

    我想创建一个函数 如果符合特定条件 则将项目从一个 STL 列表移动到另一个列表 这段代码不是这样做的方法 迭代器很可能会被擦除 函数失效并导致问题 for std list
  • 如何在用户空间程序中使用内核 libcrc32c (或相同的函数)?

    我想在我自己的用户空间程序中进行一些 CRC 检查 我发现内核加密库已经在系统中 并且支持 SSE4 2 我尝试直接 include

随机推荐