Autotools 处理本地与已安装数据文件的方法

Posted

技术标签:

【中文标题】Autotools 处理本地与已安装数据文件的方法【英文标题】:Autotools way to handle local vs installed data file 【发布时间】:2021-01-02 20:30:29 【问题描述】:

假设一个程序<somepath>/src/program.c 在运行时从<somepath>/data/datafile 读取数据。如果Makefile.am 在构建过程中通过AM_CPPFLAGS=-DDATADIR=\"@datarootdir@\",则安装的二进制文件可以成功找到/usr/local/share 中的数据文件。到现在为止还挺好。问题是,Autotools 检测源代码的方式是什么,以便安装的二进制文件从 datarootdir 读取,但本地的、卸载的二进制文件从(项目本地,而不是系统)<somepath>/data/datafile 读取?

【问题讨论】:

【参考方案1】:

没有专门的 Autotools 方法来执行此操作 - 这取决于您的具体情况。例如,常见的解决方案是首先在构建二进制文件位置的相对路径中查找数据文件,或者使用 UNINSTALLED_PATH 环境变量覆盖它所查找的安装路径。

【讨论】:

感谢您的建议。实际上,该程序目前采用第一种策略,但我无法找到一种可靠、可移植的方式来实现这一点,因为可能会从其位置之外调用二进制文件。作为一种临时措施,我可以使用一些不可靠的 argv[0] 启发式方法,或者从不可移植的 /proc/ 中读取。用一种 POSIX 方法来确定进程的二进制路径似乎是一个长期存在的问题。看来ideia这个环境变量更有前途。【参考方案2】:

什么是 Autotools 方法检测源代码,以便 已安装的二进制读取表单 datarootdir,但本地已卸载 从(项目本地,而不是系统)读取二进制文件 <somepath>/data/datafile?

您认为程序将如何在运行时识别它是否已安装?对于从 C 源代码编译的程序,安装只是意味着将可执行文件复制到其目标目录(默认为<prefix>/bin)。是同一个程序,没有万无一失的方法可以判断是否是从预定的安装目录加载的。*

无论如何,Autotools 都是用于创建构建系统的工具。它们在测试已卸载程序方面有一些有用的功能,但没有专门针对此的。

解决这个问题的一个非常常见的方法是提供一种方法来告诉程序明确地使用哪个目录(或者使用哪个配置文件,或者哪个etc使用)。即使主要动机是支持构建时测试,这样做的能力也有一些普遍用途。支持此类事情的更好方法包括

命令行选项 环境变量 运行时配置指令(如果您的程序在运行时读取配置文件) 输入数据(如果您可以灵活地使输入格式支持此)

这些并不是相互排斥的,尽管实现所有这些肯定是矫枉过正的。其中一些可以通过包装脚本使用,这可以掩盖普通用户的详细信息。您必须确定对您的情况有意义的细节,但为了获得良好的灵活性而不会过火,我可能会执行以下操作:该程序使用第一个适用的 ...

    命令行选项 (也许)输入数据 (可能)环境变量或配置文件 默认编译基于datarootdir

如果您选择编写包装脚本,那么它可能会确定自己的位置并使用上述之一指定相对于该目录的数据目录。但是,我敦促您不要尝试自动检测程序是否已安装,以此来选择在运行时使用哪些目录。


*我的意思是字面意思。有一些方法可以捕捉到大多数情况,但据我所知,没有一种是不能被愚弄的。

【讨论】:

您直截了当:“构建时测试”(我自己应该这样说)。实际上,二进制路径的运行时检测并不是寻求的解决方法。我正在考虑包装脚本行中的一些内容,灵感来自 libtool 的策略(测试脚本,安装二进制文件)。但是,是的,在这种情况下它是矫枉过正的。非常感谢您的详细解释。【参考方案3】:

简而言之,最初的问题是关于实现程序的构建时测试的常规方法,在构建过程中,应该从项目树中的路径(例如,~/home/bar)读取数据文件,安装后,应从默认系统的数据路径(例如 /usr/share)读取。

根据建议的方法和进一步的研究,实施的解决方案可以总结如下。

Makefile.am:

in_PROGRAMS = foo.bin 

foo_bin_SOURCES = main.c 
    
bin_SCRIPTS = foo

foo: foo.sh
        cp $< $@

clean-local:
        rm -f foo

install-exec-hook: 
        cd $(DESTDIR)/$(bindir) && mv foo.bin foo

uninstall-hook:
        rm -f $(DESTDIR)/$(bindir)/foo

EXTRA_DIST = foo.sh

构建软件时,会创建一个辅助 shell 脚本 foo(在模板 foo.sh 之外),它使用适当的命令行参数调用真正的二进制文件 foo.bin,以从项目树加载数据。

foo.sh:

#!/bin/sh

ARG="$0"
PROGRAM="$(dirname $ARG)/foo.bin"

if [ -f "$PROGRAM" ]; then
    if [ -z "$1" ] ; then
        ./$PROGRAM -data_dir /project/data/path
    else
        ./$PROGRAM "$1"
    fi
else
    echo "Program not found."
    exit 1
fi

安装软件时,会触发install-exec-hook 将二进制文件从foo.bin 重命名为foo。如果没有其他选项,它应该从系统数据路径读取数据。

【讨论】:

以上是关于Autotools 处理本地与已安装数据文件的方法的主要内容,如果未能解决你的问题,请参考以下文章

Linux autotools有啥用

Autotools 套件错误放置“man”文件导致安装失败

Autotools:PROGRAMS 安装路径

当电子 ABI 与已安装节点不同时,无法生成 TypeORM 迁移

automake - 使用 autotools 工具集

automake:autotools 工具集使用速成