我想定义一个shell函数
#!/bin/sh
test ()
{
do_some_complicated_tests $1 $2;
if something; then
build_thisway $1 $2;
else
build_otherway $1 $2;
fi
}
以这种方式我可以在我的Makefile的每个规则中使用它,例如:
foo: bar
test foo baz
要清楚,我希望shell函数成为Makefile的一部分。这样做最优雅的方法是什么?如果您可以在不递归调用make的情况下执行此操作,则可获得奖励积分。
背景:
我的实际问题是make -n
产生了一个非常长且不可读的输出。每个规则使用几乎相同的不可读shell命令序列,并且有许多规则。上述解决方案将使make -n
的输出更有用。
答案 0 :(得分:10)
此解决方案不依赖于外部临时文件,也不会强迫您修改SHELL
变量。
TESTTOOL=sh -c '\
do_some_complicated_tests $$1 $$2; \
if something; then
build_thisway $$1 $$2;
else
build_otherway $$1 $$2;
fi' TESTTOOL
ifneq (,$(findstring n,$(MAKEFLAGS)))
TESTTOOL=: TESTTOOL
endif
foo: bar
${TESTTOOL} foo baz
ifneq…endif
块检查命令行上的-n
标志,并将TESTTOOL
的扩展设置为: TESTTOOL
,易于阅读并且可以安全执行。< / p>
最好的解决方案是将shell函数转换为实际程序,如果这是一个选项。
答案 1 :(得分:6)
由于问题标记为gnu-make
,您可能对Beta的解决方案感到满意,但我认为最佳解决方案是1)将函数重命名为test
以外的其他函数(避免使用{{1}这样的名称}和ls
以及);为了讨论的目的,我们假设您已将其重命名为cd
,2)只需编写一个名为foo
的脚本并从Makefile中调用它。如果你真的想在Makefile中定义一个shell函数,只需为每个规则定义它:
foo
并非您必须在F = foo() { \
do_some_complicated_tests $$1 $$2; \
if something; then \
build_thisway $$1 $$2; \
else \
build_otherway $$1 $$2; \
fi \
}
all: bar
@$(F); foo baz bar
的定义的每一行上都有续行,并且foo
都已转义,以便将它们传递给shell。
答案 2 :(得分:5)
我认为这不符合“优雅”的要求,但似乎可以做你想做的事情:
##
## --- Start of ugly hack
##
THIS_FILE := $(lastword $(MAKEFILE_LIST))
define shell-functions
: BEGIN
# Shell syntax here
f()
{
echo "Here you define your shell function. This is f(): $@"
}
g()
{
echo "Another shell function. This is g(): $@"
}
: END
endef
# Generate the file with function declarations for the shell
$(shell sed -n '/^: BEGIN/,/^: END/p' $(THIS_FILE) > .functions.sh)
# The -i is necessary to use --init-file
SHELL := /bin/bash --init-file .functions.sh -i
##
## -- End of ugly hack
##
all:
@f 1 2 3 4
@g a b c d
运行它会产生:
$ make -f hack.mk
Here you define your shell function. This if f(): 1 2 3 4
Another shell function. This is g(): a b c d
使用-n
运行它会产生:
$ make -f hack.mk -n
f 1 2 3 4
g a b c d
这取决于define
和endef
之间定义的宏在实际使用之前根本不被make
解释的事实,因此您可以直接使用shell语法而不是不需要用反斜杠结束每一行。当然,如果你调用shell-functions
宏,它会爆炸。
答案 3 :(得分:4)
有些东西告诉我你最好过滤make -n
的输出,但你问的是可能的:
define test
@echo do some tests with $(1) and $(2); \
SOMETHING=$(1)_3 ; \
if [ $$SOMETHING == foo_3 ]; then \
echo build this way $(1) $(2); \
else \
echo build another way $(1) $(2) ; \
fi
endef
someTarget:
$(call test,foo,bar)
someOtherTarget:
$(call test,baz,quartz)
答案 4 :(得分:4)
这真的是贫民窟,但无论如何。我使用zsh,但我确定有bash和sh等价物。
<强>生成文件:强>
export ZDOTDIR := ./
SHELL := /usr/bin/env zsh
default:
f
.zshenv,与Makefile相同的目录:
f () { echo 'CHECK OUT THIS AWESOME FUNCTION!' }
ZDOTDIR变量使zsh在dotfiles的当前目录中查找。然后你只需在.zshenv
中坚持你想要的东西。
$ make
f
CHECK OUT THIS AWESOME FUNCTION!
答案 5 :(得分:3)
<强> TL; DR:强>
在你的makefile中:
SHELL=bash
BASH_FUNC_command%%=() { ... }
export BASH_FUNC_command%%
答案很长
我在非制作语境中使用bash做了类似的事情。这里有效。
我在bash中声明了我的shell函数,然后使用:
导出它们export -f function-name
如果在您的情况下从make调用相同的shell作为子进程,则它们自然可用。
示例:
$ # define the function
$ something() { echo do something here ; }
$ export -f something
$ # the Makefile
$ cat > Makefile <<END
SHELL=bash
all: ; something
END
$
试一试
$ make
something
do something here
$
这在环境中看起来如何?
$ env | grep something
BASH_FUNC_something%%=() { echo do something here
所以你的问题是如何在Makefile中设置环境变量。模式似乎是BASH_FUNC_ function-name %% =(){ function-body }
直接在make
中那么这对你有什么用?试试这个makefile
SHELL=bash
define BASH_FUNC_something-else%%
() {
echo something else
}
endef
export BASH_FUNC_something-else%%
all: ; something-else
并尝试一下:
$ make
something-else
something else
在Makefile中有点难看但对 make -n
没有任何丑陋答案 6 :(得分:2)
为什么不在Makefile中使用.ONESHELL并定义诸如bash函数之类的Makefile函数:
jeromesun@km:~/workshop/hello.test$ tree
.
├── Makefile
└── mkfiles
└── func_test.mk
1 directory, 2 files
jeromesun@km:~/workshop/hello.test$ cat Makefile
.ONESHELL:
-include mkfiles/*.mk
test:
@$(call func_test, one, two)
jeromesun@km:~/workshop/hello.test$ cat mkfiles/func_test.mk
.ONESHELL:
define func_test
echo "func_test parameters: 0:$0, 1:$1, 2:$2"
if [ ! -d abc ]; then
mkdir abc
echo "abc not found"
else
echo "abc found"
fi
endef
jeromesun@km:~/workshop/hello.test$
结果:
jeromesun@km:~/workshop/hello.test$ make test
func_test parameters: 0:func_test, 1: one, 2: two
abc not found
jeromesun@km:~/workshop/hello.test$ make test
func_test parameters: 0:func_test, 1: one, 2: two
abc found