1 回答

TA貢獻1943條經驗 獲得超7個贊
在 GNU/Linux 上,幾乎所有的 Go 可執行文件都屬于這些類別:
那些包括應用程序、Go 運行時和 glibc(的一部分)的靜態鏈接副本。
那些只包含應用程序和 Go 運行時的靜態鏈接,沒有 glibc。
那些只包括應用程序和 Go 運行時、靜態鏈接和動態鏈接到 glibc 的。
不幸的是,與 Go 相關的工具通常會混淆這些鏈接模式。依賴 glibc 的主要原因是應用程序使用主機名和用戶查找(功能如getaddrinfo
和getpwuid_r
)。?CGO_ENABLED=0
從src/os/user/cgo_lookup_unix.go
(使用 glibc)等實現切換到src/os/user/lookup_unix.go
(不使用 glibc)。非 glibc 實現不使用 NSS,因此提供的功能有些有限(通常不會影響不在 LDAP/Active Directory 中存儲用戶信息的用戶)。
在您的情況下,設置CGO_ENABLED=0
將您的應用程序從第三類移至第二類。(還有其他與 Go 相關的工具可以構建第一種應用程序。)非 NSS 查找代碼不是很大,因此二進制大小的增加并不顯著。由于 Go 運行時已經靜態鏈接,靜態鏈接減少的開銷甚至可能導致可執行文件大小的凈減少。
這里要考慮的最重要的問題是 NSS、線程和靜態鏈接在 glibc 中并不是那么好。所有的 Go 程序都是多線程的,(靜態)將 glibc 鏈接到 Go 程序中的原因正是訪問 NSS 函數。因此,將 Go 程序靜態鏈接到 glibc 始終是錯誤的做法。它基本上總是?有問題。即使 Go 程序不是多線程的,使用 NSS 函數的靜態鏈接程序在運行時也需要與構建時使用的 glibc版本完全相同,因此此類應用程序的靜態鏈接會降低可移植性。
所有這些都是第一類 Go 應用程序如此糟糕的原因。使用 生成靜態鏈接的應用程序CGO_ENABLED=0
沒有這些問題,因為這些應用程序(第二類)不包含任何 glibc 代碼(以用戶/主機查找功能的功能減少為代價)。
如果你想創建一個需要 glibc 的可移植二進制文件,你需要動態鏈接你的應用程序(第三種),在你想要支持的最舊的 glibc 系統上。然后應用程序將在該 glibc 版本和所有更高版本上運行(目前,Go 沒有正確鏈接 libc,所以即使是 glibc 也沒有很強的兼容性保證)。發行版通常與 ABI 兼容,但它們具有不同版本的 glibc。glibc 竭盡全力確保動態鏈接到舊版本 glibc 的應用程序將繼續在新版本的 glibc 上運行,但反之則不然:一旦您將應用程序鏈接到特定版本的 glibc,它可能會獲得功能(符號)在舊版本上不可用,因此該應用程序將無法與那些舊版本一起使用。
- 1 回答
- 0 關注
- 153 瀏覽
添加回答
舉報