如何使用 autotools 设置项目,以便生成的可执行文件可以看到所需的二进制文件?

How do I setup a project with autotools so resulting executables can see required binary files?

我正在使用 c 编写一些针对 allegro 的代码构建并使用 autotools 来处理构建系统。问题是代码正在尝试 拉入位图,我不确定如何正确处理 使用自动工具。

我的项目布局:

allegro-learning/
    Makefile.am
    README
    configure.ac
    src/
        stargate.c
        stargate.bmp

stargate.c 中的代码使用以下代码拉入位图:

stargate = load_bitmap("stargate.bmp", NULL);

allegro-learning/configure.ac 的内容:

AC_PREREQ([2.69])
AC_INIT([allegro-learning], [1.0], [itsjustme@gmail.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AM_PROG_CC_C_O
PKG_CHECK_MODULES([ALLEGRO], [allegro >= 4.2.3])
AC_CHECK_HEADERS([stdio.h])
AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

allegro-learning/Makefile.am 的内容:

SUBDIRS = src
dist_doc_DATA = README

allegro-learning/src/Makefile.am 的内容:

bin_PROGRAMS = stargate

stargate_SOURCES = stargate.c
stargate_CFLAGS = $(ALLEGRO_CFLAGS) 
stargate_LDFLAGS = $(ALLEGRO_LIBS) 

当我使用 autotools 构建和安装时:

# autoreconf --install
# ./configure --prefix=$HOME/usr
# make
# make install

和 运行 生成的 stargate 可执行文件出现所有段错误。破解它 用 GDB 打开显示失败在我上面突出显示的行(来自 stargate.c),它拉入 stargate.bmp。

然而,当我去 allegro-learning/src 并构建 直接 w/o 使用 autotools:

# cd allegro-learning/src
# gcc `pkg-config allegro --cflags --libs` -o stargate stargate.c

运行nig 可执行文件工作正常。这让我相信我没有使用 autotools 正确设置项目来安装位图,以便可执行文件可以找到它们 post-install.

正确的做法是什么?

我已经咨询过 Autotools ,当使用带有 java 的 autotools 时安装 jar 看起来是一个类似的问题,你有 .jar 文件也必须安装并可用于执行代码看看。但是他的例子嵌入了一个更大的项目,这让我很困惑。

我也看过 Data Files With Automake 但我仍然不确定我应该如何修改我的项目以便生成的可执行文件可以找到位图。事实上,我不确定 stargate.bmp 在 autotools 世界中是否符合 'data file' 的条件。也许有一种完全不同的方法来处理这种情况?

有关如何处理此类情况的任何具体指导 非常感谢。

在这里回答我自己的问题。在 automake mailing lists 上进行了一些互动后,我找到了问题的解决方案并进行了以下调整:

到allegro-learning/src/Makefile.am:

stargatedir = $(datadir)/stargate
stargate_DATA = stargate.bmp
stargate_SOURCES = stargate.c
stargate_CFLAGS = $(ALLEGRO_CFLAGS) -DPKGDATADIR=\"$(stargatedir)\"
stargate_LDFLAGS = $(ALLEGRO_LIBS) 

我向 stargate.c 添加了以下内容:

#include <stdio.h>

// for nice string concatenation:
#define Sasprintf(write_to,  ...) {           \
    char *tmp_string_for_extend = (write_to); \
    asprintf(&(write_to), __VA_ARGS__);       \
    free(tmp_string_for_extend);              \
}

char* addImageBaseDir(char* filename) {
  char *abspath = NULL;
  Sasprintf(abspath, PKGDATADIR);
  Sasprintf(abspath, "%s%s%s", abspath, "/", "stargate.bmp");
  return abspath;
}

现在我替换原来的,

stargate = load_bitmap("stargate.bmp", NULL);

stargate = load_bitmap(addImageBaseDir("stargate.bmp"), NULL)

并且使用自动工具构建现在工作得很好。

这不是您问题的直接答案,但作为设置已知数据位置的替代方法,您可能需要考虑将数据简单地编译到您的可执行文件中,这样它就不需要外部文件找到。

您可以使用 objcopy -I binary -O elf64-x86-64 -B i386 stargate.bmp stargate.o 来生成包含 stargate.bmp 数据的目标文件(当然,如果您想要可移植性,则必须适当调整输出架构)。然后,如果您 link 那些对象文件到可执行文件中,符号 _binary_stargate_bmp_start_binary_stargate_bmp_end 将可用于指出数据的开始和结束,可用于传递给您的图像加载函数。例如,您可以使用如下数据生成 FILE *

extern char _binary_stargate_bmp_start, _binary_stargate_bmp_end;
FILE *imgstream = fmemopen(&_binary_stargate_bmp_start, &_binary_stargate_bmp_end - &_binary_stargate_bmp_start, "r");