應用程序編譯後 只能在兼容該編譯器的平台上運行 , 為什麼 windows/linux 程序可以在多個系統版本間運行?

比如xp平台的程序可以在win7等版本系統運行

ubuntu 系統下通過apt-get install 安裝的程序 也都可以在不同ubuntu 版本間運行


先說「是不是」

目標為x86平台的ubuntu編譯的程序,在arm, powerpc版的ubuntu上都不能運行。

再談題目

「兼容該編譯器」這話說得很模糊。。。我在x86的ubuntu上搭一個交叉編譯環境(比如目標平台MIPS),這叫不叫x86 ubuntu「兼容」MIPS編譯器?

關鍵是,程序編譯完成後,和編譯器就沒什麼關係了(運行時庫不算,VM語言不考慮),全成機器碼了。指令不一致就跪了,所以以x86為目標編譯的程序不能放到ARM上跑。理論上只要硬體指令兼容,都可以跑,但實際上,程序可能有各種依賴(用了操作系統API,外部庫之類),不同系統的可執行文件的格式也不一致,所以Windows編譯的程序放到Linux上不能運行。

但是同種操作系統、同平台提供的庫,格式等等基本相同,就是所謂「兼容」,所以基本上可以在多個版本上運行。

還有一點

ubuntu 系統下通過apt-get install 安裝的程序 也都可以在不同ubuntu 版本間運行

apt-get install安裝程序,會根據你的系統平台,選擇相應的編譯版本下載,所以同樣的命令,在x86/x64/ARM/PowerPC等不同平台上裝的東西是不一樣的。


即使排除API的兼容問題,用靜態編譯出的可執行文件(不依賴動態鏈接庫),還是會有執行文件格式的問題,比如win下可執行文件的格式的PE,linux下是ELF。就算是同樣的可執行文件格式,比如都是ELF,ABI不兼容(比如大小端不同,棧的調用方法不同)也還是不能跑。


windows是花費了巨大的人力物力,才能達到依賴了win95的bug的程序在98修了這個bug之後還能自如的運行在98上的。linux嘛……


不談源碼兼容性,也不談 java .net 等基於虛擬機的,只談二進位兼容,有這麼幾個層次

1. 指令集和體系結構

x86 arm misc 互不兼容

x64 可以跑x86, arm64也可以跑 arm32

還有相同架構不同晶元的小差異,比如 intel 和 amd 不同的擴展指令集,這個編譯器會處理掉

2. 封裝格式

linux 支持 aout 和 elf

window 支持 pe , dos 下的com和exe 不是pe,在windows下是用模擬層跑的

3. 運行時庫,大部分的兼容性問題應該出在這裡

鏈接 libc++3 的程序,系統里只有 libc++4 就不能跑

linux 的運行時庫兼容性做的不太好,而且系統不鼓勵軟體自帶庫

windows 在這方面是下苦工的,如 vczh 所說,而且軟體有自帶庫的習慣,有了WinSxS之後,不同版本庫共用要好的多了

以前win下軟體自帶庫是直接和exe放一起的,對於ms自己的庫,現在是鼓勵用 Redistributable Package,以便不同軟體共用庫

4. 雜七雜八的兼容性問題

某個版本windows有bug,做了個fix,反而新版本windows修復bug後不能跑了。

linux是不管這種問題的,只有ms花了大量資源去搞這個。

某新版windows引入的新特性,但在老版本上還要跑,那麼在源碼里做個運行時版本判斷。不判斷直接用新特性,老系統就跑不了。

還有硬編碼 c:windowssystem32 c:documents and settings 這種只能呵呵的。其實windows在這個地方做了不少工作,但如果windows裝D盤呢。

=========開始回答問題的分割線=========

arm misc 及其他嵌入式系統,不會考慮二進位兼容性,換個系統就必須重編譯

android 在 java 層面abi是相同的,高版本系統自帶或者模擬低版本庫來保證兼容性。

在非java的so庫上,封裝格式必然是elf,android軟體會自帶多體系架構的so庫,armv5 armv7 x86

linux 上,arm 的 怎麼也跑不了 x86 的程序吧。

最近幾年 gcc 的lib穩定了不少, libcpp3 libcpp4 那時才叫痛苦。

apt-get install 安裝的就是各個編譯的特定系統兼容的軟體。

windows x86 系統還是跑不了 x64 程序

x64 系統基本都能跑 x86 程序

軟體有自帶庫的習慣

WinSxS 保證系統庫不會衝突

鼓勵用 Redistributable Package,庫可共用

windows 解決兼容性問題是做的最好的。


這分明是一個關於裝載和執行的問題。一個應用程序對操作系統來說就是一個數據文件,只要它符合系統對「應用程序」這種文件的格式要求,它就能運行。「應用程序編譯後 只能在兼容該編譯器的平台上運行」, 這是一種不科學的模糊說法。


有種東西叫指令集和體系結構,有種東西叫運行時庫,你們體會一下。


兼容啊,高版本一般兼容低版本。出於商業需求

但是跨平台是不兼容的,比如windows的二進位和linux的不能互相使用。因為操作系統載入和處理可執行文件的方式與操作系統相關。


推薦閱讀:

gcc局部變數不用初始化么?
對於同樣的 C 語言代碼,為什麼 Mac OS X 上用 gcc 編譯運行的結果和其他系統不同?
GCC的參數-march=native是如何獲取cpu類型和指令集的?

TAG:Linux | GCC | 編譯器 |