Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile with SHELL=/usr/bin/R : handling multilines

Tags:

shell

r

makefile

I'm playing with R and Gnu Make (4.0, the code below won't work with <=3.81) and I'd like to use R instead of a classical shell:

I wrote the following code:

.PHONY: all clean
SHELL = /usr/bin/R
.SHELLFLAGS=  --vanilla --no-readline --quiet -e
.ONESHELL:

UCSC=http://hgdownload.cse.ucsc.edu/goldenpath/hg17/database/

all: chr1_gold.txt.gz
    gold <- read.delim(gzfile("$<"))
    head(gold)

chr1_gold.txt.gz:
    download.file("${UCSC}/$@","$@")


clean:
    $(foreach F,chr1_gold.txt.gz,file.remove("$F");)

the target chr1_gold.txt.gz works fine but not the target "all" because there is more than one line:

$ /make-4.0/make
download.file("http://hgdownload.cse.ucsc.edu/goldenpath/hg17/database//chr1_gold.txt.gz","chr1_gold.txt.gz")
> download.file("http://hgdownload.cse.ucsc.edu/goldenpath/hg17/database//chr1_gold.txt.gz","chr1_gold.txt.gz")
trying URL 'http://hgdownload.cse.ucsc.edu/goldenpath/hg17/database//chr1_gold.txt.gz'
Content type 'application/x-gzip' length 45866 bytes (44 Kb)
opened URL
==================================================
downloaded 44 Kb

> 
> 
gold <- read.delim(gzfile("chr1_gold.txt.gz"))
head(gold)

ARGUMENT 'head(gold)' __ignored__

> gold <- read.delim(gzfile("chr1_gold.txt.gz"));\
Error: unexpected input in "\"
Execution halted
Makefile:9: recipe for target 'all' failed
make: *** [all] Error 1

I tried to add a backslash, a semi colon but that doesn't work: how can I fix this ? Can I tell make to pipe a file to the SHELL instead of using an argument (-e string) ?

EDIT:

with

all: chr1_gold.txt.gz
    gold <- read.delim(gzfile("$<")) \
    head(gold)

.

read.delim(gzfile("chr1_gold.txt.gz")) \
head(gold)

ARGUMENT 'head(gold)' __ignored__

> gold <- read.delim(gzfile("chr1_gold.txt.gz")) \
Error: unexpected input in "gold <- read.delim(gzfile("chr1_gold.txt.gz")) \"
Execution halted

with ';'

all: chr1_gold.txt.gz
    gold <- read.delim(gzfile("$<")) ;
    head(gold)

. gold <- read.delim(gzfile("chr1_gold.txt.gz")) ; head(gold) ARGUMENT 'head(gold)' ignored

> gold <- read.delim(gzfile("chr1_gold.txt.gz")) ;
> 
> 

with ';\'

all: chr1_gold.txt.gz
    gold <- read.delim(gzfile("$<")) ;\
    head(gold)

.

ARGUMENT 'head(gold)' __ignored__

> gold <- read.delim(gzfile("chr1_gold.txt.gz")) ;\
Error: unexpected input in "\"
Execution halted
Makefile:9: recipe for target 'all' failed
like image 460
Pierre Avatar asked Apr 25 '26 01:04

Pierre


1 Answers

It looks to me like this is a problem with R's -e option: it appears that unlike the shell's -e option, R's version will accept only a single command and ignores embedded newlines (as you suspected). Unfortunately there's no option in GNU make to have it automatically write a temporary file and send that to the SHELL. The logistics here are somewhat daunting: how would you specify the name of the file in the shell command? Or what if you wanted to pipe via stdin? Etc. It could be done for sure, but requires some careful consideration of the design.

Currently GNU make requires that the interpreter used for SHELL must be able to accept a multi-line script provided on the command line, that's just the way it is.

The most straightforward way to work with R that I can think of is to put the recipe into a variable using define/enddef to preserve newlines, then use the new $(file ...) function to write it to a file and call R with the name of that file. You can make this somewhat cleaner with a user-defined variable, but you'll probably have to go back to using /bin/sh as the SHELL.

like image 141
MadScientist Avatar answered Apr 26 '26 13:04

MadScientist