【问题标题】:How do I use shell variables in Makefile actions?如何在 Makefile 操作中使用 shell 变量?
【发布时间】:2012-11-26 07:43:26
【问题描述】:

我在 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

【问题讨论】:

    标签: bash makefile


    【解决方案1】:

    至少有两个考虑因素。 $() 引用了一个 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
    

    【讨论】:

    • 还有一些关于“all on one line”的细微差别值得讨论:(传统上和可移植的)您希望由 同一个 shell 执行的所有内容都必须在一个逻辑 make 行上。所以exists=...if ... fi 必须用分号和反斜杠组成一个命令行,但createdb ... 可以很高兴地作为单独的第二个命令保留在配方中。
    • 致读者:确保将\ 放在VAR="foo" \ 语句的末尾
    • 可以使用.ONESHELL: 放松“all in one line”,如gnu.org/software/make/manual/html_node/One-Shell.html#One-Shell 中所述
    【解决方案2】:

    为了完整起见,$(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

    默认:库

    # function lib_rule(name, objs)

    定义 lib_rule
    lib$(1).a: $(2)
    exit 1 |三通 make.log ;测试 $$$${PIPESTATUS[0]} -eq 0
    endef

    # 生成规则
    $(foreach L,$(MY_LIBS),$(eval $(call lib_rule,$(L),$($(L)_objs))))

    #调用生成的规则
    库:$(patsubst %,lib%.a,$(MY_LIBS))

    # 虚拟对象生成
    %.o:%.c
    touch $@

    # 虚拟源生成
    %.c:
    touch $@

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

    输出:'make -Rr'

    退出 1 |三通 make.log ;测试 ${PIPESTATUS[0]} -eq 0
    make: *** [Makefile:18: liba.a] 错误 1

    管道中最后一个命令的结果是来自 teetrue。您可以从 exit 1

    看到 bash 变量 PIPESTATUS[0] 的值为 false

    观察数据库:'make -Rrp'

    定义 lib_rule
    lib$(1).a: $(2)
    exit 1 |三通 make.log ;测试 $$$${PIPESTATUS[0]} -eq 0
    endef

    ...

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 2017-02-18
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 2023-01-11
      相关资源
      最近更新 更多