1. 程式人生 > >linux 核心配置機制(make menuconfig、Kconfig、makefile)講解

linux 核心配置機制(make menuconfig、Kconfig、makefile)講解

前面我們介紹模組程式設計的時候介紹了驅動進入核心有兩種方式:模組和直接編譯進核心,並介紹了模組的一種編譯方式——在一個獨立的資料夾通過makefile配合核心原始碼路徑完成

    那麼如何將驅動直接編譯進核心呢?

    在我們實際核心的移植配置過程中經常聽說的核心裁剪又是怎麼麼回事呢?

我們在進行linux核心配置的時候經常會執行make menuconfig這個命令,然後螢幕上會出現以下介面:


這個介面是怎麼生成的呢?

跟我們經常說的核心配置與與編譯又有什麼關係呢?

下面我們藉此來講解一下linux核心的配置機制及其編譯過程。

Linux核心的配置系統由三個部分組成,分別是:

   1、Makefile:分佈在 Linux 核心原始碼根目錄及各層目錄中,定義 Linux 核心的編譯規則;

    2、配置檔案(config.in(2.4核心,2.6核心)):給使用者提供配置選擇的功能;

    3、配置工具:包括配置命令直譯器(對配置指令碼中使用的配置命令進行解釋)和配置使用者介面(提供基於字元介面、基於 Ncurses 圖形介面以及基於 Xwindows 圖形介面的使用者配置介面,各自對應於 Make config、Make menuconfig 和 make xconfig)。

  這些配置工具都是使用指令碼語言,如 Tcl/TK、Perl 編寫的(也包含一些用 C 編寫的程式碼)。本文並不是對配置系統本身進行分析,而是介紹如何使用配置系統。所以,除非是配置系統的維護者,一般的核心開發者無須瞭解它們的原理,只需要知道如何編寫 Makefile 和配置檔案就可以。

二、makefile menuconfig過程講解

當我們在執行make menuconfig這個命令時,系統到底幫我們做了哪些工作呢?

這裡面一共涉及到了一下幾個檔案我們來一一講解

Linux核心根目錄下的scripts資料夾

arch/$ARCH/Kconfig檔案、各層目錄下的Kconfig檔案

Linux核心根目錄下的makefile檔案、各層目錄下的makefile檔案

Linux核心根目錄下的的.config檔案、arm/$ARCH/下的config檔案

Linux核心根目錄下的 include/generated/autoconf.h檔案

1)scripts資料夾存放的是跟make menuconfig配置介面的圖形繪製相關的檔案,我們作為使用者無需關心這個資料夾的內容

2)當我們執行make menuconfig命令出現上述藍色配置介面以前,系統幫我們做了以下工作:

    首先系統會讀取arch/$ARCH/目錄下的Kconfig檔案生成整個配置介面選項(Kconfig是整個linux配置機制的核心),那麼ARCH環境變數的值等於多少呢?

它是由linux核心根目錄下的makefile檔案決定的,在makefile下有此環境變數的定義:


或者通過 make ARCH=arm menuconfig命令來生成配置介面,預設生成的介面是所有引數都是沒有值的

    比如教務處進行考試,考試科數可能有外語、語文、數學等科,這裡相當於我們選擇了arm科可進行考試,系統就會讀取arm/arm/kconfig檔案生成配置選項(選擇了arm科的卷子),系統還提供了x86科、milps科等10幾門功課的考試題

3)假設教務處比較“仁慈”,為了怕某些同學做不錯試題,還給我們準備了一份參考答案(預設配置選項),存放在arch/$ARCH/configs下,對於arm科來說就是arch/arm/configs資料夾:


    此資料夾中有許多選項,系統會讀取哪個呢?核心預設會讀取linux核心根目錄下.config檔案作為核心的預設選項(試題的參考答案),我們一般會根據開發板的型別從中選取一個與我們開發板最接近的系列到Linux核心根目錄下(選擇一個最接近的參考答案)

#cp arch/arm/configs/s3c2410_defconfig .config

4).config

    假設教務處留了一個心眼,他提供的參考答案並不完全正確(.config檔案與我們的板子並不是完全匹配),這時我們可以選擇直接修改.config檔案然後執行make menuconfig命令讀取新的選項

    但是一般我們不採取這個方案,我們選擇在配置介面中通過空格、esc、回車選擇某些選項選中或者不選中,最後儲存退出的時候,Linux核心會把新的選項(正確的參考答案)更新到.config中,此時我們可以把.config重新命名為其它檔案儲存起來(當你執行make distclean時系統會把.config檔案刪除),以後我們再配置核心時就不需要再去arch/arm/configs下考取相應的檔案了,省去了重新配置的麻煩,直接將儲存的.config檔案複製為.config即可.

5)經過以上兩步,我們可以正確的讀取、配置我們需要的介面了

那麼他們如何跟makefile檔案建立編譯關係呢?

當你儲存make menuconfig選項時,系統會除了會自動更新.config外,還會將所有的選項以巨集的形式儲存在

Linux核心根目錄下的 include/generated/autoconf.h檔案下


核心中的原始碼就都會包含以上.h檔案,跟巨集的定義情況進行條件編譯。

當我們需要對一個檔案整體選擇如是否編譯時,還需要修改對應的makefile檔案,例如:


    我們選擇是否要編譯s3c2410_ts.c這個檔案時,makefile會根據CONFIG_TOUCHSCREEN_S3C2410來決定是編譯此檔案,此巨集是在Kconfig檔案中定義,當我們配置完成後,會出現在.config及autconf中,至此,我們就完成了整個linux核心的編譯過程。

    最後我們會發現,整個linux核心配置過程中,留給使用者的介面其實只有各層Kconfig、makefile檔案以及對應的原始檔。

    比如我們如果想要給核心增加一個功能,並且通過make menuconfig控制其聲稱過程

    首先需要做的工作是:修改對應目錄下的Kconfig檔案,按照Kconfig語法增加對應的選項;

    其次執行make menuconfig選擇編譯進核心或者不編譯進核心,或者編譯為模組,.config檔案和autoconf.h檔案會自動生成;

    最後修改對應目錄下的makefile檔案完成編譯選項的新增;

    最後的最後執行make zImage命令進行編譯。

三、具體例項

下面我們以前面做過的模組實驗為例,講解如何通過make menuconfig機制將前面單獨編譯的模組編譯進核心或編譯為模組

假設我已經有了這麼一個驅動:

modules.c

[cpp] view plaincopyprint?
  1. #include <linux/module.h>       /*module_init()*/
  2. #include <linux/kernel.h> /* printk() */
  3. #include <linux/init.h>       /* __init __exit */
  4. #define DEBUG   //open debug message
  5. #ifdef DEBUG
  6. #define PRINTK(fmt, arg...)     printk(KERN_WARNING fmt, ##arg)
  7. #else
  8. #define PRINTK(fmt, arg...)     printk(KERN_DEBUG fmt, ##arg)
  9. #endif
  10. /* Module Init & Exit function */
  11. staticint __init myModule_init(void)  
  12. {  
  13. /* Module init code */
  14.     PRINTK("myModule_init\n");  
  15. return 0;  
  16. }  
  17. staticvoid __exit myModule_exit(void)  
  18. {  
  19. /* Module exit code */
  20.     PRINTK("myModule_exit\n");  
  21. return;  
  22. }  
  23. module_init(myModule_init);  
  24. module_exit(myModule_exit);  
  25. MODULE_AUTHOR("dengwei");                          /*模組作者,可選*/
  26. MODULE_LICENSE("GPL");                             /*模組許可證明,描述核心模組的許可許可權,必須*/
  27. MODULE_DESCRIPTION("A simple Hello World Module"); /*模組說明,可選*/
#include <linux/module.h>       /*module_init()*/
#include <linux/kernel.h>	/* printk() */
#include <linux/init.h>		/* __init __exit */

#define DEBUG	//open debug message

#ifdef DEBUG
#define PRINTK(fmt, arg...)		printk(KERN_WARNING fmt, ##arg)
#else
#define PRINTK(fmt, arg...)		printk(KERN_DEBUG fmt, ##arg)
#endif

/* Module Init & Exit function */
static int __init myModule_init(void)
{
	/* Module init code */
	PRINTK("myModule_init\n");
	return 0;
}

static void __exit myModule_exit(void)
{
	/* Module exit code */
	PRINTK("myModule_exit\n");
	return;
}

module_init(myModule_init);
module_exit(myModule_exit);

MODULE_AUTHOR("dengwei");                          /*模組作者,可選*/
MODULE_LICENSE("GPL");                             /*模組許可證明,描述核心模組的許可許可權,必須*/
MODULE_DESCRIPTION("A simple Hello World Module"); /*模組說明,可選*/

Step1:將modules.c拷到drivers/char/目錄下(這個資料夾一般存放常見的字元驅動) Step2: vi driver/char/Kconfig,在     config DEVKMEM後新增以下資訊 config MODULES
tristate "modules device support"
default y
help
 Say Y here,the modules will be build in kernel.
 Say M here,the modules willbe build to modules.
 Say N here,there will be nothing to be do. 
Step3:make menuconfig Device driver-character devices            [*]modules device suppor Step4:vi driver/char/Makefile,在js-rtc後新增 obj-$(CONFIG_MODULES)+= modules.o
CONFIG_MODULES 必須跟上面的Kconfig中保持一致,系統會自動新增CONFIG_字首

modules.o必須跟你加入的.c檔名一致

最後執行:make zImage modules就會被編譯進核心中

第三步:

Step3:make menuconfig Device driver-character devices            [M]modules device suppor 把星號在配置介面通過空格改為M,最後執行make modules,在driver/char/目錄下會生成一個modules.ko檔案

跟我們前面講的單獨編譯模組效果一樣,也會生成一個模組,將它考入開發板執行insmod moudles.ko,即可將生成的模組插入核心使用