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

问题描述

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

解决方法

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

,

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

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

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

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

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

这些并不相互排斥,尽管实施所有这些肯定会过大。其中一些可以通过包装脚本使用,这可以掩盖普通用户的细节。您必须决定对您的案例有意义的具体细节,但为了获得良好的灵活性而不会过火,我可能会执行以下操作:该程序使用 ...

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

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


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

,

简而言之,最初的问题是关于实现程序构建时测试的传统方法,该程序在构建期间应该从项目树中的路径(例如,~/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。如果没有其他选项,它应该从系统数据路径读取数据。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...