Makefile 使目标依赖于二进制文件,二进制文件可能存在于$PATH上,也可能不存在于$PATH上

Makefile 使目标依赖于二进制文件,二进制文件可能存在于$PATH上,也可能不存在于$PATH上,makefile,dependencies,target,Makefile,Dependencies,Target,我想添加一个使用envdir运行程序的Make目标 ENVDIR := $(shell command -v envdir) serve: | $(ENVDIR) $(ENVDIR) /usr/local/myservice/env python -m SimpleHTTPServer 8000 这个想法是,如果用户没有安装envdir,它将为他们安装envdir。我需要管道角色,因为我并不总是希望它运行;我只想看到它的任何版本。不幸的是,我无法很好地预测envdir将安装到何处 U

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

ENVDIR := $(shell command -v envdir)

serve: | $(ENVDIR)
    $(ENVDIR) /usr/local/myservice/env python -m SimpleHTTPServer 8000
这个想法是,如果用户没有安装envdir,它将为他们安装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)我的“install envdir”目标实际上没有运行,b)在运行之后,$(envdir)仍然设置为空字符串,因此将其加载到服务目标中不起作用

是否有方法a)让安装目标运行,即使ENVDIR未定义,以及b)在“install ENVDIR”目标运行结束时重新定义变量的值

请不要回答“为什么您要使用envdir”-我在使用我所依赖的各种不同的二进制文件时遇到了这个问题,这恰好是一个易于共享的示例。

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

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

因此,如果
shell
函数扩展为空字符串,则将替换
envdir
(GNU make 3.81中添加了
函数)。这可能足以解决您的所有问题,因为在安装之后,
envdir
命令现在将出现在路径上,因此您不需要完整的路径。

您可以在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命令前面的double
$
,它阻止make在读取时扩展此命令…)


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

为什么不使用条件来区分已安装和未安装的情况
ifeq($(ENVDIR),)…否则…endif
可能会成功。在
envdir
安装方法的末尾,您可以简单地重新调用make,而不是试图更改
envdir
变量的值(我知道,递归make是不好的,但坏的东西有时非常有用)。