调用 Rscript 的便携式 Makefile
Portable Makefiles that call Rscript
我正在编写一个生成 Makefile
s 的 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
我正在编写一个生成 Makefile
s 的 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