我想添加一个使用envdir运行程序的Make目标。
ENVDIR := $(shell command -v envdir)
serve: | $(ENVDIR)
$(ENVDIR) /usr/local/myservice/env python -m SimpleHTTPServer 8000
这个想法是,如果用户没有安装envdir,它将为它们安装它。我需要管道角色,因为我并不总是希望它能够运行;我只是希望它的任何版本都存在。不幸的是,我无法很好地预测将安装envdir的位置。
UNAME := $(shell uname)
$(ENVDIR):
ifeq ($(UNAME), Darwin)
brew install daemontools
endif
ifeq ($(UNAME), Linux)
sudo apt-get install daemontools
endif
# Add other operating systems here as appropriate...
我遇到的另一个问题是,如果用户没有安装envdir,则变量将计算为空字符串。所以a)我的“安装envdir”目标实际上没有运行,并且b)运行后,$(ENVDIR)仍然设置为空字符串,因此将其加载到服务目标中不起作用。
有没有办法a)让安装目标运行,即使ENVDIR未定义,b)在“安装envdir”目标运行结束时重新定义变量的值?
请不要回答“你为什么使用envdir” - 我遇到了我依赖的各种不同二进制文件这个问题,这恰好是一个容易分享的例子。
答案 0 :(得分:1)
您可以在shell中完全执行此操作:
ENVDIR := $( command -v envdir 2> /dev/null || ( install envdir > /dev/null && echo newEnvDirPath ) )
这是最简单的,但会导致安装envdir
,即使当前目标不需要它。如果你想在目标中使用它,你可以这样做:
ENVDIR:=$(cat .ENVDIR 2> /dev/null)
$(type -v $(ENVDIR) > /dev/null || rm .ENVDIR )
.ENVDIR:
command -v envdir 2> /dev/null > $@ || ( install envdir > /dev/null && echo newEnvDirPath > $@)
$(eval ENVDIR:=$$(cat $@))
shell: | .ENVDIR
如果文件.ENVDIR
不存在,它将运行配方,该配方将安装路径写入.ENVDIR
,或者它将安装并写入.ENVDIR
的新路径。无论哪种方式,当配方行完成时,.ENVDIR
将包含可执行路径。然后,目标会运行$(eval)
来设置ENVDIR
。请注意,调用eval会导致重新分析makefile,这不是理想的,但应该只在系统上执行一次。 (另请注意cat命令前面的双$$
,这会阻止make在读取时扩展它...)。
或者,如果.ENVDIR
确实存在,它将读取文件以确定尝试使用哪个envdir。在下一行上进行检查以确保该版本仍然存在于系统上,如果没有,则删除该文件,强制重新创建该文件。
答案 1 :(得分:0)
对于"空"问题你可以这样做:
ENVDIR := $(or $(shell command -v envdir),envdir)
这样,如果shell
函数扩展为空字符串,envdir
将被替换(or
函数在GNU make 3.81中添加)。这可能足以解决您的所有问题,因为安装后envdir
命令现在将显示在PATH上,因此您不需要完整路径。