检查Makefile中是否存在程序

Pro*_*ica 94 makefile gnu-make

如何检查程序是否可以从Makefile中调用?

(也就是说,程序应存在于路径中或以其他方式可调用.)

例如,它可用于检查安装的编译器.

例如类似这个问题,但不假设底层shell是POSIX兼容的.

Jon*_*ham 59

有时您需要一个Makefile才能在不同的目标操作系统上运行,如果所需的可执行文件不在,PATH而不是在失败之前运行很长时间,您希望构建早期失败.

工程师提供的出色解决方案需要制定目标.但是,如果要测试许多可执行文件并且Makefile有许多独立目标,每个目标都需要测试,那么每个目标都需要将测试目标作为依赖项.当您一次制作多个目标时,这会产生大量额外的输入和处理时间.

0xf提供的解决方案可以在不创建目标的情况下测试可执行文件.当有多个目标可以单独或一起构建时,这可以节省大量的输入和执行时间.

我对后一种解决方案的改进是使用which可执行文件(where在Windows中),而不是依赖--version于每个可执行文件中的选项,直接在GNU Make ifeq指令中,而不是定义一个新变量,并使用GNU Make error如果不存在所需的可执行文件,则停止构建的函数${PATH}.例如,要测试lzop可执行文件:

 ifeq (, $(shell which lzop))
 $(error "No lzop in $(PATH), consider doing apt-get install lzop")
 endif
Run Code Online (Sandbox Code Playgroud)

如果要检查多个可执行文件,则可能需要使用foreach带有which可执行文件的函数:

EXECUTABLES = ls dd dudu lxop
K := $(foreach exec,$(EXECUTABLES),\
        $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
Run Code Online (Sandbox Code Playgroud)

请注意使用:=赋值运算符以强制立即评估RHS表达式.如果您的Makefile更改了PATH,那么您将需要:而不是上面的最后一行:

        $(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH")))
Run Code Online (Sandbox Code Playgroud)

这应该给你类似于的输出:

ads$ make
Makefile:5: *** "No dudu in PATH.  Stop.
Run Code Online (Sandbox Code Playgroud)

  • 小心使用 ifeq 的 TABS 缩进,这是一种规则语法!它必须没有标签。很难过。/sf/answers/1485888141/ (6认同)
  • 如果使EXECUTABLES所有变量(即LS CC LD),并使用$($(exec)),则可以将其传递以从环境或其他makefile中无缝进行。交叉编译时很有用。 (2认同)
  • 运行“ifeq (, $(shell which lzop))” =/ (2认同)
  • 在Windows上,使用`where my_exe 2> NUL`而不是`which`. (2认同)
  • 如果您使用的是“Bash”,则无需对“which”进行外部调用。请改用内置的“命令 -v”。[更多信息](/sf/answers/47404871/)。 (2认同)

men*_*kgs 41

我混合了@kenorb和@ 0xF的解决方案,得到了这个:

DOT := $(shell command -v dot 2> /dev/null)

all:
ifndef DOT
    $(error "dot is not available please install graphviz")
endif
    dot -Tpdf -o pres.pdf pres.dot 
Run Code Online (Sandbox Code Playgroud)

它精美的作品,因为如果可执行文件不可用"命令-v"不打印任何东西,所以变量DOT永远不会被定义,你可以检查它,只要你在你的代码需要.在这个例子中,我抛出了一个错误,但如果你愿意,你可以做一些更有用的事情.

如果变量可用,"command -v"执行打印命令路径的廉价操作,定义DOT变量.

  • @JulienPalard我相信你错了:[posix](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html)需要`command`工具(包括`-v`选项)另一方面,`哪个'没有标准化的行为(我知道)并且有时是彻头彻尾的[无法使用](http://stackoverflow.com/a/677212/117814) (7认同)
  • "命令"通常不起作用的原因是*不是因为它缺席*,而是因为GNU Make的[特殊优化](/sf/answers/1228517041/):如果命令是"足够简单"它将绕过壳; 不幸的是,除非你稍微破坏命令,否则内置插件有时会无法工作. (6认同)
  • 至少在某些系统(即Ubuntu 14.04)中,`$(shell命令-v dot)`失败并出现`make:command:Command not found`.要解决此问题,请将stderr输出重定向到/ dev/null:`$(shell命令-v dot 2>/dev/null)`.[说明](http://stackoverflow.com/a/12991757/882918) (4认同)
  • `command`是一个内置的bash,为了更方便,考虑使用`which`? (2认同)
  • `command -v`需要类似POSIX的shell环境.如果没有cygwin或类似的仿真,这将无法在Windows上运行. (2认同)
  • 只是想警告这不作为配方的一部分,因为`ifndef`总是被评估.在这方面,工程师的答案更好. (2认同)

eng*_*uan 33

这是你做的吗?

check: PYTHON-exists
PYTHON-exists: ; @which python > /dev/null
mytarget: check
.PHONY: check PYTHON-exists
Run Code Online (Sandbox Code Playgroud)

归功于我的同事.


0xF*_*0xF 21

使用该shell函数以打印标准输出的方式调用程序.例如,通过--version.

GNU Make忽略传递给的命令的退出状态shell.为避免潜在的"未找到命令"消息,请将标准错误重定向到/dev/null.

然后,你可以检查结果使用ifdef,ifndef,$(if)等.

YOUR_PROGRAM_VERSION := $(shell your_program --version 2>/dev/null)

all:
ifdef YOUR_PROGRAM_VERSION
    @echo "Found version $(YOUR_PROGRAM_VERSION)"
else
    @echo Not found
endif
Run Code Online (Sandbox Code Playgroud)

作为奖励,输出(例如程序版本)可能在Makefile的其他部分中很有用.

  • @Matthias009,当我测试 GNU Make v4.2.1 时,使用 `ifdef` 或 `ifndef` (如接受的答案中所示)仅当正在评估的变量立即设置(`:=`)而不是延迟设置(`=` )。然而,使用立即设置变量的缺点是它们在声明时评估,而延迟设置变量在调用时评估。这意味着即使 Make 仅运行从不使用这些变量的规则,您也将使用 `:=` 执行变量命令!您可以通过使用 `=` 和 `ifneq ($(MY_PROG),)` 来避免这种情况 (3认同)

Flo*_*low 8

我的解决方案涉及一个小助手脚本1,如果存在所有必需的命令,则放置一个标志文件.这样做的好处是只检查所需命令一次,而不是每次make调用.

check_cmds.sh

#!/bin/bash

NEEDED_COMMANDS="jlex byaccj ant javac"

for cmd in ${NEEDED_COMMANDS} ; do
    if ! command -v ${cmd} &> /dev/null ; then
        echo Please install ${cmd}!
        exit 1
    fi
done

touch .cmd_ok
Run Code Online (Sandbox Code Playgroud)

Makefile文件

.cmd_ok:
    ./check_cmds.sh

build: .cmd_ok target1 target2
Run Code Online (Sandbox Code Playgroud)

1有关该command -v技术的更多信息,请点击此处.

  • 我只是测试它,它的工作原理,因为你没有提供任何不适合你的提示(bash脚本或Makefile代码)或任何错误消息,我无法帮助你找到问题. (2认同)

mpe*_*pen 7

在这里清理了一些现有的解决方案......

REQUIRED_BINS := composer npm node php npm-shrinkwrap
$(foreach bin,$(REQUIRED_BINS),\
    $(if $(shell command -v $(bin) 2> /dev/null),$(info Found `$(bin)`),$(error Please install `$(bin)`)))
Run Code Online (Sandbox Code Playgroud)

$(info ...)如果您希望它更安静,您可以排除.

这将很快失败.无需目标.


Vit*_*tik 6

For me all above answers are based on linux and are not working with windows. I'm new to make so my approach may not be ideal. But complete example that works for me on both linux and windows is this:

# detect what shell is used
ifeq ($(findstring cmd.exe,$(SHELL)),cmd.exe)
$(info "shell Windows cmd.exe")
DEVNUL := NUL
WHICH := where
else
$(info "shell Bash")
DEVNUL := /dev/null
WHICH := which
endif

# detect platform independently if gcc is installed
ifeq ($(shell ${WHICH} gcc 2>${DEVNUL}),)
$(error "gcc is not in your system PATH")
else
$(info "gcc found")
endif
Run Code Online (Sandbox Code Playgroud)

optionally when I need to detect more tools I can use:

EXECUTABLES = ls dd 
K := $(foreach myTestCommand,$(EXECUTABLES),\
        $(if $(shell ${WHICH} $(myTestCommand) 2>${DEVNUL} ),\
            $(myTestCommand) found,\
            $(error "No $(myTestCommand) in PATH)))
$(info ${K})        
Run Code Online (Sandbox Code Playgroud)


Rud*_*haw 6

我个人定义了一个require先于所有其他目标运行的目标。这个目标只是一次运行一个所有需求的版本命令,如果命令无效,则打印适当的错误消息。

all: require validate test etc

require:
    @echo "Checking the programs required for the build are installed..."
    @shellcheck --version >/dev/null 2>&1 || (echo "ERROR: shellcheck is required."; exit 1)
    @derplerp --version >/dev/null 2>&1 || (echo "ERROR: derplerp is required."; exit 1) 

# And the rest of your makefile below.
Run Code Online (Sandbox Code Playgroud)

以下脚本的输出是

Checking the programs required for the build are installed...
ERROR: derplerp is required.
makefile:X: recipe for target 'prerequisites' failed
make: *** [prerequisites] Error 1
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

45328 次

最近记录:

5 年,11 月 前