為什么我用gcc編譯了腳本?
題主說的gcc可以編譯內核也可以編譯應用,是因為GCC有-ffreestanding選項。開啟后GCC就知道正在編譯內核,因此禁用C標準庫里的大部分庫,并針對裸機環境進行調整。而不使用此選項,gcc就會針對運行在操作系統上的應用編譯。
但是使用這種gcc編譯內核,僅有十分局限的用途,即重新從源代碼編譯當前正在運行的內核,即最近版本的Linux(假如你使用的是Linux)。
如果你想編寫自己的操作系統,那不能使用系統自帶的GCC。你需要編譯交叉編譯器。
關于為什么Linux發行版的GCC不能用于開發操作系統或者編譯其他操作系統內核,可以看
Why do I need a Cross Compiler?GCC工具鏈支持交叉編譯,即GCC支持在M平臺上運行,并生成N平臺上的二進制文件。
工具鏈的目標格式為三元組 CPU架構-制造商-操作系統 有的時候操作系統后會跟上c語言庫的名字或者abi。
常見的組合有:CPU架構(i686,x86_64,arm,rv64gc),操作系統(Linux,FreeBSD,mingW64),c語言庫(glibc,musl,newlib)abi(sysv,arm v7的eabi,eabihf)。那些沒有特定制造商的工具鏈有的使用unknown作為制造商標識,有的則省略。沒有操作系統的工具鏈常使用none作為標識。
每一份GCC,都指定了CPU架構,系統的頭文件(也有可能只支持裸機環境),binutils,c語言庫,改變這些只能從頭編譯。
gcc -dumpmachine
這個命令可以顯示一個編譯器的目標平臺。
比如,Linux發行版提供的GCC一般是x86_64-Linux-GNU,表示編譯出的文件運行在x86_64平臺上的Linux內核,并且使用glibc和sysv abi。
如果編譯器的運行平臺和目標平臺一致,則稱為本機(native)編譯器,這種編譯器生成的二進制文件一般可以直接運行。其他的稱為交叉編譯器,生成的文件不能直接運行。
實際上也有x86_64的Linux上運行的x86_64-Linux-GNU交叉編譯器,唯一的不同是編譯目標可能使用不同版本的庫,其作用是自舉(bootstrap)。
所謂bootstrap,就是從源碼重新編譯一套能運行的Linux內核,gcc本機編譯器,glibc。一般這項工作由發行版維護,如果想自己嘗試一下,可以閱讀著名的linux from scratch
LFS Project Homepage覺得LFS軟件少的可以用Gentoo Linux
Gentoo AMD64 HandbookGentoo Linux在安裝時需要編譯Linux內核,同時可以自己選擇libc,以及編譯選項。
再拿rust語言的情況來對比一下。
rust語言的編譯器,rustc,其二進制文件發行支持交叉編譯。
也就是rustc這個幾十兆的可執行程序可以生成支持的所有CPU架構的目標文件,這得益于rustc的后端llvm。llvm在這一點上比gcc強大了一個次元。
如果使用包管理器cargo,只要項目根文件lib.rs或main.rs開頭包含#![no_std],即代表不使用標準庫,編譯到裸機代碼。這和GCC的ffreestanding選項是一個意思。
使用cargo build --target 目標 即可交叉編譯。不需要重新編譯rustc。根據平臺的區別,有時需要外部連接器。
由于不需要重新編譯編譯器,因此使用rust做操作系統開發總體來說比c語言+gcc方便不少。