【问题标题】:How do I setup a project with autotools so resulting executables can see required binary files?如何使用自动工具设置项目,以便生成的可执行文件可以看到所需的二进制文件?
【发布时间】:2015-03-14 11:51:17
【问题描述】:

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

我的项目布局:

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) 

当我使用自动工具构建和安装时:

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

并运行生成的星际之门可执行文件中的所有段错误。破解它 open with GDB 显示失败在我上面突出显示的行(来自stargate.c),它引入了stargate.bmp。

但是,当我只是去 allegro-learning/src 并构建 直接不使用自动工具:

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

运行可执行文件工作正常。这让我相信我没有使用自动工具正确设置项目来安装位图,因此可执行文件可以在安装后找到它们。

这样做的正确方法是什么?

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

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

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

【问题讨论】:

    标签: c autotools autoconf automake allegro


    【解决方案1】:

    在这里回答我自己的问题。在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)
    

    现在使用 autotools 构建可以正常工作。

    【讨论】:

    • 仅作记录,您的第一个 Sasprintf 将执行 free(NULL),这在标准 C 中没有明确定义。
    • @Dolda2000:嗯……好点。最好不要做这样的事情。我必须修改它。
    【解决方案2】:

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

    您可以使用objcopy -I binary -O elf64-x86-64 -B i386 stargate.bmp stargate.o 来生成包含stargate.bmp 数据的目标文件(当然,如果您想要可移植性,则必须适当地调整输出架构)。然后,如果您将这些对象文件链接到可执行文件,符号_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");
    

    【讨论】:

    • 非常有趣!从来没想过。我会试试看。
    • 这是编译嵌入式设备固件时非常常用的方法。由于设备的 ROM 只能包含一个可执行文件(原始内存内容是可执行文件,没有文件系统),所有资源都沿着代码和数据放置,并且设置了符号,因此链接器可以调整可执行文件中的地址。然后将原始可执行文件(不是 ELF,只是混合或连接代码 (.text) 和数据 (.rodata) 的“blob”)存储在 ROM 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 2018-03-20
    • 2021-07-25
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多