"make"没有注意到 Rust 模块中的修改 - 如何更好地将 Rust 集成到构建中?



在一个简单的嵌入式项目中,我有两个文件main.rsmodule.rs。为了构建项目,我使用了类似这样的代码:

all: main.o
    $(CC) main.o $(LDFLAGS)
%.o: %.rs
    $(RUSTC) $(RUSTFLAGS) -o ${@} ${<}

如果只有module.rs被改变,make all不会重新编译我的Rust代码。我该如何解决这个问题?


我发布了一个次优的自我回答作为第一步,但希望看到更好的方法。

使用Make的最佳方法是将每个依赖项编码到Makefile中。这就是让Make知道为了达到目标状态需要重建什么的力量。

要在C项目中执行此操作,您通常会使用GCC命令行选项-M。这就把编译器引入了其中,因为它是解析C源代码和理解代码之间依赖关系的最佳工具文件。

对于Rust编译器rustc实际上有一个等效的开关:--emit=dep-info。当您在源文件上运行此命令时,它将输出一个扩展名为.d的文件,其中包含一个几乎与makefile兼容的依赖项列表。如果您有一个main.rs引用模块foo.rs,它将输出如下内容:

main.d: main.rs foo.rs

稍微调整一下,你就可以很好地发挥它。然后,您可以将其包含在Makefile中:

main.o:
    rustc -o $@ $<
main.d: main.rs
    rustc --emit=dep-info $<
    # Add the object file as a rule
    gsed 's/:/ $(@:.d=.o):/' -i $@
-include main.d

在这里,我在几个部分中指定了main,但我相信您可以轻松地将它们修改为模式规则。

实用的解决方案是只使用Cargo, Rust构建工具和包管理器。让它处理依赖(本地模块其他crate)。

libbar.dylib: target/debug/libbar.dylib
    cp $< $@
.PHONY: target/debug/libbar.dylib
target/debug/libbar.dylib:
    cargo build --verbose

这里,我将规则标记为PHONY,表示"始终运行此规则"。我已经添加了--verbose,让Cargo打印出它正在做什么,这样您就可以在重建时验证。

我建议放弃cp步骤,如果可以,而只是使用嵌套路径,但如果其他东西依赖于当前位置,则可能需要复制

样式

%.o: %.rs

在构建C项目时很常见,但这并不是编写目标的唯一方式。特定于上面的设置,这将修复以下情况:

main.o: main.rs module.rs
    $(RUSTC) $(RUSTFLAGS) -o main.o main.rs

与原始代码的一个值得注意的区别是,输入的名称对命令来说并不是真正重要的。我们可以归纳如下:

main.o: $(wildcard *.rs)
    $(RUSTC) $(RUSTFLAGS) -o ${@} ${@:.o=.rs}

这是一个开始,但它仍然有一些我无法摆脱的缺点:

  • main.o:部分是硬编码。如果有多个顶层模块需要编译,就会出现代码重复
  • 由于通配符,所有Rust文件将被考虑用于所有顶级模块。换句话说,更改任何Rust文件都需要完全重新编译。

最新更新