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)
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变量.
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的其他部分中很有用.
我的解决方案涉及一个小助手脚本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
技术的更多信息,请点击此处.
在这里清理了一些现有的解决方案......
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 ...)
如果您希望它更安静,您可以排除.
这将很快失败.无需目标.
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)
我个人定义了一个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 次 |
最近记录: |