调用 Rscript 的便携式 Makefile

Portable Makefiles that call Rscript

我正在编写一个生成 Makefiles 的 R 程序包,我需要编写一个 Makefile 来调用 Rscript,然后再创建目标。该问题的 MWE 如下。 Make 错误退出,因为 .INIT 的右侧不执行。为 file.rds 编写食谱不符合我的需要。

a=1
.INIT=`Rscript -e 'saveRDS('$(a)', "file.rds")'`

all: file2.rds

file2.rds: file.rds
        cp file.rds file2.rds

clean:
        rm file.rds file2.rds

我该怎么做才能解决此问题 Makefile 并保持其便携性?从 R 扩展手册中,我无法使用 $(shell 来完成我想要完成的事情。


编辑

从@Spacedman 的第一个回答中,我了解到 .INIT 是 "expanded"/当且仅当它在某处用作变量时才执行。太棒了! @Spacedman,我邀请你将以下内容 Makefile 复制到你自己的答案中,这样我就可以给你信用。

a=1
.INIT=`Rscript -e 'saveRDS('$(a)', "file.rds")'`

all: file2.rds

file2.rds:
        echo "file.rds should not have been built."

file3.rds:
        echo -n $(.INIT)
        cp file.rds file3.rds

clean:
        rm file.rds file2.rds

下面展示了我所希望的结果。

$ make file2.rds
echo "file.rds should not have been built."
file.rds should not have been built.
$ ls file.rds
ls: cannot access file.rds: No such file or directory
$ make file3.rds
echo -n `Rscript -e 'saveRDS('1', "file.rds")'`
cp file.rds file3.rds
$ ls file.rds
file.rds

我认为你需要使用 :=$(shell ...) 因此:

.INIT := $(shell Rscript -e 'saveRDS('$(a)', "file.rds")')

这使得 simply expanded variable 而不是 recursively expanded variable。我认为 Make 甚至不会费心查看您对 .INIT 的定义,因为它从未使用过。

反引号在 Make 中不是这样工作的,你必须使用 $(shell ...)。真的可以不用$(shell ...)anywhere吗?

https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_6.html

测试:

$ rm file.rds  file2.rds 
$ make
cp file.rds file2.rds
$ ls file*rds
file2.rds  file.rds

这似乎表明 make 已经通过 R 脚本创建了 file.rds

如果您可以将反引号字符串放入配方中,您就可以让它发挥作用(如您所见!)。请注意,我认为您不需要回显字符串,您可以将其展开,这似乎可行:

a=1
.INIT=`Rscript -e 'saveRDS('$(a)', "file.rds")'`

all: file2.rds

file2.rds:
    echo "file.rds should not have been built."

file3.rds:
    $(.INIT)
    cp file.rds file3.rds