你再仔細查看一下相關的環境變數設置的是否正確?以及編譯選項是否正確?因為關於 gcc 編譯器的使用,有時候雖然你的源程序是正確的,但是由於環境變數的設置不正確(例如: INCLUDE、LIB等)、或者是雖然環境變數設置正確、但是編譯選項的不正確(例如:-Imy_include_file、-Lmy_lib_file等),都有可能導致程序無法正確編譯通過。所以必須要仔細檢查所有的細節問題。另外,你還必須保證 makefile 文件的語法必須是正確的,即:所需要編譯的源文件、以及中間代碼文件(*.o)等,它們之間的順序也是很重要的,如果這些順序不正確的話,那麼也會產生出錯信息。
B. 編譯Linux內核的具體步驟
1. 下載內核源代碼,並解壓家目錄
2. 設置好編譯環境
3. 修改好Makefile和.config
4. 執行make -j4
等一下,編譯就會結束了。
C. linux 編譯內核幾個常見問題解決方法
第一次把自己編譯的驅動模塊載入進開發板,就出現問題,還好沒花費多長時間,下面列舉出現的問題及解決方案
1:出現insmod: error inserting 'hello.ko': -1 Invalid mole format
法一(網上的):是因為內核模塊生成的環境與運行的環境不一致,用linux-2.6.27內核源代碼生成的模塊,可能就不能在linux-2.6.32.2內核的linux環境下載入,需要在linux-2.6.27內核的linux環境下載入。
a.執行 uname -r //查看內核版本
b.一般出錯信息被記錄在文件/var/log/messages中,執行下面命令看錯誤信息
# cat /var/log/messages |tail
若出現類似下面:
Jun 4 22:07:54 localhost kernel:hello: version magic '2.6.35.6-45.fc14.i686.PAE
' should be '2.6.35.13-92.fc14.i686.PAE'
則把 Makefile里的KDIR :=/lib/moles/2.6.35.6-45.fc14.i686.PAE/build1 改為
KDIR :=/lib/moles/2.6.35.13-92.fc14.i686.PAE/build1 //改成自己內核源碼路徑
(這里的build1是一個文件鏈接,鏈接到/usr/src/kernels/2.6.35.6-45.fc14.i686.PAE和13-92的)
然並卵,我的fedora 14 /usr/src/kernels下並沒有2.6.35.13-92.fc14.i686.PAE,只有2.6.35.13-92.fc14.i686,雖然不知道兩者有什麼區別,但改成2.6.35.13-92.fc14.i686還是不行,照樣這個問題,還好後來在看教學視頻的到啟發
法二:改的還是那個位置
KDIR :=/opt/FriendlyARM/linux-2.6.32.2 //把這里改成你編譯生成kernel的那個路徑
all:
$ (MAKE) -C $ (KDIR) M = $ (PWD) moles ARCH=arm CROSS_COMPILE=arm-linux- //加這句
2. [70685.298483] hello: mole license 'unspecified' taints kernel.
[70685.298673] Disabling lock debugging e to kernel taint
方法:在模塊程序中加入: MODULE_LICENSE("GPL");
3. rmmod: chdir(2.6.32.2-FriendlyARM): No such file or directory 錯誤解決
方法:lsmod 可查看模塊信息
即無法刪除對應的模塊。
就是必須在/lib/moles下建立錯誤提示的對應的目錄((2.6.32.2)即可。
必須創建/lib/moles/2.6.32.2這樣一個空目錄,否則不能卸載ko模塊.
# rmmod nls_cp936
rmmod: chdir(/lib/moles): No such file or directory
但是這樣倒是可以卸載nls_cp936,不過會一直有這樣一個提示:
rmmod: mole 'nls_cp936' not found
初步發現,原來這是編譯kernel時使用make moles_install生成的一個目錄,
但是經測試得知,rmmod: mole 'nls_cp936' not found來自於busybox,並不是來自kernel
1).創建/lib/moles/2.6.32.2空目錄
2).使用如下源碼生成rmmod命令,就可以沒有任何提示的卸載ko模塊了[luther.gliethttp]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
const char *modname = argv[1];
int ret = -1;
int maxtry = 10;
while (maxtry-- > 0) {
ret = delete_mole(modname, O_NONBLOCK | O_EXCL);//系統調用sys_delete_mole
if (ret < 0 && errno == EAGAIN)
usleep(500000);
else
break;
}
if (ret != 0)
printf("Unable to unload driver mole \"%s\": %s\n",
modname, strerror(errno));
}
3).把生成的命令復制到文件系統
# arm-linux-gcc -static -o rmmod rmmod.c
# arm-linux-strip -s rmmod
# cp rmmod /nfs/
cp /nfs/rmmod /sbin
代碼如下:
proc.c
[html] view plain
<span style="font-size:18px;">#include <linux/mole.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "proctest"
MODULE_LICENSE("GPL");
struct proc_dir_entry *Our_Proc_File;
int procfile_read(char *buffer,char **buffer_location,off_t offset, int buffer_length, int *eof, void *data)
{ int ret;
ret = sprintf(buffer, "HelloWorld!\n");
return ret;
}
int proc_init()
{ Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",procfs_name);
return -ENOMEM; }
Our_Proc_File->read_proc = procfile_read;//
// Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk("/proc/%s created\n", procfs_name);
return 0;
}
void proc_exit()
{ remove_proc_entry(procfs_name, NULL);
printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}
mole_init(proc_init);
mole_exit(proc_exit);</span></span></span></span></span>
[html] view plain
<span style="font-size:18px;">
ifneq ($(KERNELRELEASE),)
obj-m :=proc.o
else
KDIR :=/opt/FriendlyARM/linux-2.6.32.2
#KDIR :=/lib/moles/2.6.35.13-92.fc14.i686.PAE/build1
PWD :=$(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) moles ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif</span></span></span></span></span>
make後生成proc.ko,再在開發板上insmod proc.ko即可
執行 dmesg 就可以看到 產生的內核信息啦
D. linux下編譯內核 和 編譯 應用程序的問題
啟動要載入驅動模塊,就要先確定有這個模塊存在,然後載入它做一些准備。所以要編譯內核。。。 內核是操作系統最基本的部分。它是為眾多應用程序提供對計算機硬體的安全訪問的一部分軟體
E. 如何編譯內核及製作RPM包
前言
要編譯自內核能各種同答案列舉:
1 研究習內核源碼
2 支持新硬體或者打某項內核功能
3 升級內核更新版本
4 按自要求定製優化內核功能
種種...
折騰需要理由我說面直接進入主題
編譯式
編譯內核種式kernel.org載選擇載需要版本內核源碼
:linux-2.6.32-rc1.tar.bz2載內核源碼/home/user/目錄進入載目錄解壓壓縮包
#cd /home/user/
#tar -xjvf linux-2.6.32-rc1.tar.bz2
二 准備編譯環境
始前首先確認面軟體包已經安裝(編譯標普華4.0直接全部安裝CD3保證條件)
* rpmdevtools
* yum-utils
fedora系統使用命令安裝:
#yum install yum-utils rpmdevtools
1. rpmbuild命令工作所需目錄樹面命令完該操作手建立目錄樹
命令建立:
#rpmdev-setuptree
命令/usr/src/rpmbuild/目錄目錄結構(位置沒則能前用戶目錄).
# tree /usr/src/rpmbuild/
rpmbuild/
|-- BUILD
|-- RPMS
|-- SOURCES
|-- SPECS
`-- SRPMS
面部rpmbuild環境建立rpm
3. 安裝內核源碼包需要依賴組件(跳步操作)
su -c 'yum-builddep kernel-.src.rpm'
4.安裝內核源碼系統默認目錄/usr/src/neoshine:
rpm -Uvh kernel-.src.rpm
三 配置內核(config配置文件)
面介紹何解源碼包並修改配置重新打包源碼
1. 解源碼包並打所補丁BUILD目錄
cd ~/rpmbuild/SPECS
rpmbuild -bp --target=`uname -m` kernel.spec
kernel源碼找:
/usr/src/neoshine/rpmbuild/BUILD/kernel-/linux-. directory
配置內核源碼
1. 進入內核源碼:
cd ~/rpmbuild/BUILD/kernel-2.6.$ver/linux-2.6.$ver.$arch/
2. 復制/boot/config*配置文件源碼目錄,config文件已經配或者其備份kernel配置文件:
cp /boot/config2.6- 2.6.$ver.$arch .config
3. 先檢查kernel配置新增選項:
make oldconfig
4. 定製內核功能關閉initrd支持選項執行圖形化內核配置工具:
make menuconfig
註:generic setup選項找initial RAM system and RAM disk(initramfs and initrd) support 項取消編譯同確保跟文件系統應驅系統所存儲器應驅都已經編譯內核(否則啟系統).
5. .config文件第行改面內容(注意:沒行面編譯報錯)
# i386
6. 拷貝.configSOURCES/:
cp .config ../SOURCES/config-$arch
四 編譯新內核
1. 面始准備編譯新內核包
打SPEC/kernel.spec
vim SPEC/kernel.spec
改變面行內容定製自內核擴展名(fc10類):
%define buildid .
步新內核rpm包程需要編譯內核源碼包
使用面命令新內核源碼包
rpmbuild -bb --with baseonly --without debuginfo --target=`uname -m` kernel.spec
參數說明:bb表示編譯二進制包即源碼包without debuginfo 表示沒調試信息
target=`uname -r`表示應前平台內核包
面命令功執行完BUILD/i686目錄新內核安裝包
五 安裝新內核
rpm -ivh kernel-$ver-$arch.rpm
步操作自安裝內核boot目錄安裝應內核模塊/lib/moles/目錄並且新內核應grub引導菜單
修改grub引導菜單格式
title new kernel
kernel /boot/vmlinuz-$ver-$arch root=/dev/sdax(hdax)
注意處要使用uuid指定跟文件系統(能掛載根區導致內核死機)要再加顯示相關參數(內核支持應設置看黑黑屏幕)
至禁用initrd新內核配置安裝完畢
F. 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/moles/`uname -r`/build/.config
d) 如果你是移植Linux到嵌入式系統,則還要再下載安裝交叉編譯工具鏈。
例如,你的目標單板CPU可能是arm或mips等cpu,則安裝相應的交叉編譯工具鏈。安裝後,需要將工具鏈路徑添加到PATH環境變數中。例如,你安裝的是arm工具鏈,那麼你在shell中執行類似如下的命令,假如有類似的輸出,就說明安裝好了。
[root@localhost 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 ing conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
註:arm的工具鏈,可以從這里下載:回復「ARM」即可查看。
二、設置編譯目標
在配置或編譯內核之前,首先要確定目標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/moles/`uname -r`/build/.config
這里順便多說兩句,PC機內核的配置文件,選擇的功能真是多。不編不知道,一編才知道。Linux發行方這樣做的目的,可能是想讓所發行的Linux能夠滿足用戶的各種需求吧。
b) 執行make menuconfig對此配置做一些需要的修改,退出時選擇保存,就將新的配置更新到.config文件中了。
注
G. Linux內核編譯的具體操作過程及注意問題
你好,樓主:
1、配置.config文件,將你要編譯的配置XXX_config准備好,使用make XXX_config來進行配置;
2、這時你就可以在內核根目錄下進行make menuconfig來使用圖形界面配置內核選項,配置後保存即可;
3、最後只需要使用make或者make uImage生成相應的鏡像即可。
注意問題多在config這里,如果配置時報錯,可嘗試make clobber來清除原來的依賴關系。
H. 如何編譯一個內核
1. 預備工作
我推薦使用root用戶執行下面所有的步驟. 如果你還沒有創建root登陸口令, 請運行下面的命令:
sudo passwd root
然後, 以root身份登陸:
su
如果你想使用一般用戶來替代root用戶, 記住在本文所有命令前輸入sudo, 比如當我運行
apt-get update
你需要運行下面的命令來替代, 等.
sudo apt-get update
1.1 Ubuntu 6.10上的/bin/sh ("Edgy Eft")
在Ubuntu 6.10, /bin/sh預設是一個鏈接到/bin/dash的字元鏈接. 當你編譯軟體源代碼的時候, /bin/dash似乎還存在問題. 至少我已經遇到了一些問題. 所以我把/bin/sh鏈接到了/bin/bash.
如果你使用Ubuntu 6.10, 現在你可以運行:
rm -f /bin/sh
ln -s /bin/bash /bin/sh
2 安裝必需的軟體包 (為內核編譯做准備)
首先我們升級軟體(包)庫:
apt-get update
然後我們安裝所有需要的軟體包:
apt-get install kernel-package libncurses5-dev fakeroot wget bzip2
3 下載內核源代碼
接下來我們下載需要的內核到/usr/src目錄(去www.kernel.org網站下載你需要的內核版本, 比如. linux-2.6.18.1tar.bz2(你可以從這里下載所有的2.6內核: http://www.kernel.org/pub/linux/kernel/v2.6/). 然後下載到/usr/src目錄:
cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.1.tar.bz2
然後解壓內核源代碼, 創建一個指向內核源代碼目錄的linux字元鏈接:
tar xjf linux-2.6.18.1.tar.bz2
ln -s linux-2.6.18.1 linux
cd /usr/src/linux
4 給內核源代碼打補丁(可選)
有時你的預設內核不支持新買的設備, 你需要安裝新的驅動. 或者你需要使用虛擬技術或其它高級的技術, 而這些現有的內核都不支持. 這樣情況下你需要給給內核源代碼打補丁(當然補丁已經發布..)
現在我們假設你已經下載需要的補丁(以下例子我叫它patch.bz2)到/usr/src. 運行下面的命令給內核源代碼直接打上補丁(你的用戶必須位於/usr/src/linux目錄):
bzip2 -dc /usr/src/patch.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch.bz2 | patch -p1
第一個命令用於測試, 對內核沒有任何影響. 如果沒有顯示錯誤, 你可以運行第二個命令給內核打補丁. 如果第一個命令有誤, 請務繼續的操作!
你也能夠通過內核的prepatches方式打補丁. 比如, 如果你需要一個功能, 而這個功能僅存在於2.6.19-rc4中,
正式完整的內核版本仍沒有發布, 而patch-2.6.19-rc4.biz2已經發布. 你可以把這個補丁打到2.6.18的內核源代碼中,
但請不要達到2.6.18.1或2.6.18.2, 等. 這個規則在接下來的網頁中註明:
http://kernel.org/patchtypes/pre.html
prepatches等同於linux中的測試發行; 他們位於存檔的測試目錄中,
我們可以使用patch(1)工具對上一個完整發行版(版本號分三部分)打補丁(例如, 2.6.12-rc4
prepatch只可以給2.6.11內核源代碼打補丁, 而不是2.6.11.10.)
所以如果你想編譯2.6.19-rc4內核, 你必須在步驟3.1下載2.6.18(http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2)替代2.6.18.1內核源代碼!
下面是如何給2.6.18打上2.6.19-rc4補丁:
cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.19-rc4.bz2
cd /usr/src/linux
bzip2 -dc /usr/src/patch-2.6.19-rc4.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch-2.6.19-rc4.bz2 | patch -p1
5. 配置內核
使用當前工作內核的配置文件做為新內核配置文件的基礎是一個很好的主意. 因此我們拷貝已存的配置文件到/usr/src/linux:
cp /boot/config-`uname -r` ./.config
然後運行
make menuconfig
然後我們看到內核的配置菜單. 移動綠色游標到 Load an Alternate Configuration File 行後選擇.config文件(包含了當前工作內核的配置)做為配置文件:
然後瀏覽內核配置菜單, 選擇你需要的功能. 完成配置後, 選擇Exit, 回答下面的問題(Do you wish to save your new kernel configuration? 你希望保存新的內核配置嗎?), 選擇Yes:
6 構建內核
執行下面命令來構建內核:
make-kpkg clean
fakeroot make-kpkg --initrd --append-to-version=-custom -j4 kernel_image kernel_headers
如果要進行交叉編譯,可以進行確定架構機器上的編譯。
fakeroot make-kpkg --initrd --append-to-version=-custom -j4 --arch i386 kernel_image kernel_headers (比如在64位機器上編譯32位的內核)
在--append-to-version= 後面你可以寫上任何字元串來區別內核版本, 但是必須以" - "符號開始而且後面不包括任何空格.
保持耐心, 內核編譯需要一定時間, 主要看你的內核配置和處理器速度.
7 安裝新內核
在成功構建內核後, 你在/usr/src目錄能發現兩個.deb軟體包.
cd /usr/src
ls -l
在我的測試系統上, 他們分別名為
linux-image-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb
(包含了實際的內核) 和
linux-headers-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb
(包含了需要的文件, 用於以後需要編譯額外的內核模塊). 我是這樣安裝的:
dpkg -i linux-image-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb
dpkg -i linux-headers-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb
(現在你甚至能夠拷貝這兩個.deb文件到其它的Ubuntu系統, 通過上面的方式安裝. 你將不再需要編譯內核.)
然後檢查 /boot/grub/menu.lst文件, 現在你將能發現新內核使用的兩個引導配置塊:
vi /boot/grub/menu.lst
在我測試系統上已經添加好的引導配置塊是這樣的:
title Ubuntu, kernel 2.6.18.1-custom
root (hd0,0)
kernel /boot/vmlinuz-2.6.18.1-custom root=/dev/sda1 ro quiet splash
initrd /boot/initrd.img-2.6.18.1-custom
savedefault
boot
title Ubuntu, kernel 2.6.18.1-custom (recovery mode)
root (hd0,0)
kernel /boot/vmlinuz-2.6.18.1-custom root=/dev/sda1 ro single
initrd /boot/initrd.img-2.6.18.1-custom
boot
現在重啟系統:
shutdown -r now
如果一切進展順利, 你的新內核正常工作. 你還可以通過運行下面命令來檢查新內核是否運行:
uname -r
這將會顯示如:
2.6.18.1-custom
如果系統沒有起來, 重啟一下, 你會看到:
按ESC進入GRUB菜單:
選擇你以前的內核啟動系統, 現在你能再次嘗試編譯新的工作內核. 不要忘記從/boot/grub/menu.1st文件中移去不需要的引導內核信息.