本文共3200餘字,預計閱讀時間9分鐘,本文知乎鏈接:Cygwin系列(二):初窺Cygwin背後。

本文接上篇Cygwin系列(一):Cygwin是什麼,介紹Cygwin實現的思路。

前言:跨平台移植實現

一個程序軟體從誕生到運行起來,粗略地分,要經歷以下幾個過程:

  1. 編寫源代碼;
  2. 源代碼編譯、鏈接;
  3. 系統載入程序文件;
程序軟體從誕生到運行的經歷

3個階段的主導角色分別是:文本編輯器(Editor)、編譯工具鏈(Tool chain,鏈的意思是一系列工具而不止一個)、程序載入器(Loader)。要實現跨平台移植,就要從這三方面入手。

  • 編寫過程

源代碼是純文本,在不同的系統平台(如Windows、UNIX、Linux)差異除了換行符其他可以忽略不計,而且文本編輯器通常也能設定換行符,再退一步,還有工具實現文本中換行符的轉換。可以認為,源代碼編寫過程在不同系統平台沒有差異。

  • 編譯鏈接過程

程序源代碼文件經過編譯彙編生成二進位的目標文件,目標文件就包含了機器指令、數據等內容,目標文件再與必要的庫文件鏈接最終形成可執行文件。

編譯鏈接過程示意圖

不同的系統平台(如Windows、UNIX、Linux)上目標文件、可執行文件格式是不同的,庫文件是已有目標的歸檔包(archive),不同的系統平台所擁有的庫文件(比如Cygwin系列(一):Cygwin是什麼所提到的C標準庫)也是不一樣的。

一言以蔽之,系統A上的目標文件、庫文件、可執行文件在系統B上一般是不可直接識別的;如果他們能做到相互識別,那可稱這兩個系統ABI(Application Binary Interface,應用程序二進位介面)兼容。

  • 載入過程

os內核創建一個新的進程,裝載器,或者叫載入器,在內存開闢一片區域,從外部存儲空間(如磁碟)中複製可執行文件內容到內存相關的段(segment)中,再跳轉到程序入口並執行。

不同的系統平台(如Windows、UNIX、Linux)載入過程大致類似,但細節上有諸多不同。

此外,上述過程中的編譯工具鏈(Tool chain)、程序載入器(Loader),這些程序本身在不同的系統平台也是不一樣的。

Cygwin是怎麼做到的?

1995年,Windows已經啟用Windows NT內核、發布Windows 95並獲得了巨大的成功。另一頭,Linux發行版如Slackware、Debian、Red Hat,UNIX-like發行版如4.4BSD、FreeBSD等也都擁有了眾多的用戶。UNIX和Linux是近親,在API層面兼容(由POSIX標準保證),而Windows與UNIX/Linux是API、ABI均不兼容。如果程序能夠在不同操作系統上運行,那便能大大豐富軟體生態。

Windows、Linux發行版和FreeBSD(圖片來源於網路)

Cygwin取巧的步驟是上圖的編譯鏈接過程。

1995年,Cygnus Solutions公司的工程師注意到Windows NT和Windows 95的目標文件使用COFF格式,Windows系統的可執行文件格式PE(Portable Executable)和Linux系統的可執行文件格式ELF(Executable Linkable Format)都是COFF的變種,而且此時GNU項目的gcc編譯工具鏈已經支持COFF格式和newlib C標準庫。

這位工程師靈光一閃,可否改造gcc編譯工具鏈產生一個交叉工具鏈,進而能夠生成Windows系統原生的目標文件和可執行文件呢?得益於gcc良好的跨平台支持特性,這項工作很快就完成了,這個「交叉」版的gcc運行於Linux系統,但生成Windows系統的目標文件,正因運行系統(host)和目標系統(target)不同,所以它才叫「交叉」工具鏈。

第一步:製作交叉版gcc工具鏈

接下來,第二項重要工作,是要把這個「改造」版的gcc進一步改造,使其能夠運行在Windows系統上。要讓這個Windows版的gcc真正運行起來,還依賴於bash、POSIX兼容的系統調用等等系列程序和環境,一種思路是把這些依賴程序使用Win32 API重寫、再編譯構建,但這要花大量的時間將每一個程序都重寫。

Cygnus Solutions公司放棄了這種思路,乾脆使用Win32 API重寫一個函數庫(Cygwin DLL),提供Win32 API所缺少的必要的POSIX API,如fork、spawn、signals、select、sockets等,事實上Cygwin DLL還調用了部分Windows Native API,並且由於os設計理念上的差異,以及Windows中有大量未對外公開的Win32 API、Windows Native API,有些POSIX API根本無法用它們模擬,Cygnus Solutions公司只能完全從零重寫,而且為了處理POSIX和Windows中的差異還寫了一部分Cygwin專有的函數。再進一步,將相關程序鏈接到此DLL,交叉編譯出Win32版的bash等依賴程序以及libc等函數庫。

第二步:生成Win32版Cygwin DLL和必要工具

現在,兼容PSOIX的模擬層、構建gcc所依賴的bash等工具都已齊備,「改造」版的gcc移植到Windows系統幾乎是水到渠成的事情了。

第三步:移植gcc工具鏈到Windows

至此,兼容PSOIX的模擬層以及基於此模擬層的bash、gcc編譯工具鏈、函數庫等所組成的開發工具集已能在Windows 95/NT系統上運行起來。緊接著,Cygnus Solutions公司改寫配置腳本,逐步把眾多GNU、BSD及其他自由軟體都移植到Windows 95/NT系統上,並按照UNIX/Linux的目錄樹架構組織存放,使得Cygwin環境越來越完備,UNIX系統上標準工具在Cygwin中都有了可用的版本。到1996年10月,Cygwin已完全自足,發布17.1 beta版。

Cygwin隨後的發展

整個Cygwin工具集開始是作為一個單獨的安裝包提供,到2000年4月,項目宣布了新的發布方式,額外提供一個不依賴於Cygwin的Windows原生程序——setup.exe,具有圖形界面,用於安裝、更新、卸載軟體包,因此可視為Cygwin軟體包管理器,此後setup.exe和Cygwin DLL分別獨立開發。

2009年Cygwin DLL v1.7發布,拋棄了對老版本Windows(Windows 95/98/Me)的支持,充分利用Windows NT的新特性,如文件名大小寫敏感、IPv6支持等。隨後,Cygwin DLL、setup.exe都有了64位版本。Cygwin軟體包按照用途分類組織,方便管理。Cygwin項目還提供了一系列系統工具,如cygpath、cygrunsrv、cygcheek、cygstart等,以便更好地操作管理Windows系統。

越來越多的開發者也加入了Cygwin項目,幫助將GNU、BSD及其他自由軟體移植到Cygwin並打包。越來越多的機構、公司將Cygwin官方的軟體倉庫同步鏡像過來,由此在世界各地形成眾多Cygwin鏡像站點,共世界各地的用戶下載Cygwin的軟體包,中國的比如網易、阿里、清華、中科大、華科等均提供Cygwin鏡像站。

參考

  • http://www.cygwin.com
  • en.wikipedia.org/wiki/C
  • en.wikipedia.org/wiki/L
  • 俞甲子,石凡,潘愛民·程序員的自我修養——鏈接、裝載與庫[M]·電子工業出版社,2009·

更多閱讀

silaoA:Cygwin前傳:從割據到互補?

zhuanlan.zhihu.com
圖標
silaoA:Cygwin系列(一):Cygwin是什麼?

zhuanlan.zhihu.com
圖標

? 本文同步發布在微信公眾號 偽碼人(We_Coder),如需轉載請私信知乎賬號或聯繫公眾號。

本文對你有幫助?請轉發分享,歡迎關注與留言交流。


推薦閱讀:
相关文章