在一个发行版上构建二进制文件以在其他发行版上运行

在一个发行版上构建二进制文件以在其他发行版上运行

我想在 Docker 容器上构建一个非常简单的命令行客户端应用程序,以向客户提供该应用程序。该应用程序使用 PEAK(制造该适配器的公司)的 CAN 转 USB 适配器。 PEAK 提供了一个库 (libpcanbasic),应用程序使用该库来访问 CAN 总线。

为了构建 libpcanbasic 库,必须安装适配器的驱动程序。我使用分阶段的 docker 容器,首先在其中构建 libpcanbasic.so 库。然后我使用第二阶段来拥有一个带有更新的 GCC (gcc:12.1.0-bullseye) 的容器。

不,我在链接我的应用程序时遇到了麻烦。 libpcanbasic.so 依赖于不属于第二阶段容器的 libc 版本/风格:

# readelf -d /usr/lib/libpcanbasic.so

Dynamic section at offset 0x189b8 contains 25 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.musl-aarch64.so.1]
 0x000000000000000e (SONAME)             Library soname: [libpcanbasic.so]
 0x000000007ffffffd (AUXILIARY)          Auxiliary library: [visibility=hidden]
 0x000000000000000c (INIT)               0x3f38
 0x000000000000000d (FINI)               0x121f0
 0x0000000000000019 (INIT_ARRAY)         0x28998
 0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x289a8
 0x000000000000001c (FINI_ARRAYSZ)       16 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x190
 0x0000000000000005 (STRTAB)             0x1638
 0x0000000000000006 (SYMTAB)             0x558
 0x000000000000000a (STRSZ)              2719 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x28b88
 0x0000000000000002 (PLTRELSZ)           3096 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x3320
 0x0000000000000007 (RELA)               0x20d8
 0x0000000000000008 (RELASZ)             4680 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x0000000000000018 (BIND_NOW)           
 0x000000006ffffffb (FLAGS_1)            Flags: NOW
 0x000000006ffffff9 (RELACOUNT)          185
 0x0000000000000000 (NULL)               0x0

我可以将该 libc 文件 (libc.musl-aarch64.so.1) 复制到/lib第二阶段容器中,然后链接就可以了:

# readelf -d ./build/client/bootloader_client 

    Dynamic section at offset 0x14da8 contains 29 entries:
      Tag        Type                         Name/Value
     0x0000000000000001 (NEEDED)             Shared library: [libpcanbasic.so]
     0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
     0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
     0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
     0x000000000000000c (INIT)               0x402d98
     0x000000000000000d (FINI)               0x40e670
     0x0000000000000019 (INIT_ARRAY)         0x424d78
     0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
     0x000000000000001a (FINI_ARRAY)         0x424d88
     0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
     0x0000000000000004 (HASH)               0x400278
     0x000000006ffffef5 (GNU_HASH)           0x4005d0
     0x0000000000000005 (STRTAB)             0x4010d0
     0x0000000000000006 (SYMTAB)             0x400620
     0x000000000000000a (STRSZ)              4274 (bytes)
     0x000000000000000b (SYMENT)             24 (bytes)
     0x0000000000000015 (DEBUG)              0x0
     0x0000000000000003 (PLTGOT)             0x424fe8
     0x0000000000000002 (PLTRELSZ)           2448 (bytes)
     0x0000000000000014 (PLTREL)             RELA
     0x0000000000000017 (JMPREL)             0x402408
     0x0000000000000007 (RELA)               0x402318
     0x0000000000000008 (RELASZ)             240 (bytes)
     0x0000000000000009 (RELAENT)            24 (bytes)
     0x000000006ffffffe (VERNEED)            0x402268
     0x000000006fffffff (VERNEEDNUM)         3
     0x000000006ffffff0 (VERSYM)             0x402182
     0x0000000000000000 (NULL)               0x0            

但我想,当我尝试在其他地方执行生成的二进制文件时,我会遇到问题。

为什么应用程序和共享对象(libpcanbasic.so)不只依赖于libc.so?为什么是非常具体的版本?这可以改变吗?而且,如果我想为客户提供二进制文件,最佳实践是什么?

最好的问候,托斯顿

答案1

你的库最终不会“仅仅依赖于libc.so”,因为它是使用穆斯勒libc(我猜你的第一阶段使用基于 Alpine 的容器映像)。您的应用程序不依赖于libc.so任何一个,而取决于libc.so.6哪个GNU C 库(它是在 Debian 上构建的,默认使用 GNU C 库)。

由于您习惯于容器构建,因此向客户提供二进制文件的最佳实践是使用与您想要支持的目标相对应的容器映像来构建它们。由于据我所知,您的库没有任何特定的依赖项,因此您可以通过使用旧的基于 GNU C 库的发行版构建它来简化您的维护负担(构建一个可在具有相同库版本的任何发行版上使用的库)稍后),如果您想支持基于 musl 的目标,则可以使用基于 musl 的发行版。

如果您继续进行多阶段构建,您至少应该确保所有阶段都基于相同的映像(或兼容的映像)。

相关内容