如何在 make check 期间定位二进制文件?
How to locate binaries during make check?
由于路径问题,我遇到了问题 运行 make check
。目前我的 shell 脚本(由 autoconf 配置)包含
prefix="@prefix@"
exec_prefix="@exec_prefix@"
PATH="@libexecdir@:$PATH"
稍后期望执行位于@libexecdir@ 中的二进制文件。这在 make install
之后起作用,但在 make check
期间不起作用。由于文件尚未安装,因此它们不在预期位置。
正确的解决方法是什么?我一定不是第一个尝试解决这个问题的人...
I must not be the first one to try to solve this.
不,虽然我稍后会描述一些可能性,但没有一个真正的惯例来处理这个问题。有些项目根本不解决它——他们要么根本不提供自动化测试,要么在安装后将测试套件设计为运行。
What is the correct solution to this?
这取决于您的程序/脚本的细节。对于在哪里可以找到它们所依赖的外部软件的高度不灵活的程序可能很难在安装前进行测试。当然,如果安装前的可测试性是一个项目目标,那么您必须在脚本中构建一些灵活性,以了解它如何定位它想要的二进制文件 运行.
这种灵活性最常见的形式可能是
- 识别可以在 运行 时间覆盖二进制文件位置的命令行选项,和/或
- 识别具有相同目的的环境变量。
根据项目的不同,这种覆盖功能可能服务于更多用例,而不仅仅是测试。
不过,只要我们讨论的是环境变量,脚本就不应该依赖可执行搜索路径来定位所需的二进制文件。 libexec 目录不应该在路径中——二进制文件应该只明确地 运行。即使在脚本内部设置它也不是一个充分的解决方案,因为它可能会从那里传播到脚本 运行s 的其他程序。此外,如果由于某种原因所需的二进制文件不在 libexec 目录中,那么您不希望意外 运行 一个恰好具有相同名称的不同二进制文件。
为了回答我自己的问题,正确的做法是 RTFM(通常是这样):
Most of these variables have values that rely on prefix or exec_prefix. It is deliberate that the directory output variables keep them unexpanded: typically ‘@datarootdir@’ is replaced by ‘${prefix}/share’, not ‘/usr/local/share’, and ‘@datadir@’ is replaced by ‘${datarootdir}’.
This behavior is mandated by the GNU Coding Standards, so that when the user runs:
‘make’
she can still specify a different prefix from the one specified to configure, in which case, if needed, the package should hard code dependencies corresponding to the make-specified prefix.
‘make install’
she can specify a different installation location, in which case the package must still depend on the location which was compiled in (i.e., never recompile when ‘make install’ is run). This is an extremely important feature, as many people may decide to install all the files of a package grouped together, and then install links from the final locations to there.
In order to support these features, it is essential that datarootdir remains defined as ‘${prefix}/share’, so that its value can be expanded based on the current value of prefix.
A corollary is that you should not use these variables except in makefiles. For instance, instead of trying to evaluate datadir in configure and hard-coding it in makefiles using e.g., ‘AC_DEFINE_UNQUOTED([DATADIR], ["$datadir"], [Data directory.])’, you should add -DDATADIR='$(datadir)' to your makefile's definition of CPPFLAGS (AM_CPPFLAGS if you are also using Automake).
Similarly, you should not rely on AC_CONFIG_FILES to replace bindir and friends in your shell scripts and other files; instead, let make manage their replacement. For instance Autoconf ships templates of its shell scripts ending with ‘.in’, and uses a makefile snippet similar to the following to build scripts like autoheader and autom4te:
edit = sed \
-e 's|@bindir[@]|$(bindir)|g' \
-e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \
-e 's|@prefix[@]|$(prefix)|g'
autoheader autom4te: Makefile
rm -f $@ $@.tmp
srcdir=''; \
test -f ./$@.in || srcdir=$(srcdir)/; \
$(edit) $${srcdir}$@.in >$@.tmp
chmod +x $@.tmp
chmod a-w $@.tmp
mv $@.tmp $@
autoheader: $(srcdir)/autoheader.in
autom4te: $(srcdir)/autom4te.in
由于路径问题,我遇到了问题 运行 make check
。目前我的 shell 脚本(由 autoconf 配置)包含
prefix="@prefix@"
exec_prefix="@exec_prefix@"
PATH="@libexecdir@:$PATH"
稍后期望执行位于@libexecdir@ 中的二进制文件。这在 make install
之后起作用,但在 make check
期间不起作用。由于文件尚未安装,因此它们不在预期位置。
正确的解决方法是什么?我一定不是第一个尝试解决这个问题的人...
I must not be the first one to try to solve this.
不,虽然我稍后会描述一些可能性,但没有一个真正的惯例来处理这个问题。有些项目根本不解决它——他们要么根本不提供自动化测试,要么在安装后将测试套件设计为运行。
What is the correct solution to this?
这取决于您的程序/脚本的细节。对于在哪里可以找到它们所依赖的外部软件的高度不灵活的程序可能很难在安装前进行测试。当然,如果安装前的可测试性是一个项目目标,那么您必须在脚本中构建一些灵活性,以了解它如何定位它想要的二进制文件 运行.
这种灵活性最常见的形式可能是
- 识别可以在 运行 时间覆盖二进制文件位置的命令行选项,和/或
- 识别具有相同目的的环境变量。
根据项目的不同,这种覆盖功能可能服务于更多用例,而不仅仅是测试。
不过,只要我们讨论的是环境变量,脚本就不应该依赖可执行搜索路径来定位所需的二进制文件。 libexec 目录不应该在路径中——二进制文件应该只明确地 运行。即使在脚本内部设置它也不是一个充分的解决方案,因为它可能会从那里传播到脚本 运行s 的其他程序。此外,如果由于某种原因所需的二进制文件不在 libexec 目录中,那么您不希望意外 运行 一个恰好具有相同名称的不同二进制文件。
为了回答我自己的问题,正确的做法是 RTFM(通常是这样):
Most of these variables have values that rely on prefix or exec_prefix. It is deliberate that the directory output variables keep them unexpanded: typically ‘@datarootdir@’ is replaced by ‘${prefix}/share’, not ‘/usr/local/share’, and ‘@datadir@’ is replaced by ‘${datarootdir}’.
This behavior is mandated by the GNU Coding Standards, so that when the user runs:
‘make’
she can still specify a different prefix from the one specified to configure, in which case, if needed, the package should hard code dependencies corresponding to the make-specified prefix.
‘make install’
she can specify a different installation location, in which case the package must still depend on the location which was compiled in (i.e., never recompile when ‘make install’ is run). This is an extremely important feature, as many people may decide to install all the files of a package grouped together, and then install links from the final locations to there.
In order to support these features, it is essential that datarootdir remains defined as ‘${prefix}/share’, so that its value can be expanded based on the current value of prefix.
A corollary is that you should not use these variables except in makefiles. For instance, instead of trying to evaluate datadir in configure and hard-coding it in makefiles using e.g., ‘AC_DEFINE_UNQUOTED([DATADIR], ["$datadir"], [Data directory.])’, you should add -DDATADIR='$(datadir)' to your makefile's definition of CPPFLAGS (AM_CPPFLAGS if you are also using Automake).
Similarly, you should not rely on AC_CONFIG_FILES to replace bindir and friends in your shell scripts and other files; instead, let make manage their replacement. For instance Autoconf ships templates of its shell scripts ending with ‘.in’, and uses a makefile snippet similar to the following to build scripts like autoheader and autom4te:
edit = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \ -e 's|@prefix[@]|$(prefix)|g' autoheader autom4te: Makefile rm -f $@ $@.tmp srcdir=''; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit) $${srcdir}$@.in >$@.tmp chmod +x $@.tmp chmod a-w $@.tmp mv $@.tmp $@ autoheader: $(srcdir)/autoheader.in autom4te: $(srcdir)/autom4te.in