Linux

學習從原始碼編譯東西(在 Unix/Linux/OSX 上)

  • March 14, 2018

當我盡可能從包(MacPorts / apt-get)安裝軟體時,我經常發現自己需要從原始碼編譯包。./configure && make && sudo make install通常就足夠了,但有時它不起作用 - 當它不起作用時,我經常被卡住。這幾乎總是以某種方式與其他庫依賴項相關。

我想學習以下內容:

  • 我如何弄清楚要傳遞給哪些參數./configure
  • 共享庫在 OS X / Linux 下是如何工作的——它們在文件系統上的位置、如何./configure && make找到它們、連結它們時實際發生的情況
  • 共享庫和靜態連結庫之間的實際區別是什麼?為什麼我不能靜態連結所有內容(現在 RAM 和磁碟空間很便宜),從而避免奇怪的庫版本衝突?
  • 我怎樣才能知道我安裝了哪些庫以及哪些版本?
  • 如何在不破壞正常系統的情況下安裝多個版本的庫?
  • 如果我使用包管理的系統上從原始碼安裝東西,那麼最乾淨的方法是什麼?
  • 假設我設法從原始碼編譯了一些繁瑣的東西,那麼我怎樣才能將其打包,這樣其他人就不必跳過同樣的圈子?特別是在 OS X 上……
  • 我需要掌握哪些命令行工具才能擅長這些東西?像 otool、pkg-config 等的東西。

我願意在這裡投入相當多的時間和精力——我不一定想要直接回答上述問題,我更願意獲得關於我可以閱讀的書籍/教程/常見問題解答的建議,這會給我知識 我需要了解實際發生的情況,從而自己解決問題。

我為直接回答所有問題而道歉,但我不知道任何有用的教程、常見問題解答等。基本上接下來是 8 年製作桌面應用程序(我幫助分發)、沮喪和Google搜尋:

1. 如何確定要傳遞給 ./configure 的參數?

實實在在地練習。Autotools 很簡單,因為它是一致的。但是有很多東西可以使用 cmake 或自定義建構腳本。一般來說,你不應該傳遞任何東西來配置,它應該確定你的系統是否可以建構 foo-tool。

配置和 GNU 工具都在 /、/usr 和 /usr/local 中查找依賴項。如果你在其他任何地方安裝任何東西(如果依賴項是由 MacPorts 或 Fink 安裝的,這會讓事情變得很痛苦),你將不得不傳遞一個標誌來配置或修改 shell 的環境,以幫助 GNU 工具找到這些依賴項。

2. 共享庫在 OS X / Linux 下是如何工作的——它們在文件系統上的位置,./configure && make 如何找到它們,當它們連結時實際發生了什麼

在 Linux 上,它們需要安裝到動態連結器可以找到的路徑,這由LD_LIBRARY_PATH環境變數和 /etc/ld.conf 的內容定義。在 Mac 上,大多數開源軟體幾乎總是相同的(除非它是 Xcode 項目)。除了 env 變數是DYLD_LIBRARY_PATH

連結器有一個預設路徑搜尋庫。它是 /lib:/usr/lib:/usr/local/lib

您可以通過使用 CPATH 變數或 CFLAGS 或任何數量的其他環境變數來補充這一點(方便複雜)。我建議 CFLAGS 像這樣:

出口 CFLAGS="$CFLAGS -L/new/path"

-L 參數添加到連結路徑。

現代的東西使用 pkg-config 工具。您安裝的現代東西還會安裝一個 .pc 文件,該文件描述了庫及其位置以及如何連結到它。這可以使生活更輕鬆。但它沒有隨 OS X 10.5 一起提供,所以你也必須安裝它。還有很多基本的部門不支持它。

連結的行為只是“在執行時解析這個函式”,實際上它是一個大字元串表。

3. 共享庫和靜態連結庫之間的實際區別是什麼?為什麼我不能靜態連結所有內容(現在 RAM 和磁碟空間很便宜),從而避免奇怪的庫版本衝突?

當您連結到靜態庫文件時,程式碼將成為您應用程序的一部分。就像該庫有一個巨大的 .c 文件,並且您將其編譯到您的應用程序中。

動態庫具有相同的程式碼,但是當應用程序執行時,程式碼會在執行時載入到應用程序中(簡化解釋)。

您可以靜態連結到所有內容,但遺憾的是,幾乎沒有任何建構系統可以輕鬆實現這一點。您必須手動編輯建構系統文件(例如 Makefile.am 或 CMakeLists.txt)。但是,如果您經常安裝需要不同版本庫的東西並且您發現並行安裝依賴項很困難,那麼這可能值得學習。

訣竅是將連結行從 -lfoo 更改為 -l/path/to/static/foo.a

您可能可以找到並替換。然後使用 ldd foo 或 otool -L foo 檢查該工具沒有連結到 .so 或 dylib

另一個問題是並非所有庫都編譯為靜態庫。許多人都這樣做。但後來 MacPorts 或 Debian 可能決定不發布它。

4. 如何知道我安裝了哪些庫,安裝了哪些版本?

如果您有這些庫的 pkg-config 文件,則很容易:

pkg-config –list-all

否則你往往不能輕易。dylib 可能有一個與庫版本相同的 soname(即 foo.0.1.dylib,soname 為 0.1)。然而,這不是必需的。soname 是一種二進制可計算性功能,如果您更改庫中函式的格式,則必須修改 soname 的主要部分。所以你可以得到例如。用於 2.0 庫的版本 14.0.5 soname。雖然這並不常見。

我對這種事情感到沮喪,並在 Mac 上為此開發了一個解決方案,接下來我將討論它。

5. 如何在不破壞正常系統的情況下安裝多個版本的庫?

我的解決方案在這裡:http: //github.com/mxcl/homebrew/

我喜歡從原始碼安裝,並且想要一個簡單的工具,但有一些包管理。因此,我使用 Homebrew 建構,例如。wget 自己從原始碼,但確保安裝到一個特殊的前綴:

/usr/local/Cellar/wget/1.1.4

然後我使用自製工具將所有這些符號連結到 /usr/local,所以我仍然有 /usr/local/bin/wget 和 /usr/local/lib/libwget.dylib

稍後,如果我需要不同版本的 wget,我可以並行安裝它,只需更改連結到 /usr/local 樹的版本即可。

6. 如果我在使用包管理的系統上從原始碼安裝東西,那麼最乾淨的方法是什麼?

我相信 Homebrew 方式是最乾淨的,所以使用它或做類似的事情。安裝到 /usr/local/pkgs/name/version 和符號連結或硬連結其餘部分。

請使用 /usr/local。每個存在的建構工具都會在那裡搜尋依賴項和標頭。你的生活會輕鬆很多。

7. 假設我設法從原始碼編譯了一些繁瑣的東西,那麼我怎樣才能將它打包,這樣其他人就不必跳過同樣的圈子?特別是在 OS X 上……

如果它沒有依賴項,您可以壓縮建構目錄並將其提供給其他可以執行“make install”的人。但是,您只能對完全相同的 OS X 版本可靠地執行此操作。在 Linux 上,它可能適用於具有相同核心版本和 libc 次要版本的類似 Linux(例如 Ubuntu)。

在 Unix 上分發二進製文件不容易的原因是因為二進製文件的兼容性。GNU 人和其他所有人經常更改他們的二進制介面。

基本上不分發二進製文件。事情可能會以非常奇怪的方式破裂。

在 Mac 上,最好的選擇是製作一個 macports 包。每個人都使用 macports。在 Linux 上,有很多不同的建構系統和組合,我認為沒有比寫一篇關於您如何在 y 奇怪的配置中成功建構 x 工具的部落格文章更好的建議了。

如果你做了一個包描述(對於 macports 或 homebrew),那麼任何人都可以安裝那個包,它也解決了依賴問題。然而,這通常並不容易,而且將您的 macports 配方包含在主 macports 樹中也不容易。macports 也不支持外來安裝類型,它們為所有軟體包提供一種選擇。

我未來使用 Homebrew 的目標之一是讓點擊網站上的連結成為可能(例如 homebrew://blah,它將下載該 Ruby 腳本,安裝該軟體包的 deps,然後建構應用程序。但是,是的,尚未完成,但考慮到我選擇的設計並不太棘手。

8. 我需要掌握哪些命令行工具才能擅長這些東西?像 otool、pkg-config 等的東西。

otool 真的只有在之後才有用。它告訴你建構的二進制連結到什麼。當您弄清楚必須建構的工具的依賴關係時,它是無用的。pkg-config 也是如此,因為您在使用它之前已經安裝了依賴項。

我的工具鍊是,閱讀 README 和 INSTALL 文件,然後配置 –help。觀察建構輸出以檢查它是否正常。解析任何建構錯誤。也許將來,詢問伺服器故障:)

引用自:https://serverfault.com/questions/46381