在一個發行版上建構二進製文件以在另一個發行版上執行
我想在 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
?為什麼是非常具體的版本?這可以改變嗎?而且,如果我想為客戶提供二進製文件,最佳實踐是什麼?最好的問候,托斯滕
您的庫最終不會“僅依賴於
libc.so
”,因為它是使用musl libc建構的(我猜您的第一階段使用的是基於 Alpine 的容器映像)。您的應用程序不依賴於libc.so
任何一個,它取決於libc.so.6
哪個是GNU C 庫(它是基於 Debian 建構的,預設為 GNU C 庫)。由於您習慣於容器建構,因此向客戶提供二進製文件的最佳實踐是使用與您要支持的目標相對應的容器映像來建構它們。據我所知,由於您的庫沒有任何特定的依賴項,因此您可以通過使用較舊的基於 GNU C 庫的發行版建構它來簡化維護負擔(建構一個可在具有相同庫版本的任何發行版上使用的庫或稍後),如果您想支持基於 musl 的目標,則可以使用基於 musl 的發行版。
如果您繼續進行多階段建構,您至少應該確保所有階段都基於相同的映像(或兼容的映像)。