gcc makefile

GCC程序編譯linux

GCC (GNU C Compiler) 編譯器,GNU 自己是一個計劃,目標是開發出一套徹底免費的操做系統,GCC就是他推出很好的多平臺編譯器,不論是嵌入式應用程序開發 仍是作驅動開發內核開發 嵌入式內核開發 都須要用到它,用它能夠編譯連接C C++等程序,c++

GCC 支持的體系結構有40餘種,常見的有X86  ARM POWERPC 等等同時GCC還能運行在不一樣的操做系統中,如LINUX WINDOWS Solaris 等,GCC除支持C語言外還支持多種語言,如C++ ,Ada,Java 等程序員

在LINUX系統中,可執行的文件沒有統一的後綴的,系統從文件的屬性(x r w )來區分可行文件 和 不可執行文件shell

GCC編譯程序時,編譯過程能夠分爲四個階段:預處理 編譯 彙編(Assembling)連接數據庫

預處理:這個階段 主要處理源文件中的 #ifdef  #include  #define 等命令,這個中間階段會生產一個 *.i文件 實際工做一般不會專門生產這種文件, gcc -E test.c -o test.i編程

編譯:這個階段把預處理後的結果編譯成彙編或者目標模塊,輸入的是中間文件 *.i,編譯後生產的是 彙編語言文件 *.s  這個階段對應的GCC命令以下所示。less

彙編:這個階段把編譯出來的結果彙編成具體的CPU上的目標代碼模塊,輸入的是彙編文件*.s,輸出的是機器語言*.o,*o這個也叫作目標文件,這個文件雖然也是機器代碼,可是不可執行, gcc -c test.s -o test.o函數

連接:這個階段 把多個目標代碼模塊鏈接生產一個大的目標模塊,輸入的是機器代碼文件*.o 還有其餘的機器代碼文件和庫文件  輸出的是一個可執行的二進制代碼文件 gcc test.o  -o test工具

gcc -o test  first.c  second.c  third.c 該命令同時編譯三個源文件 再將它們連成一個可執行的程序test( 這裏不管是一個原文件仍是多個原文件  被編譯和鏈接的原文件中必須有且僅有一個main函數)優化

GCC 經過後綴來區分輸入文件的類別,.c .a(庫文件) .C( .cc .cxx C++源文件)  .h .l(通過預處理的的C源文件) .ii(通過預處理的的C++源文件) .o(編譯後的目標文件).s (彙編源文件) .S(通過預編譯的彙編源代碼文件)

 

用makefile本質也使用gcc,沒有差異。你徹底能夠用gcc命令編譯模塊

 

GCC的使用

GCC [options] [filenames] ,options 編譯器所須要的編譯選項,gcc大約有100多個編譯選項, filenames要編譯的文件名

介紹編譯選項:

 

-D MACRO 定義宏 等於在程序中使用#define MACRO  「-DMODULE -D__KERNEL__ -DLINUX」 實際上是GCC命令行的用法,等效於在一個頭文件中定義:#define  MODULE     #define  __KERNEL__  #define  LINUX

-pipe 在編譯過程當中 生產各類臨時文件

 

-o output_filename 肯定可執行文件的名稱爲output_filename 默認是a.o(ut)

-v 把整個過程的輸出信息都打印出來

-E 輸出預處理的結果,不進行編譯 彙編 和 鏈接

-C(大寫) 配合 -E使用 讓預處理後的結果把註釋保留  以方便閱讀 

-S 只將源文件編譯成彙編代碼,不進行彙編 和 鏈接

-c 只編譯 不鏈接成爲可執行文件 編譯器只是由輸入的.c等代碼文件生成.o後綴的目標文件

-g 產生調試工具(GNU 的gdb)所必要的符號信息,要想對編譯出的程序進行調試,就必須加入這個選項,也就是把調試開關打開

-O 對程序進行優化編譯,連接

-O2 優化程度更深一些 ,優化後的程序 執行時候,要的時間比沒有優化的要小,運行程序時 能夠time 來計算程序的運行時間 time ./outimize(程序名)

–I 當咱們在編譯一個程序的時候,包含了一個頭文件假設叫作<a.h>,而a.h沒有在include這個目錄中,一個咱們能夠把這個頭文件拷到這個目錄中,另外一個咱們能夠用指令來添加一個頭文件的路徑,能夠有多個 -I 來指定過個路徑 ,如指定 gcc –I (大寫艾) gcc –I/home/lesson/part/3(頭文件所在的目錄) 編譯的文件名 –o 輸出的文件名 

-L  添加庫的 同理-I 搜尋庫文件( *.a )的路徑 ( -Ldir ) 

-l(小艾爾) 在連接時 GCC默認連接C庫,其餘不會連接的,若是你要用到其餘的庫如數學庫,你要先指明,或者你本身的庫,如數學庫是libm.a 咱們寫時能夠省略掉前面lib 與後面的.a 他會自動加 寫成 –lm 就行 gcc foo.c –L/home.lib –lfoo –o foo

-static 靜態連接庫文件 靜態連接區別於動態連接:

Gcc 默認採用動態連接,.so爲動態連接庫 .a爲靜態庫,靜態連接時,鏈接器找出程序所需的函數,而後將他們拷貝到可執行文件中,組成一個文件,一旦連接成功,這個靜態庫也就不須要了,而動態連接,是在程序內留下一個標記指明當程序執行時首先必須載入這個庫,動態連接節省空間,gcc –static hello.c –o hello

-wall  生產因此警告信息 推薦你們使用這個選項

-w(小)  不生產任何警告信息

-D MACRO 定義宏 等於在程序中使用#define MACRO

///////////////////////////////////////////////////////////

LINUX 2.4 內核文件 包括頭文件 大概有一萬個 2.6大概有2萬個

Linux 程序員 必須學會使用GNU make來構建和管理 本身的軟件工程,GNU的make 可以使整個軟件工程的編譯連接只須要一個命令就能夠完成。Make 只是一個命令,在執行時,須要一個命名爲makefile的文件,makefile 文件描述了整個工程的編譯鏈接等的規則,包括工程中的哪些源文件須要編譯以及如何編譯,須要建立那些庫文件,以及如何建立這些庫文件,如何最後產生咱們想要得可執行文件

在大型的開發項目中,一般有幾十到上百個的源文件,若是每次均手工鍵入 gcc 命令進行編譯的話,則會很是不方便。所以,人們一般利用 make 工具來自動完成編譯工做。這些工做包括:若是僅修改了某幾個源文件,則只從新編譯這幾個源文件;若是某個頭文件被修改了,則從新編譯全部包含該頭文件的源文件。利用這種自動編譯可大大簡化開發工做,避免沒必要要的從新編譯。實際上,make 工具經過一個稱爲 makefile 的文件來完成並自動維護編譯工做。makefile 須要按照某種語法進行編寫,其中說明了如何編譯各個源文件並鏈接生成可執行文件,並定義了源文件之間的依賴關係。當修改了其中某個源文件時,若是其餘源文件依賴於該文件,則也要從新編譯全部依賴該文件的源文件。makefile 文件是許多編譯器,包括 Windows NT 下的編譯器維護編譯信息的經常使用方法,只是在集成開發環境中,用戶經過友好的界面修改 makefile 文件而已。默認狀況下,GNU make 工具在當前工做目錄中按以下順序搜索 makefile:個人2.6.18的內核默認的呃是 Makefile 而不是makefile
* GNUmakefile
* makefile
* Makefile


在 UNIX 系統中,習慣使用 Makefile 做爲 makfile 文件。若是要使用其餘文件做爲 makefile,則可利用類
似下面的 make 命令選項指定 makefile 文件:
$ make -f Makefile.debug

-----------------------------------------------------------------------

makefile 基本結構
makefile 中通常包含以下內容:
* 須要由 make 工具建立的項目,一般是目標文件和可執行文件。一般使用「目(target)」一詞來表示要建立的項目。
* 要建立的項目依賴於哪些文件。
* 建立每一個項目時須要運行的命令。

Makefile裏面包含了不少條規則:規則用於說明如何生存一個或者多個目標文件,描述的是在什麼狀況下,如何重建規則的目標文件 一般規則包含 目標的依賴關係  和重建的目標命令 

通常規則的格式是:

目標:依賴

命令

一個規則能夠有多個命令行,每一條命令佔一行,每個命令行必須以TAB字符開始,TAB字符告訴make此行是一個命令行,make按照命令完成相應的動做

# This makefile just is a example. #表註釋

//////////////////////////////////////////////////

edit: main.o kbd.o  command.o \

       insert.o ....

(TAB)cc -o edit  main.o kbd.o  command.o \

     insert.o ....

main.o: main.c  defs.h

(TAB)cc -c main.c

insert.o:insert.c dfs.h

(TAB)cc -c insert.c

.......

////////////上面寫法很差 由於不方便更新 改動/////////////////

obj = main.o kbd.o command.o \

     insert.o .....

edit: $(obj)

     cc -o edit $(obj)

//////////////////make 的編譯隱含規則/////////////////////////

編譯時make會自動爲這個.o文件尋找合適的依賴文件(對應得.c文件 對應是指除了後綴 其他部分都相同的兩個文件)同時使用正確的命令來創建這個目標文件 這樣寫規則時 能夠省略掉命令行 同時也能夠省略掉 與*.o同名的C文件 只要在依賴關係中給出 包含的各個頭文件 就能夠

obj = main.o kbd.o command.o \

     insert.o .....

edit: $(obj)

     cc -o edit $(obj)

main.o:defs.h

insert.o:dfs.h

/////////////////////另外一類根據依賴關係分類法/////////////////////

obj = main.o kbd.o command.o \

     insert.o .....

edit: $(obj)

     cc -o edit $(obj)

$(obj):defs.h

 main.o kbd.o command.o:d.h

 insert.o  command.o:k.h

//////////////////////////////////////////////////

在makefile中規則的順序是很重要的,由於makefile中只應該有一個最終目標,其餘的目標都是被這個目標所連帶出來的,因此必定要讓make知道你的最終目標是什麼,makefile中目標可能有不少,若是沒有指定,默認第一條規則的目標將被確立爲最終的目標。

當在shell中輸入 make命令後,make將讀取當前目錄下 的Makefile 文件,並將Makefile中的第一個目標作爲其執行的「終極目標」,開始處理第一個規則「終極目標」,處理這個過程 先處理他的依賴條件 根據這個條件 作出相應得動做 對後面的文件

Makefile中 把那些沒有任何依賴只有執行動做的目標稱爲「僞目標」,phony targets

.PHONY:clean PHONY指明clean爲一個僞目標

Clean:

 Rm –f hello …

-------------------------------------------------------------------------

makefile 變量
GNU的make 工具備許多便於表達依賴性關係以及創建目標的命令的特點。其中之一就是變量或宏的定義能力。若是你要以相同的編譯選項同時編譯十幾個 C 源文件,而爲每一個目標的編譯指定冗長的編譯選項的話,將是很是乏味的。但利用簡單的變量定義,可避免這種乏味的工做:

# Define macros for name of compiler
CC = gcc

# Define a macr o for the CC flags
CCFLAGS = -D_DEBUG -g -m486

# A rule for building a object file
test.o: test.c test.h
    $(CC) -c $(CCFLAGS) test.c

在上面的例子中,CC 和 CCFLAGS 就是 make 的變量。GNU make 一般稱之爲變量,而其餘 UNIX 的 make
工具稱之爲宏,實際是同一個東西。在 makefile 中引用變量的值時,只需變量名以前添加 $ 符號,如
上面的 $(CC) 和 $(CCFLAGS)。

GNU make 的主要預約義變量
GNU make 有許多預約義的變量,這些變量具備特殊的含義,可在規則中使用。下面給出了一些主要的
預約義變量,除這些變量外,GNU make 還將全部的環境變量做爲本身的預約義變量。
預約義變量                含義
$*              不包含擴展名的目標文件名稱。
$+              全部的依賴文件,以空格分開,並以出現的前後爲序,可能包含重複的依賴文件。
$<              第一個依賴文件的名稱。
$?              全部的依賴文件,以空格分開,這些依賴文件的修改日期比目標的建立日期晚。
$@              目標的完整名稱。$@表明目標
$^              全部的依賴文件,以空格分開,不包含重複的依賴文件。
$%              若是目標是歸檔成員,則該變量表示目標的歸檔成員名稱。例如,若是目標名稱
                爲 mytarget.so(image.o),則 $@ 爲 mytarget.so,而 $% 爲 image.o。
AR              歸檔維護程序的名稱,默認值爲 ar。
ARFLAGS         歸檔維護程序的選項。
AS              彙編程序的名稱,默認值爲 as (編譯器)。
ASFLAGS         彙編程序的選項。
CC              C 編譯器的名稱,默認值爲 cc(編譯器)。
CCFLAGS         C 編譯器的選項。
CPP             C 預編譯器的名稱,默認值爲 $(CC) -E。
CPPFLAGS        C 預編譯的選項。
CXX             C++ 編譯器的名稱,默認值爲 g++。
CXXFLAGS        C++ 編譯器的選項。
FC              FORTRAN 編譯器的名稱,默認值爲 f77。
FFLAGS          FORTRAN 編譯器的選項。

//////////////////////////////////////////////////////////////////

咱們系統中裝了gcc編譯器,功能強大,但咱們在編譯一個文件時 便可用cc 也能夠用gcc 他們的關係是

 

Linux CC與Linux GCC的區別歸納介紹。從名字上看,老的unix系統的CC程序叫作C Compiler。但GCC這個名字按GNU的說法叫作Gnu Compiler Collection。由於gcc包含不少編譯器(C, C++, Objective-C, Ada, Fortran,and   Java)。因此它們是不同的,一個是一個古老的C編譯器,一個是編譯器的Gnu的編譯器的集合(Gcc裏的C編譯器比CC強大太多了,因此你不必用CC)。當你調用gcc時不必定是調用的C/C++編譯器,是gcc根據文件擴展名自動識別並調用對應的編譯器,具體可查閱$man gcc。

你是下載不到CC的,緣由是:CC來自於昂貴的Unix系統,CC是商業軟件,要想用你須要打電話,寫訂單,而不是打開你的Browser去download。

linux下的cc是gcc的符號連接。能夠經過$ls –l /usr/bin/cc來簡單察看.而編譯時看到的控制檯輸出CC則是一個指向gcc的變量,該變量是make程序的內建變量,就算你在Makefile中沒有CC= ,該變量也會存在,並默認指向gcc。cc的符號連接和變量存在的意義在於源碼的移植性,能夠方便的用GCC來編譯老的用cc編譯的unix軟件,甚至連Makefile都不要改。並且也便於linux程序在unix下編譯。

近幾年的一個新狀況是愈來愈多的unix用戶,據我所知像solaris,bsd用戶也不太使用CC了,人們都必定要裝一個gcc,用它來編譯C/C++程序。緣由顯而易見,gcc足夠強大,健壯。支持估計目前爲止只有它支持的ISO c/c++ 新特性。固然你最好不要使用night版本的gcc

 make是用來編譯的,它從Makefile中讀取指令,而後編譯。

make install是用來安裝的,它也從Makefile中讀取指令,安裝到指定的位置,make install 就是讀取makefile文件中 install:對應得語句 相似於 make clean

 

Make是一個解釋Makefile文件中指令的命令工具,其最基本的功能就是經過Makefile文件來描述源程序之間的相互關係並自動維護編譯工做,它會告知系統以何種方式編譯和連接程序。一旦肯定完成Makefile文件,剩下的工做就只是在Linux終端下輸入make這樣的一個命令,就能夠自動完成全部的編譯任務,並生成目標程序。工程狀況下GNU make的工做流程以下。

1、查找當前目錄下的Makefile文件

2、初始化文件中的變量

3、分析Makefile中的全部規則

4、爲全部的目標文件創建依賴關係

5、根據依賴關係,決定哪些目標文件要從新生成

6、執行生成命令

//////////////////////////////////////////////////////////////////

隱含規則
GNU make 包含有一些內置的或隱含的規則,這些規則定義瞭如何從不一樣的依賴文件創建特定類型的目標。
GNU make 支持兩種類型的隱含規則:
1: 後綴規則(Suffix Rule)。後綴規則是定義隱含規則的老風格方法。後綴規則定義了將一個具備某個
後綴的文件(例如,.c 文件)轉換爲具備另一種後綴的文件(例如,.o 文件)的方法。每一個後綴規
則以兩個成對出現的後綴名定義,例如,將 .c 文件轉換爲 .o 文件的後綴規則可定義爲:

.c.o:
$(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<

2:模式規則(pattern rules)。這種規則更加通用,由於能夠利用模式規則定義更加複雜的依賴性規則。
模式規則看起來很是相似於正則規則,但在目標名稱的前面多了一個 % 號,同時可用來定義目標和依賴
文件之間的關係,例以下面的模式規則定義瞭如何將任意一個 X.c 文件轉換爲 X.o 文件:

%.c:%.o
$(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<

------------------------------------------------------------------------------

運行 make
咱們知道,直接在 make 命令的後面鍵入目標名可創建指定的目標,若是直接運行 make,則創建第一個
目標。咱們還知道能夠用 make -f mymakefile 這樣的命令指定 make 使用特定的 makefile,而不是
默認的 GNUmakefile、makefile 或 Makefile。但 GNU make 命令還有一些其餘項,下面列舉了一些make的命令行參數選項                       

命令行選項              含義

-C DIR              在讀取 makefile 以前改變到指定的目錄 DIR。

-f FILE             以指定的 FILE 文件做爲 makefile。
-h                  顯示全部的 make 選項。
-i                  忽略全部的命令執行錯誤。
-I DIR              當包含其餘 makefile 文件時,可利用該選項指定搜索目錄。
-n                  只打印要執行的命令,但不執行這些命令。
-p                  顯示 make 變量數據庫和隱含規則。
-s                  在執行命令時不顯示命令。
-w                  在處理 makefile 以前和以後,顯示工做目錄。
-W FILE             假定文件 FILE 已經被修改。

------------------------------------------------------------------------------

變量 若是咱們要爲一個目標添加一個依賴 用變量就方便 只要修改變量賦值處就行

如給hello 添加一個依賴 func3.o

咱們能夠兩種方法修改:

1: hello:main.o func1.o func3.o

Gcc main.o func1.o func3.o –o hello

2: 用變量 obj=main.o func1.o func3.o

          Hello:$(obj)  gcc $(obj) –o hello

Makefile 中系統默認的自動化變量

$^ 表明全部的依賴文件

 

$<表明第一個依賴文件

如: hello:main.o func1.o func2.o

     Gcc main.o func1.o func2.o –o hello

è  Hello: main.o func1.o func2.o

è  Gcc  $^ -o $@

Makefile 中 #後面的內容視爲註釋

@取消回顯

!!!!!!!!!!!!!!

特別注意:

在編寫makefile時 寫命令時 前面的空白不是空格鍵 而是一個tab鍵 注意了 ,同時 用於分解多行的反斜線"\"後面不能有空格 這些很容易就犯錯

gcc前必定要 有一個tab分隔符,不能有空格;不然會出現「makefile:2: *** 遺漏分隔符  make中規定每一Shell命令以前的開頭必須使用字符  當時第九行處我是頂格寫的 因此不對 rm....因此在開頭處加了一個TAB製表符 就OK了
////////////////////////////////////////////////////////////////////////////////////
範例

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int hello_init(void)
{
  printk(KERN_ALERT "hello module init\n");
  return 0;
}

static void hello_exit(void)
{
  printk(KERN_ALERT "hello module exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

//////////////////////////////////////
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

clean:
    rm -f *.ko *.mod.c *.mod.o *.o

編譯模塊

#make

清除

#make clean

/////////////////////說明以下/////////////////////////

hello.c文件中調用的頭文件

init.h中的module_init(),module_exit()
kernel.h中的printk(),KERN_ALERT
module.h中的MODULE_LICENSE()

Makefile文件中的核心

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

1)-C $(KERNELDIR)表示在$(KERNELDIR)目錄下執行make命令。 編譯內核模塊時須要依賴內核代碼的2)M=$(PWD) 表示當前目錄表示包含$(PWD)下的Makefile文件。3)modules表示模塊編譯。4)用到了ifneq...else...endif語句因爲開始還沒定義KERNELRELEASE,因此只能執行else分支。而在執行$(MAKE) -C $(KERNELDIR) M=$(PWD) modules後,會在內核的Makefile中定義KERNELRELEASE,當再次進入本Makefile時,則只會執行ifneq的第一個分支,即obj-m := hello.o這一句話是很是重要的。事實上,這個Makefile作的本份工做就是它

相關文章
相關標籤/搜索