Polyglot Makefiles

栏目: IT技术 · 发布时间: 4年前

内容简介:Did you know that you can change the shell in aNow typingWhat else is possible? Can I use other programming languages as the shell? Is it possible to write in-line Python in a

Did you know that you can change the shell in a Makefile ? It’s true. I found this out when trying to use bash instead of the default /bin/sh by setting SHELL .

.ONESHELL:
bash: SHELL := bash
bash:
	# note: the double dollar-sign is required because Make substitues $variables
	export greeting="¡hola"
	echo "$${greeting}, bash!"

Now typing make bash will print ¡hola, bash!

What else is possible? Can I use other programming languages as the shell? Is it possible to write in-line Python in a Makefile ?

Python

.ONESHELL:
python: SHELL := python3
python:
	greeting = "hello"
	print(f"{greeting}, python!")

Yes, this is possible

Typing make python will print hello, python! .

Notice that there is a variable .ONESHELL being set. Normally, make will evaluate each command in a separate shell meaning that, in this example, greeting would be undefined in the second line. Adding .ONESHELL to the top of your Makefile , as recommended by someone else whose last name begins with Davis-* and blogs about make , causes multi-line code in the Make directive to be evaluated in a single call to Python.

R

What about writing R in-line in a Makefile? Note the addition of .SHELLFLAGS . By default, make runs SHELL -c "your\nscript\nhere" which is not compatible R. To run a script in-line from a command in R, you use -e :

R: .SHELLFLAGS := -e
R: SHELL := Rscript
R:
	greeting = "bonjour"
	message(paste0(greeting, ", R!"))

This is equivalent to running Rscript -e 'greeting = "bounjour"; message(paste0(greeting, ", R!"));'

Now you can write a pipeline that combines R and Python in a single file :tada:

Bring in the containers

Data analysis pipelines often have adventurous dependencies. Docker made all of that a lot easier but writing docker run ... can be cumbersome. What if we could make Docker the interpreter and write commands to be executed inside the container in-line as well?

docker: .SHELLFLAGS = run --volume $(shell pwd):/workdir --rm --workdir /workdir --entrypoint /bin/bash ubuntu -c
docker: SHELL := docker
docker:
	echo "hello, $$(uname -a)!"

Again, this is possible. Running make docker will run echo ... in a Docker container running Ubuntu. Note the --volume flag which will mount the current working directory as the container’s working directory meaning that files can be read/created between your local filesystem and that of the container. So build artifacts can be shared between make directives.

hello, Linux 453c728113d6 4.19.76-linuxkit #1 SMP Fri Apr 3 15:53:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux!

Why?

This started as an experiment to see what is possible with make . But it was motivated by a real world problem: I often need to combine tools across programming languages and environments to run data analysis pipelines. I like to automate things and make is a great tool for doing so. Having everything in-line is more readable and having everything in a single file means that I have to jump between fewer tabs to understand the pipeline itself.

The ability to write commands that get executed in Docker means that I have to spend less time figuring out how to get a bunch of dependencies installed in a single container which becomes increasingly difficult as the number of dependencies increases (especially if you work in Bioinformatics).

Full Makefile

note: Some of these features only work on make 4.+ which I installed using Homebrew . These examples do not work using make 3.x which is comes with macOS Catalina.

.ONESHELL:
.SILENT:

main: \
	python \
	ruby \
	R \
	bash \
	docker

docker: .SHELLFLAGS = run --rm --entrypoint /bin/bash ubuntu -c
docker: SHELL := docker
docker:
	echo "hello, $$(uname -a)!"

python: SHELL := python3
python:
	greeting = "hello"
	print(f"{greeting}, python!")

ruby: .SHELLFLAGS := -e
ruby: SHELL := ruby
ruby:
	greeting = "labas"
	puts "#{greeting}, ruby!"

R: .SHELLFLAGS := -e
R: SHELL := Rscript
R:
	greeting = "bonjour"
	message(paste0(greeting, ", R!"))

bash: .SHELLFLAGS := -euo pipefail -c
bash: SHELL := bash
bash:
	export greeting="¡hola"
	echo "$${greeting}, bash!"

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序设计语言

程序设计语言

斯科特 / 裘宗燕 / 电子工业出版社 / 2007-6 / 99.00元

★列为全球上百所大学标准教材和首席参考书! ★图书馆必备典藏,作者Michael L.Scott 是计算机领域的著名学者,译者是北京大学的裘宗燕教授,他熟悉专业,译笔流畅,因此,这是一本难得的著、译双馨的佳作。 这是一本很有特色的教材,其核心是讨论程序设计语言的工作原理和技术。本书融合了传统的程序设计语言教科书和编译教科书的有关知识,并增加了一些有关汇编层体系结构......一起来看看 《程序设计语言》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具