如何在Makefile操作中使用Shell变量?

48

我在Makefile中添加了以下内容来重新创建我的数据库,包括必要时销毁它。但是它并没有起作用。

.PHONY: rebuilddb
    exists=$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM pg_database WHERE datname='the_db'")
    if [ $(exists) -eq 1 ]; then
        dropdb the_db
    fi
    createdb -E UTF8 the_db

运行它会导致错误:

$ make rebuilddb
exists=
if [  -eq 1 ]; then
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [rebuilddb_postgres] Error 2

为什么会出错?就我所知,它看起来像是有效的 Bash 代码。在 Makefile 中执行时是否需要特殊考虑?
更新:根据答案,我得到了一个可行的版本。
.PHONY: rebuilddb
    exists=$$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM pg_database WHERE datname='the_db'"); \
    if [ "$$exists" == "1" ]; then \
        dropdb the_db; \
    fi;
    createdb -E UTF8 the_db
2个回答

60

至少有两个要考虑的问题。$()是对Make变量的引用,你需要转义$来进行命令替换。另外,shell命令必须全部在一行上。请尝试:

至少有兩個要考慮的問題。$()是對Make變量的引用,你需要轉義$來進行命令替換。另外,shell命令必須全部在一行上。請嘗試:

exists=$$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM \
    pg_database WHERE datname='the_db'"); \
    if [ "$$exists" -eq 1 ]; then \
        dropdb the_db; \
    fi; \
    createdb -E UTF8 the_db

另一方面,似乎直接尝试删除数据库并允许失败会更简单:

rebuilddb:
    -dropdb the_db  # Leading - instructs make to not abort on error
    createdb -E UTF8 the_db

3
关于“所有内容在一行”的使用还有一些微妙之处值得讨论:(传统且可移植的)所有你希望由同一个shell执行的命令必须放在同一逻辑_make_行中。 因此,exists = ...if ... fi必须用分号和反斜杠制成单个命令行,但是 createdb ... 可以愉快地保留为配方中的独立第二个命令。 - John Marshall
1
给读者:请确保在 VAR="foo" \ 语句的末尾加上 \ - redolent
2
通过使用 https://www.gnu.org/software/make/manual/html_node/One-Shell.html#One-Shell 中描述的 .ONESHELL,可以放宽“全在一行”的限制。 - sdive

0

为了完整性,使用$(eval $(call ...)的用法

在动态生成规则中使用时,您必须使用$$$$转义shell变量。

这是一个已经在"GNU Make 4.2.1"上测试过的示例:

MY_LIBS=a b c

a_objs=a1.o a2.o
b_objs=b1.o b2.o b3.o
c_objs=c1.o c2.o c3.o c4.o

default: libs

# function lib_rule(name, objs)

define lib_rule
lib$(1).a: $(2)
exit 1 | tee make.log ; test $$$${PIPESTATUS[0]} -eq 0
endef

# generate rules
$(foreach L,$(MY_LIBS),$(eval $(call lib_rule,$(L),$($(L)_objs))))

# call generated rules
libs: $(patsubst %,lib%.a,$(MY_LIBS))

# dummy object generation
%.o:%.c
touch $@

# dummy source generation
%.c:
touch $@

clean::
rm -f *.c *.o lib*.a make.log

输出结果:'make -Rr'

退出 1 | tee make.log; 测试 $ {PIPESTATUS [0]} -eq 0 制作:*** [Makefile:18: liba.a] 错误 1
管道中最后一个命令的结果是来自tee的true。您可以看到bash变量PIPESTATUS [0]从exit 1具有值false。
观察数据库:“make-Rrp”
定义lib_rule lib $(1).a:$(2) 退出1 | tee make.log; 测试 $$$$ {PIPESTATUS [0]} -eq 0 endef

...

libc.a: c1.o c2.o c3.o c4.o
exit 1 | tee make.log ; test $${PIPESTATUS[0]} -eq 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接