題主說的gcc可以編譯核心也可以編譯應用,是因為GCC有-ffreestanding選項。開啟後GCC就知道正在編譯核心,因此禁用C標準庫裡的大部分庫,並針對裸機環境進行調整。而不使用此選項,gcc就會針對執行在作業系統上的應用編譯。
但是使用這種gcc編譯核心,僅有十分侷限的用途,即重新從原始碼編譯當前正在執行的核心,即最近版本的Linux(假如你使用的是Linux)。
如果你想編寫自己的作業系統,那不能使用系統自帶的GCC。你需要編譯交叉編譯器。
關於為什麼Linux發行版的GCC不能用於開發作業系統或者編譯其他作業系統核心,可以看
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軟體少的可以用Gentoo Linux
Gentoo 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方便不少。
題主說的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方便不少。