1. 程式人生 > >Linux核心編譯詳解

Linux核心編譯詳解

學習了網上的一些資料,自己試著摸索了一下,整理出此文。

由於在下水平相當有限,不當之處,還望大家批評指正^_^

重要的參考資料有:

好了,下面進入正題。

一、準備工作

準備工作如何做,這裡就不詳說了。

a) 首先,你要有一臺PC(這不廢話麼^_^),裝好了Linux。

b) 安裝好GCC(這個指的是host gcc,用於編譯生成運行於pc機程式的)、make、ncurses等工具。

c) 下載一份純淨的Linux核心原始碼包,並解壓好。

注意,如果你是為當前PC機編譯核心,最好使用相應的Linux發行版的原始碼包。

不過這應該也不是必須的,因為我在我的Fedora 13上(其自帶的核心版本是2.6.33.3),就下載了一個標準的核心linux-2.6.32.65.tar.xz,並且順利的編譯安裝成功了,上電重啟都OK的。

不過,我使用的.config配置檔案,是Fedora 13自帶核心的配置檔案,即/lib/modules/`uname -r`/build/.config

d) 如果你是移植Linux到嵌入式系統,則還要再下載安裝交叉編譯工具鏈。

例如,你的目標單板CPU可能是arm或mips等cpu,則安裝相應的交叉編譯工具鏈。安裝後,需要將工具鏈路徑新增到PATH環境變數中。例如,你安裝的是arm工具鏈,那麼你在shell中執行類似如下的命令,假如有類似的輸出,就說明安裝好了。

[[email protected] linux-2.6.33.i686]# arm-linux-gcc  --version
arm-linux-gcc (Buildroot 2010.11) 4.3.5
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


二、設定編譯目標

在配置或編譯核心之前,首先要確定目標CPU架構,以及編譯時採用什麼工具鏈。這是最最基礎的資訊,首先要確定的。

如果你是為當前使用的PC機編譯核心,則無須設定。

否則的話,就要明確設定。

這裡以arm為例,來說明。

有兩種設定方法():

a) 修改Makefile

開啟核心原始碼根目錄下的Makefile,修改如下兩個Makefile變數並儲存。

ARCH           := arm
CROSS_COMPILE  := arm-linux-

注意,這裡cross_compile的設定,是假定所用的交叉工具鏈的gcc程式名稱為arm-linux-gcc。如果實際使用的gcc名稱是some-thing-else-gcc,則這裡照葫蘆畫瓢填some-thing-else-即可

。總之,要省去名稱中最後的gcc那3個字母。

b) 每次執行make命令時,都通過命令列引數傳入這些資訊。

這其實是通過make工具的命令列引數指定變數的值。

例如

配置核心時時,使用

make  ARCH=arm  CROSS_COMPILE=arm-linux-  menuconfig

編譯核心時使用

make  ARCH=arm  CROSS_COMPILE=arm-linux- 

注意,實際上,對於編譯PC機核心的情況,雖然使用者沒有明確設定,但並不是這兩項沒有配置。因為如果使用者沒有設定這兩項,核心原始碼頂層Makefile(位於原始碼根目錄下)會通過如下方式生成這兩個變數的值。

SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 -e s/arm.*/arm/ -e s/sa110/arm/ \
 -e s/s390x/s390/ -e s/parisc64/parisc/ \
 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
 -e s/sh[234].*/sh/ )

ARCH?= $(SUBARCH)
CROSS_COMPILE?=

經過上面的程式碼,ARCH變成了PC編譯機的arch,即SUBARCH。因此,如果PC機上uname -m輸出的是ix86,則ARCH的值就成了i386。

而CROSS_COMPILE的值,如果沒配置,則為空字串。這樣一來所使用的工具鏈程式的名稱,就不再有類似arm-linux-這樣的字首,就相當於使用了PC機上的gcc。

最後再多說兩句,ARCH的值還需要再進一步做泛化。因為核心原始碼的arch目錄下,不存在i386這個目錄,也沒有sparc64這樣的目錄。

因此頂層makefile中又構造了一個SRCARCH變數,通過如下程式碼,生成他的值。這樣一來,SRCARCH變數,才最終匹配到核心原始碼arch目錄中的某一個架構名。

SRCARCH := $(ARCH)  

ifeq ($(ARCH),i386)
        SRCARCH := x86
endif


ifeq ($(ARCH),x86_64)
        SRCARCH := x86
endif

ifeq ($(ARCH),sparc64)
       SRCARCH := sparc
endif

ifeq ($(ARCH),sh64)
       SRCARCH := sh
endif

三、配置核心

核心的功能那麼多,我們需要哪些部分,每個部分編譯成什麼形式(編進核心還是編成模組),每個部分的工作引數如何,這些都是可以配置的。因此,在開始編譯之前,我們需要構建出一份配置清單,放到核心原始碼根目錄下,命名為.config檔案,然後根據此.config檔案,編譯出我們需要的核心。

但是,核心的配置項太多了,一個一個配,太麻煩了。而且,不同的CPU架構,所能配置的配置項集合,是不一樣的。例如,某種CPU的某個功能特性要不要支援的配置項,就是與CPU架構有關的配置項。所以,核心提供了一種簡單的配置方法。

以arm為例,具體做法如下。

a) 根據我們的目標CPU架構,從核心原始碼arch/arm/configs目錄下,找一個與目標系統最接近的配置檔案(例如s3c2410_defconfig),拷貝到核心原始碼根目錄下,命名為.config。

注意,如果你是為當前PC機編譯核心,最好拷貝如下檔案到核心原始碼根目錄下,做為初始配置檔案。這個檔案,是PC機當前執行的核心編譯時使用的配置檔案。

/lib/modules/`uname -r`/build/.config

這裡順便多說兩句,PC機核心的配置檔案,選擇的功能真是多。不編不知道,一編才知道。Linux發行方這樣做的目的,可能是想讓所發行的Linux能夠滿足使用者的各種需求吧。

b) 執行make menuconfig對此配置做一些需要的修改,退出時選擇儲存,就將新的配置更新到.config檔案中了。

注意-1,我們執行此操作時,核心打開了一組配置項集合,讓我們進行配置。這一組配置項集合,是由我們前面設定的CPU架構決定的。說得細一點,配置系統開啟arch/arm/Kconfig檔案(make menuconfig執行時能看到有一行“scripts/kconfig/mconf arch/arm/Kconfig”這樣的列印),這個檔案又包含了其他核心子系統的Kconfig檔案(檔名也可能是其他名字),其他子系統的Kconfig檔案,再層層包含下層的Kconfig檔案,從而生成了全部的配置項集合。而每一項配置項,當前設定的值(例如,是編進核心,還是編譯成模組,或者也可能是一項引數),則是由核心原始碼根目錄下的.config檔案生成的。

注意-2,即使你不需要對配置進行任何修改,都務必請執行一下make menuconfig,然後進入配置介面後直接退出並儲存。不然的話,後面的編譯可能會遇到問題。筆者就遇到過這個問題。筆者猜測原因可能是,初始的配置檔案是基於老版本的核心做的,新版本的核心可能新增了一些基礎功能項,從而導致功能項之間的依賴關係發生了變化。例如,老的配置檔案中選中的一個功能項,在新版核心中的實現,可能依賴了更多的其他功能項。因此需要對舊的初始配置檔案進行一些調整,從而保證各個功能項的依賴條件得到滿足。經過make menuconfig之後,筆者發現,.config檔案的內容的確發生了變化。

四、編譯核心

編譯本身很簡單,對於2.6版本以上的核心,執行如下一條命令就搞定了。

make

我們不妨花點時間,理解一下核心編譯的機制。

a) 核心如何使用config檔案

前面生成了.config檔案,這是個文字檔案,其中都是一些類似如下的內容:

CONFIG_YENTA_ENE_TUNE=y
CONFIG_YENTA_TOSHIBA=y
CONFIG_PD6729=m
CONFIG_I82092=m

CONFIG_MTDRAM_ERASE_SIZE=128

能看出,有些是設定了將某個功能編譯進核心,有些是設定了將某個功能編譯成模組,有些是設定了某個功能的某個引數。

這個檔案的語法,其實就是定義makefile變數的語法。沒錯,這就是makefile。

當我們執行make開始編譯核心的時候,編譯系統還會生成另一個config檔案,那就是include/config/auto.conf。裡面的內容和.config類似,只是內容少了一些。

核心編譯的時候,頂層Makefile(位於原始碼根目錄下),會包含上述config檔案。

這樣就獲得了相應的makefile變數,從而知道如何編譯核心的各個部分。

從頂層makefile中,可以看到如下程式碼:

ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf

但是,這兩個config檔案的關係如何,到底會包含哪個,在下也沒有理清。有清楚的,還望賜教:)

b) 核心如何編譯各個子系統或模組

從上一步知道,通過config檔案,核心頂層makefile已經生成了大量的makefile變數。

另一方面,每個子系統或模組,他們的原始碼目錄中,都有一個Makefile,其中定義了本子系統或模組所需要編譯的內容。

接下來,make工具就可以帶著頂層makefile中生成的大量的makefile變數,一層層進入到各個子系統或模組所在的目錄中去,去實現各目錄中Makefile中定義的內容的編譯。

而這些目錄中的Makefile可以說是非常簡單。

如果某個目錄下,只有一個模組hello,此模組只有一個.c檔案,例如xxx.c。那麼其Makefile的全部內容只有如下一行。

obj-$(CONFIG_HELLO) := hello.o

如果hello模組,由main.c a.c b.c三個檔案構成,則Makefile也只需要兩行內容。

obj-$(CONFIG_HELLO) := hello.o

hello-objs := main.o a.o b.o

如果一個目錄下存放了多個模組的C檔案,別是hello、hello2、hello3。
hello模組的構成:main.c  a.c  b.chello2模組的構成:main2.c  a2.c  b2.chello3模組的構成:hello3.c此時,Makefile只需要5行內容。

obj-$(CONFIG_HELLO) += hello.o

obj-$(CONFIG_HELLO2) += hello2.o

obj-$(CONFIG_HELLO3) += hello3.o

hello-objs := main.o a.o b.o
hello2-objs := main2.o a2.o b2.o

由於頂層Makefile中帶有大量的變數,因此,子目錄內Makefile中的$(CONFIG_HELLO) 變數經過解析後,會變成y或m。這樣的話,每個子目錄中的Makefile經過解析後,等於只是定義了一個變數,變數名為obj-m或obj-y。

變數obj-m或obj-y的值,則是一串.o檔案的列表。表中每一項,代表一個功能項。如果變數名為obj-m,則此功能被編譯成模組。如果變數名為obj-y,則此功能被編進核心。

c) 核心程式碼中,如何知道某個功能有沒有配置,配置成了什麼形式

當我們執行make開始編譯核心的時候,編譯系統還會生成一個C語言標頭檔案include/generated/autoconf.h

這個檔案中都是類似如下的內容:

#define CONFIG_DM9000 1
#define CONFIG_DM9000_DEBUGLEVEL 4
#define CONFIG_SND_RAWMIDI_SEQ_MODULE 1
第一行,是說明使用者選擇了將DM9000這個驅動編進核心,第二行是此驅動的一個引數。如果使用者選擇的是將DM9000編譯成模組,則第一行的內容就變成如下形式了。
#define CONFIG_DM9000_MODULE 1

有了這個標頭檔案,某個核心原始碼的.c檔案中如果包含了這個標頭檔案,通過#ifdef CONFIG_XXX就可以知道使用者有沒有配置XXX功能了。


好了,核心編譯機制,在下理解的也很有限,這裡就不多說了^_^

五、安裝核心

a) 為當前PC機安裝核心

依次執行如下兩條命令,分別完成模組和核心的安裝。

make  modules_install

make  install

然後開啟boot/grub/grub.conf,會看到裡面多出了一個條目。

將其中的timeout修改為5,以便開機時有5秒的時間選擇啟動哪一個核心。

最後,重啟電腦。在bootloader介面出現時,選擇啟動新核心即可。

b) 為嵌入式系統安裝核心

這就不是一句兩句能說清的了,具體問題大家自己具體參考相關資料吧^_^

對於一般的arm單板,常見的方法是,PC機通過SecureCrt連線單板串列埠,通過網線連線單板網口,PC機上啟動tftp伺服器,把核心映像zImage檔案放到tftp下載目錄中。重啟單板,SecureCrt中看到u-boot啟動倒計時的時候,按任意鍵進入u-boot互動介面。然後在這個介面下,通過相關命令下載核心映像zImage檔案,然後通過命令將下載的zImage燒寫到單板的FLASH中。最後重啟單板即可。

至於模組的安裝,則很簡單,通過如下一條命令搞定

make -C  /path/to/kernel_src_dir  modules_install  INSTALL_MOD_PATH=/path/to/rootfs_dir

上面的命令執行後,模組就已經安裝到目標系統的根檔案系統中了 。

當然,上面的根檔案系統只是按一定的結構組織起來的一組目錄與檔案,他還需要被打包成具體的檔案系統格式(如CramFS,squashfs,jffs2等),然後燒寫到flash中才能最終使用^_^

相關推薦

Linux核心編譯

學習了網上的一些資料,自己試著摸索了一下,整理出此文。 由於在下水平相當有限,不當之處,還望大家批評指正^_^ 重要的參考資料有: 好了,下面進入正題。 一、準備工作 準備工作如何做,這裡就不詳說了。 a) 首先,你要有一臺PC(這不廢話麼^_^),裝好了Lin

linux核心sysfs-1

sysfs 是 Linux 核心中設計較新的一種虛擬的基於記憶體的檔案系統,它的作用與 proc 有些類似,但除了與 proc 相同的具有檢視和設定核心引數功能之外,還有為 Linux 統一裝置模型作為管理之用。相比於 proc 檔案系統,使用 sysfs 匯出核心資料的方

Linux核心程序之三:flush-x:y

上一篇文章《裝置檔案與裝置號》當然不是突然穿插而來的自言自語,而是理解本文的前提,下面來看。是一類程序,這在系列的上一篇文章裡已經講到過,系統的絕大部分的bdi裝置都會有對應的flush-x:y核心程序,而這個x:y是對應bdi裝置的裝置號。 先看一下系統當前掛載的檔案系統

Linux核心引數

核心引數詳解 長期更新 SYN_RECV 服務端收到sys,還未發出syn+ack 1.net.ipv4.tcp_synack_retries 預設值5,linux對應1+2+4+..32=2^6-1=63s 2.net.ipv4.tcp_s

Linux核心程序之一:sync_supers

先說下環境,CentOS 6.0/Linux kernel 2.6.38.8/X86-64,後面提到的程式碼也都來之kernel 2.6.38.8。這個環節下的程序列表具體如下所示,後續將有一系列的文章分析各個程序(主要是核心程序)的功能: [[email pro

Linux核心模組(驅動)編譯

本文主要說說如何編譯自己開發的核心模組。由於驅動通常也被編譯成核心模組,因此文章的內容也適用於驅動的編譯。 由於在下能力相當有限,有不當之處,還望大家批評指正^_^ 一、準備工作 準備工作如何做,

作業系統之--linux核心編譯步驟

ORIGIN 作為自由軟體,linux 核心版本不斷更新,新核心會修訂舊核心的 bug,並增加若干新特性,如支援更多的硬體、具備更好的系統管理能力、執行速度更快、更穩定等。使用者若想要使用這些新特性,或希望根據自身系統需求定製一個更高效、更穩定的核心,就需要重

Linux 核心編譯選項

linux核心編譯選項詳解(一):General setup [*]Prompt for development and/or incomplete code/drivers 顯示尚在開發中或尚未完成的程式碼與驅動.你應該選擇它,因為有許多裝置可能必需選擇這個選項才能進行配

Linux 核心編譯步驟及配置

前言    Linux核心是作業系統的核心,也是作業系統最基本的部分。    Linux核心的體積結構是單核心的、但是他充分採用了微核心的設計思想、使得雖然是單核心、但工作在模組化的方式下、並且這個模組可以動態裝載或卸 載;Linux負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效

Linux核心調整和核心引數

SYN COOKIE原理和Linux核心中的實現 http://www.ibm.com/developerworks/cn/linux/l-syncookie/?ca=dwcn-newsletter-linux Linux系統下的DDOS攻擊防範 http://hi.baidu.com/mo

linux核心優化,核心引數

轉自百度文庫,最後有一部分修改: 一、前言 本文件針對OOP8生產環境,具體優化策略需要根據實際情況進行調整;本文件將在以下幾個方面來闡述如何針對RedHat Enterprise Linux進行效能優化。 1)       Linux Proc檔案系統,通過對Proc檔案

Linux系統呼叫(如何從使用者空間進入核心空間)

系統呼叫概述         計算機系統的各種硬體資源是有限的,在現代多工作業系統上同時執行的多個程序都需要訪問這些資源,為了更好的管理這些資源程序是不允許直接操作的,所有對這些資源的訪問都必須有作業系統控制。也就是說作業系統是使用這些資源的唯一入口,而這個入口就是作業系

linux核心剖析---Linux系統呼叫(實現機制分析)

本文介紹了系統呼叫的一些實現細節。首先分析了系統呼叫的意義,它們與庫函式和應用程式介面(API)有怎樣的關係。然後,我們考察了Linux核心如何實現系統呼叫,以及執行系統呼叫的連鎖反應:陷入核心,傳遞系統呼叫號和引數,執行正確的系統呼叫函式,並把返回值帶回使用者空間。最後

編譯核心步驟

開始就是下載最新的核心,我用的FC5,核心已經很新了, 是2.6.8,在www.kernel.org下載了一個最新的核心,2.6.20的。   把kernel下載到隨便一個地方,tar:之後把壓縮包放到/usr/src/redhat/SOURCES/下面,其實這麼也可以這樣,

GCC 編譯

stand 空間 error 支持 預處理 -a 三級 net 錯誤 常用選項-E:只進行預處理,不編譯-S:只編譯,不匯編-c:只編譯、匯編,不鏈接-g:包含調試信息-I:指定include包含文件的搜索目錄-o:輸出成指定文件名 高級選項-v:詳細輸出編譯過程中所采用的

Linux啟動流程

linux 詳解 啟動流程 grub mbr 內核 linux啟動流程第一部分 Linux啟動基礎知識1.1 linux centos6.8啟動流程圖 BIOS加電自檢à加載MBRà加載啟動grubà加載內核à啟動/sbin/i

Linux netstat命令,高級面試必備

bytes tool head osi ngs 進行 pen 通信 詳細信息 簡介 Netstat 命令用於顯示各種網絡相關信息,如網絡連接,路由表,接口狀態 (Interface Statistics),masquerade 連接,多播成員 (Multicast Mem

linux top 命令

ctrl+ 一次 所有 使用方法 ase 隱藏 統計 ini 前臺 top命令是Linux下常用的性能分析工具,能夠實時顯示系統中各個進程的資源占用狀況,類似於Windows的任務管理器。下面詳細介紹它的使用方法。top - 01:06:48 up 1:22, 1 user

【轉】linux awk命令

column 環境變量 最後一行 工作流程 初始 文本文件 for循環 其中 cti 簡介 awk是一個強大的文本分析工具,相對於grep的查找,sed的編輯,awk在其對數據分析並生成報告時,顯得尤為強大。簡單來說awk就是把文件逐行的讀入,以空格為默認分隔符將每行切

Linux ls命令

-c 目錄 輸出 限制 普通 排序 當前 ls -l sna ls 命令可以說是Linux下最常用的命令之一。 -a 列出目錄下的所有文件,包括以 . 開頭的隱含文件。(後有詳解)-b 把文件名中不可輸出的字符用反斜杠加字符編號(就象在c語言裏一樣)的形式列出。-c 輸出