从 Makefile 检查程序是否存在
如何检查程序是否可以从 Makefile 调用?
(也就是说,该程序应该存在于路径中或者可以调用。)
例如,它可以用于检查安装了哪个编译器。
例如,类似这个问题,但不假设底层 shell 与 POSIX 兼容。
How can I check if a program is callable from a Makefile?
(That is, the program should exist in the path or otherwise be callable.)
It could be used to check for which compiler is installed, for instance.
E.g. something like this question, but without assuming the underlying shell is POSIX compatible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
假设您有不同的目标和构建器,每个目标和构建器都需要另一组工具。
设置此类工具的列表并将它们视为强制检查其可用性的目标
例如:
Assume you have different targets and builders, each requires another set of tools.
Set a list of such tools and consider them as target to force checking their availability
For example:
检查
--version
的STDERR
输出的解决方案不适用于将版本打印到STDOUT
而不是STDERR
的程序代码>.检查程序返回代码,而不是检查其输出到STDERR
或STDOUT
。如果程序不存在,则其退出代码将始终不为零。The solutions checking for
STDERR
output of--version
does not work for programs which print their version toSTDOUT
instead ofSTDERR
. Instead of checking their output toSTDERR
orSTDOUT
, check for the program return code. If the program does not exist, its exit code will always be non zero.通过在另一个 makefile 目标中编译一个特殊的小程序来解决,其唯一目的是检查我正在寻找的任何运行时内容。
然后,我在另一个 makefile 目标中调用该程序。
如果我没记错的话,事情是这样的:
Solved by compiling a special little program in another makefile target, whose sole purpose is to check for whatever runtime stuff I was looking for.
Then, I called this program in yet another makefile target.
It was something like this if I recall correctly:
有点晚了,但这是我对这个问题的看法,
您可以在全局范围内应用它:
或在特定规则内:
或在 for 循环内
A bit late but here is my take on that question
you can either apply it globally:
or within a specific rule:
or within a for loop
甚至后来,在寻找答案时来到这里
...但后来我尝试了其他东西(在Linux上)...
--8<----8<----8<--
even later, got here while searching an answer
... but then I tried something else (on Linux) ...
--8<----8<----8<--
受到本主题以及 StackOverflow 和类似网站中其他答案的启发,我使用以下内容:
Makefile
ℹ️ (这只是
Makefile
的顶部code>'si will create self...)
sh
。CheckUtils.mk
ℹ️ 关于突出显示的错误报告:https ://github.com/highlightjs/highlight.js/issues/3878
ℹ️ 此文件的最新版本可在我在 GitLab 的一个存储库中找到。
I use the following, inspired by other answers in this topic and StackOverflow and similar sites:
Makefile
ℹ️ (This is just the top of
Makefile
's i will create self...)sh
.CheckUtils.mk
ℹ️ Bug report wrt highlighting: https://github.com/highlightjs/highlight.js/issues/3878
ℹ️ The latest version of this file is available in one-of-my repo's at GitLab. ????????
Output
make
without any changes will be similar to:nonexisting
util uncommented. will be similar to:Hope this will be useful to others, it will at least serve as a backup for myself ????
有时,您需要一个 Makefile 才能在不同的目标操作系统上运行,并且您希望构建在所需的可执行文件不在
PATH
中时尽早失败,而不是在失败之前运行很长时间。engineerchuan提供的优秀解决方案需要制定一个目标。但是,如果您有许多可执行文件要测试,并且您的 Makefile 有许多独立的目标,每个目标都需要测试,那么每个目标都需要测试目标作为依赖项。当您一次创建多个目标时,这会导致大量额外的打字和处理时间。
0xf 提供的解决方案可以在不创建目标的情况下测试可执行文件。当有多个目标可以单独或一起构建时,这可以节省大量的输入和执行时间。
我对后一种解决方案的改进是使用
which
可执行文件(Windows 中的where
),而不是依赖于--version
每个可执行文件中的选项,直接在 GNU Makeifeq
指令中,而不是定义新变量,并使用 GNU Makeerror
函数在需要时停止构建可执行文件不在${PATH}
中。例如,要测试lzop
可执行文件:如果您有多个可执行文件需要检查,那么您可能需要使用
foreach
函数和which
可执行文件:请注意使用
:=
赋值运算符,这是强制立即计算 RHS 表达式所必需的。如果您的 Makefile 更改了PATH
,那么您将需要而不是上面的最后一行:这应该为您提供类似于以下内容的输出:
Sometimes you need a Makefile to be able to run on different target OS's and you want the build to fail early if a required executable is not in
PATH
rather than to run for a possibly long time before failing.The excellent solution provided by engineerchuan requires making a target. However, if you have many executables to test and your Makefile has many independent targets, each of which requires the tests, then each target requires the test target as a dependency. That makes for a lot of extra typing as well as processing time when you make more than one target at a time.
The solution provided by 0xf can test for an executable without making a target. That saves a lot of typing and execution time when there are multiple targets that can be built either separately or together.
My improvement to the latter solution is to use the
which
executable (where
in Windows), rather than to rely on there being a--version
option in each executable, directly in the GNU Makeifeq
directive, rather than to define a new variable, and to use the GNU Makeerror
function to stop the build if a required executable is not in${PATH}
. For example, to test for thelzop
executable:If you have several executables to check, then you might want to use a
foreach
function with thewhich
executable:Note the use of the
:=
assignment operator that is required in order to force immediate evaluation of the RHS expression. If your Makefile changes thePATH
, then instead of the last line above you will need:This should give you output similar to:
我混合了 @kenorb 和 @0xF 的解决方案并得到了这个:
它工作得很好,因为如果可执行文件不可用,“命令 -v”不会打印任何内容,因此变量 DOT 永远不会被定义,您可以随时检查它想要在你的代码中。在此示例中,我抛出了一个错误,但如果您愿意,您可以做一些更有用的事情。
如果变量可用,“command -v”将执行打印命令路径、定义 DOT 变量的廉价操作。
I mixed the solutions from @kenorb and @0xF and got this:
It works beautifully because "command -v" doesn't print anything if the executable is not available, so the variable DOT never gets defined and you can just check it whenever you want in your code. In this example I'm throwing an error, but you could do something more useful if you wanted.
If the variable is available, "command -v" performs the inexpensive operation of printing the command path, defining the DOT variable.
这是你做的吗?
归功于我的同事。
is this what you did?
credit to my coworker.
使用
shell
函数以将某些内容打印到标准输出的方式调用您的程序。例如,传递--version
。GNU Make 忽略传递给
shell
的命令的退出状态。为了避免潜在的“找不到命令”消息,请将标准错误重定向到/dev/null
。然后您可以使用
ifdef
、ifndef
、$(if)
等检查结果。作为奖励,输出(例如程序版本)可能对 Makefile 的其他部分有用。
Use the
shell
function to call your program in a way that it prints something to standard output. For example, pass--version
.GNU Make ignores the exit status of the command passed to
shell
. To avoid the potential "command not found" message, redirect standard error to/dev/null
.Then you may check the result using
ifdef
,ifndef
,$(if)
etc.As a bonus, the output (such as program version) might be useful in other parts of your Makefile.
在这里清理了一些现有的解决方案...
如果您希望它更安静,您可以排除
$(info ...)
。这将快速失败。无需目标。
Cleaned up some of the existing solutions here...
The
$(info ...)
you can exclude if you want this to be quieter.This will fail fast. No target required.
我个人定义了一个
require
目标,它在所有其他目标之前运行。该目标只是一次运行所有需求的版本命令,并在命令无效时打印相应的错误消息。以下脚本的输出是
I am personally defining a
require
target which runs before all the others. This target simply runs the version commands of all requirements one at a time and prints appropriate error messages if the command is invalid.The output of the below script is
我的解决方案涉及一个小帮助程序脚本1,如果所有必需的命令都存在,它会放置一个标志文件。这样做的好处是,对所需命令的检查仅执行一次,而不是在每次
make
调用时执行。check_cmds.sh
Makefile
1 有关
command -v
技术的更多信息,请参见 此处。My solution involves a little helper script1 that places a flag file if all required commands exist. This comes with the advantage that the check for the required commands is only done once and not on every
make
invocation.check_cmds.sh
Makefile
1 More about the
command -v
technique can be found here.对我来说,以上所有答案都基于 Linux,不适用于 Windows。我是新手,所以我的方法可能并不理想。但在 Linux 和 Windows 上都适用于我的完整示例是这样的:
可选地,当我需要检测更多可以使用的工具时:
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:
optionally when I need to detect more tools I can use:
您可以使用 bash 内置命令,例如
type foo
或command -v foo
,如下所示:其中
foo
是您的程序/命令。重定向到> /dev/null
如果你想让它保持安静。You can use bash built commands such as
type foo
orcommand -v foo
, as below:Where
foo
is your program/command. Redirect to> /dev/null
if you want it silent.