Makefile-根据条件分配变量
我试图将GNU make官方文档中的示例改编为我的用例: 因此,我创建了这个原型:Makefile-根据条件分配变量,makefile,gnu-make,Makefile,Gnu Make,我试图将GNU make官方文档中的示例改编为我的用例: 因此,我创建了这个原型: libs_for_gcc="gcc libs" normal_libs="normal libs" libs= all: do_nothing @echo "all: done." do_nothing: @echo "do_nothing: done." example: @echo "
libs_for_gcc="gcc libs"
normal_libs="normal libs"
libs=
all: do_nothing
@echo "all: done."
do_nothing:
@echo "do_nothing: done."
example:
@echo "example: go ..."
@echo "example - cc: '$(CC)'"
@echo "libs_for_gcc: $(libs_for_gcc)"
@echo "normal_libs: $(normal_libs)"
@echo "libs: $(libs)"
ifeq ($(CC),gcc)
libs=$(libs_for_gcc) && echo "libs: '$$libs'"
@echo "example - libs: '$(libs)'"
else
libs=$(normal_libs) && echo "libs: '$$libs'"
@echo example - libs: $(libs)
endif
@echo "example - libs: '$(libs)'"
@echo "example: done."
test: libs += " -Ddebug"
test: example foo
bar:
@echo "bar: go ..."
ifeq (${libs}, "")
@echo "bar - libs: empty"
@echo "assigning libs"
libs=$(libs_for_gcc)
else
@echo "bar - libs: not empty"
@echo "bar - libs: '${libs}'"
endif
@echo "bar - libs: '${libs}'"
@echo "bar: done."
foo:
@echo "foo: go ..."
ifneq ("$(libs)", "")
@echo "foo - libs: not empty"
@echo "foo - libs: '$(libs)'"
else
@echo "foo - libs: empty"
endif
@echo "foo: done."
现在,当我使用$make
它只是产生:
$ make
example: go ...
example - cc: 'cc'
libs_for_gcc: gcc libs
normal_libs: normal libs
libs:
libs="normal libs"
example - libs:
example - libs: ''
example: done.
$ make bar
bar: go ...
bar - libs: not empty
bar - libs: ''
bar - libs: ''
bar: done.
$ make foo
foo: go ...
foo - libs: empty
foo: done.
我发现libs
的值没有按预期更改
当我运行make bar
目标时,它会生成:
$ make
example: go ...
example - cc: 'cc'
libs_for_gcc: gcc libs
normal_libs: normal libs
libs:
libs="normal libs"
example - libs:
example - libs: ''
example: done.
$ make bar
bar: go ...
bar - libs: not empty
bar - libs: ''
bar - libs: ''
bar: done.
$ make foo
foo: go ...
foo - libs: empty
foo: done.
这里的libs
不是空的,但里面没有任何内容
当我运行makefoo
目标时,它会生成:
$ make
example: go ...
example - cc: 'cc'
libs_for_gcc: gcc libs
normal_libs: normal libs
libs:
libs="normal libs"
example - libs:
example - libs: ''
example: done.
$ make bar
bar: go ...
bar - libs: not empty
bar - libs: ''
bar - libs: ''
bar: done.
$ make foo
foo: go ...
foo - libs: empty
foo: done.
这里libs
被理解为空的
当我看到libs
没有正确更改时,我尝试将语法更改为:
example:
# [...]
ifeq ($(CC),gcc)
libs := $(libs_for_gcc)
@echo "example - libs: '$(libs)'"
else
libs := $(normal_libs)
@echo example - libs: $(libs)
endif
但是我得到了GNU的make错误:
我找不到关于这种行为的任何文档,因此我感谢您的建议
编辑:
- 添加了
和所有
目标测试
背景: gnumake命令是打包和部署软件的工具链的重要组成部分,因此在系统管理员和DevOps工程师的日常工作中非常重要
- Debian和RPM打包使用GNU make来打包软件。
它运行
命令序列/configure&&make&&makeinstall
- Travis CI工作流使用GNU make运行TestSuite。
它运行
/configure&&make&&make测试
序列
test
的libs
,example
和foo
目标。
我还看到了有关Bash变量libs
的重要提示,该变量仅在同一行中有效:
$ make
do_nothing: done.
all: done.
$ make test
example: go ...
example - cc: 'cc'
libs_for_gcc: gcc libs
normal_libs: normal libs
libs: -Ddebug
libs="normal libs" && echo "libs: '$libs'" ;
libs: 'normal libs'
example - libs: -Ddebug
example - libs: ' -Ddebug'
example: done.
foo: go ...
foo - libs: empty
foo - libs: ' -Ddebug'
foo: done.
配方libs=$(libs\u表示_gcc)&&echo“libs:'$$libs'
显示创建了一个新的Bash变量libs
,它不会影响GNU make变量
但是,有条件的
ifneq($(libs),)
无法检测到libs
已为测试目标设置了libs。您的示例与GNU make手册中的示例之间的区别在于,在GNU make手册中,他们正在设置名为libs的make变量(他们在任何配方之外分配变量)
在您的使用中,您分配了一个名为libs
的shell变量(您在配方中分配它,并用制表符缩进)
这就是为什么在尝试使用:=
时会出现错误,因为这是一个make赋值,不是有效的shell赋值
然后在echo
中打印make变量$(libs)
,该变量根本没有设置。此外,配方的每个逻辑行都在它自己的shell中运行。因此,您运行的是等效于:
/bin/sh -c 'libs="gcc libs"'
/bin/sh -c 'echo '
因此,即使您更改了echo命令以打印shell变量(通过$$libs
),它也将是空的,因为设置它的前一个shell已退出
您希望使用与示例中相同的语法:将变量的赋值从配方中取出,并改为设置make变量:
libs_for_gcc = gcc libs
normal_libs = normal libs
ifeq ($(CC),gcc)
libs = $(libs_for_gcc)
else
libs = $(normal_libs)
endif
example:
@echo "example: go ..."
@echo "example - cc: '$(CC)'"
@echo "libs_for_gcc: $(libs_for_gcc)"
@echo "normal_libs: $(normal_libs)"
@echo "libs: $(libs)"
@echo "example - libs: '$(libs)'"
@echo "example: done."
您的示例与GNU make手册中的示例之间的区别在于,在GNU make手册中,他们正在设置一个名为libs
的make变量(他们在任何配方之外分配变量)
在您的使用中,您分配了一个名为libs
的shell变量(您在配方中分配它,并用制表符缩进)
这就是为什么在尝试使用:=
时会出现错误,因为这是一个make赋值,不是有效的shell赋值
然后在echo
中打印make变量$(libs)
,该变量根本没有设置。此外,配方的每个逻辑行都在它自己的shell中运行。因此,您运行的是等效于:
/bin/sh -c 'libs="gcc libs"'
/bin/sh -c 'echo '
因此,即使您更改了echo命令以打印shell变量(通过$$libs
),它也将是空的,因为设置它的前一个shell已退出
您希望使用与示例中相同的语法:将变量的赋值从配方中取出,并改为设置make变量:
libs_for_gcc = gcc libs
normal_libs = normal libs
ifeq ($(CC),gcc)
libs = $(libs_for_gcc)
else
libs = $(normal_libs)
endif
example:
@echo "example: go ..."
@echo "example - cc: '$(CC)'"
@echo "libs_for_gcc: $(libs_for_gcc)"
@echo "normal_libs: $(normal_libs)"
@echo "libs: $(libs)"
@echo "example - libs: '$(libs)'"
@echo "example: done."
最后,我实现了使Makefile使测试
目标工作。
关键是要理解GNU make变量可以在3种不同的上下文中赋值。
而且GNU make经常需要帮助函数,因为有一些关于条件的奇怪问题
这些问题大多未记录在案,只能通过尝试和出错以及在StackOverflow.com上搜索来解决
1.分配变量的第一个、最简单和记录最好的上下文是在全局上下文中,如官方文档和第一个答案所示。
全局变量${libs}
具有全局可见性
2.下一个不太明显但仍记录在官方文件中的上下文在目标定义行中
这里的${libs}
对测试
目标及其调用的所有依赖目标有效。
但唯一的条件是目标本身
3.分配发电机