2017-08-31 29 views
5

我想添加一个Make目标,该目标使用envdir运行程序。

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

为什么不使用条件来区分已经安装了'envdir'的情况和它不是的情况? 'ifeq($(ENVDIR),)... else ... endif'可能会成功。在'envdir'安装配方结束时,您可以简单地重新调用make,而不是试图改变'ENVDIR'变量的值(我知道,*递归make是坏的,但坏事有时非常有用)。 –

回答

0

对于“空”的问题,你可以这样做:

ENVDIR := $(or $(shell command -v envdir),envdir) 

因此,如果shell功能扩展为空字符串,envdir将被取代(在GNU添加or功能使3.81)。这可能足以解决您的所有问题,因为安装后envdir命令现在将显示在PATH上,因此您不需要完整路径。

1

你可以完全做到这一点的壳像这样:

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 > [email protected] || (install envdir > /dev/null && echo newEnvDirPath > [email protected]) 
    $(eval ENVDIR:=$$(cat [email protected])) 

shell: | .ENVDIR 

如果文件.ENVDIR不存在,它将运行的配方,这要么安装路径写入.ENVDIR,或者它将安装并将新路径写入.ENVDIR。无论哪种方式,当配方行结束时,.ENVDIR将包含可执行文件路径。目标然后运行$(eval)来设置ENVDIR。注意调用eval会导致makefile被重新编译,这并不理想,但应该只在系统上执行一次。 (还要注意cat命令前面的双重$$,这会阻止make在读取时扩展它)。

或者,如果.ENVDIR确实存在,它将读取该文件以确定尝试使用哪个envdir。检查在下一行完成,以确保该版本在系统上仍然存在,如果不存在,则删除该文件,迫使其重新创建。

相关问题