• 正文
    • 目標和依賴
    • 變量定義
    • 系統(tǒng)變量
    • 條件表達式的語法
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

飛凌嵌入式ElfBoard ELF 1板卡-Linux內(nèi)核移植之Makefile介紹

01/03 09:00
1039
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

前面我們編譯內(nèi)核時,那么多.c文件最終生成一個zImage鏡像。其實是make工具通過解析Makefile文件進行一系列編譯操作,最終生成我們想要的鏡像文件。Makefile文件中描述了個工程所有文件的編譯順序、編譯規(guī)則以及依賴關(guān)系,決定了工程中文件是否需要編譯,以及這些文件的編譯順序。Make工具還可以通過比較文件最后修改時間,來決定哪些文件需要更新哪些不需要更新,更改了某個文件之后,只對依賴此文件的目標文件進行重新編譯更新,這就大大減少了編譯時間。

開源碼目錄可以看到,Makefile文件不僅存在于源碼根目錄下,在其他的子目錄下也基本都有Makefile文件。在執(zhí)行編譯時,Make工具會解析根目錄下Makefile 文件進行編譯,而根目錄的Makefile會調(diào)用子目錄下的Makefile,子目錄下又有子目錄,層層調(diào)用。

Makefile需要按照一定的格式語法規(guī)則進行書寫。如果你是做Linux應(yīng)用開發(fā)的人員,那么寫Makefile就是必備技能,就需要深諳Makefile語法規(guī)則。對于我們Linux平臺初級開發(fā)人員,很少需要我們?nèi)懸粋€復(fù)雜的Makefile文件,只是在做平臺移植的時候可能需要去簡單修改或者閱讀Makefile文件,所以呢,下面我們就簡單了解一下Makefile基本格式規(guī)則。

目標和依賴

目標就是我們需要生成的文件,依賴就是生成目標文件所需要的其他文件,稱為依賴文件?;菊Z法規(guī)則如下:

targets … :dependent_files …

(tap)command

舉例一

我們先創(chuàng)建一個簡單的app.c文件:

elf@ubuntu:~/work/tmp$ touch?app.c

在文件中輸入如下代碼:

#include <stdio.h>

int main(void)

{

printf("my first app !!! rn");

return 0;

}

按照基本規(guī)則建立一個簡單的Makefile文件,app為我們需要的目標文件,app.c為所要生成的app的依賴文件,gcc –o app app.c就是生成目標app需要執(zhí)行的命令。

建立一個Makefile文件:

elf@ubuntu:~/work/tmp$ touch makefile

文件中輸入如下內(nèi)容:

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

app:app.c

gcc -o app app.c

使用make命令,可以看到執(zhí)行了命令gcc -o app app.c,ls命令查看文件,發(fā)現(xiàn)在該目錄下生成了app目標文件:

elf@ubuntu:~/work/tmp$ make

gcc -o app app.c

elf@ubuntu:~/work/tmp$ ls

app app.c makefile

執(zhí)行app,即可看到app.c中我們寫的打印信息:

elf@ubuntu:~/work/tmp$ ./app

my first app !!!

然后我們再執(zhí)行make命令,會發(fā)現(xiàn)出現(xiàn)如下信息,‘a(chǎn)pp’ is up to date,說明app已經(jīng)是最新的,沒必要再重新生成:

elf@ubuntu:~/work/tmp$ make

make: ‘a(chǎn)pp’ is up to date.

我們做一下稍微的改動,修改app.c文件中的內(nèi)容或者使用touch命令更改一下app.c的時間屬性,然后再進行make看看:

elf@ubuntu:~/work/tmp$ touch app.c

elf@ubuntu:~/work/tmp$ make

gcc -o app app.c

可以看到又重新執(zhí)行了gcc -o app app.c命令,重新生成了app。也就是說,make工具會判斷依賴文件的時間戳是否比目標文件時間戳更新,來決定是否重新生成目標文件。

舉例二

假如我們有多個文件需要編譯,比如我們創(chuàng)建多個文件fun1.c,fun1.h,fun2.c,fun2.h,app.c。

fun1.c:

#include <stdio.h>

#include "fun1.h"

void fun1(char *s)

{

printf("%srn",s);

}

fun1.h:

#ifndef _FUN1_H

#define _FUN1_H

void fun1(char *s);

#endif

fun2.c:

#include "fun2.h"

int fun2(int x,int y)

{

return x+y;

}

fun2.h:

#ifndef _FUN2_H

#define _FUN2_H

int fun2(int x,int y);

#endif

創(chuàng)建app.c文件,該文件引用fun1.c和fun2.c中定義的函數(shù):

#include <stdio.h>

#include "fun1.h"

#include "fun2.h"

int main(void)

{

fun1("I am fun1 !");

printf("fun2 return value=%d n",fun2(1,2));

return 0;

}

最后創(chuàng)建makefile文件,其中app是我們的最終目標文件,app的依賴文件為app.o,fun1.o,fun2.o,這幾個.o文件稱為中間目標文件,它們又有各自所依賴的.c和.h文件,最后的clean也是一個目標文件,但是這個目標沒有任何依賴,也不會生成真正文件,只是執(zhí)行一條命令,我們稱之為偽目標。我們可以看到clean執(zhí)行的是刪除.o和app的命令。

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

app:app.o fun1.o fun2.o

gcc -o app app.o fun1.o fun2.o

app.o:app.c

gcc -c app.c

fun1.o:fun1.c fun1.h

gcc -c fun1.c

fun2.o:fun2.c fun2.h

gcc -c fun2.c

clean:

rm -rf *.o app

創(chuàng)建完成之后,我們直接make:

elf@ubuntu:~/work/tmp$ make

gcc -c app.c

gcc -c fun1.c

gcc -c fun2.c

gcc -o app app.o fun1.o fun2.o

elf@ubuntu:~/work/tmp$ ls

app ?app.c ?app.o ?fun1.c ?fun1.h ?fun1.o ?fun2.c ?fun2.h ?fun2.o ?makefile

上圖可以看到生成最終目標app和一些中間目標文件,這個過程經(jīng)過了以下四個步驟:

gcc -c app.c

gcc -c fun1.c

gcc -c fun2.c

gcc -o app app.o fun1.o fun2.o

執(zhí)行app,可以看到執(zhí)行成功:

elf@ubuntu:~/work/tmp$ ./app

I am fun1 !

fun2 return value=3

現(xiàn)在修改其中一個文件fun2.h后,比如更改一下fun2.h的時間屬性,然后再次編譯:

elf@ubuntu:~/work/tmp$ touch fun2.h

elf@ubuntu:~/work/tmp$ make

gcc -c fun2.c

gcc -o app app.o fun1.o fun2.o

可以看到只用了兩個步驟,app的其他依賴文件并沒有被重新編譯生成。

最后,執(zhí)行make clean清除中間文件和app:

elf@ubuntu:~/work/tmp$ make clean

rm -rf *.o app

elf@ubuntu:~/work/tmp$ ls

app.c ?fun1.c ?fun1.h ?fun2.c ?fun2.h ?makefile

變量定義

變量是在Makefile中定義的名字,用來代替一個文本字符串,該文本字符串稱為該變量的值。變量名是不包括“:”、“#”、“=”結(jié)尾空格的任何字符串。變量名是大小寫敏感的。推薦在Makefile內(nèi)部使用小寫字母作為變量名。

變量賦值方式有以下幾種:

遞歸賦值

變量的名稱 = 變量值

變量的值將會是整個Makefile中最后被指定的值。

舉例,建立一個makefile文件,定義兩個變量a和b,引用變量使用$(),使用@echo進行打?。?/p>

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

a = 123

b = $(a) string

a = 678

target:

@echo "a = $(a)"

@echo "b = $(b)"

可以看到b的值為678 string,而不是123 string

elf@ubuntu:~/work/tmp$ make

a = 678

b = 678 string

簡單賦值

變量的名稱 := 變量值

變量的值決定于它在Makefile中的位置,而不是整個Makefile展開后最終的值。

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

a := 123

b := $(a) string

a := 678

target:

@echo "a = $(a)"

@echo "b = $(b)"

make后可以看到b的值為123 string:

elf@ubuntu:~/work/tmp$ make

a = 678

b = 123 string

條件賦值

變量的名稱 ?= 變量值

如果變量未定義,則使用該變量值定義變量。如果該變量已經(jīng)被定義賦值,則該賦值語句無效,使用原有值。

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

a ?= 123

b ?= $(a) string

a ?= 678

target:

@echo "a = $(a)"

@echo "b = $(b)"

make后,a的值是第一次被賦予的值:

elf@ubuntu:~/work/tmp$ make

a = 123

b = 123 string

追加賦值

變量的名稱 += 變量值

舉例:

注意:復(fù)制粘貼過程中可能會出現(xiàn)格式問題

a := 123

b := $(a) string

a += $(b)

target:

@echo "a = $(a)"

@echo "b = $(b)"

make之后結(jié)果:

elf@ubuntu:~/work/tmp$ make

a = 123 123 string

b = 123 string

系統(tǒng)變量

系統(tǒng)變量或者叫環(huán)境變量,包含了常見編譯器、匯編器的名稱及其編譯選項,我們在編譯之前使用source /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi主要就是設(shè)置這些系統(tǒng)環(huán)境變量的值。

下表列出了Makefile中常見系統(tǒng)變量及其部分默認值:

AR:庫文件維護程序的名稱,默認值為ar;

AS:匯編程序的名稱,默認值為as;

CC:C編譯器的名稱,默認值為cc;

CPP:C預(yù)編譯器的名稱,默認值為$(CC) –E;

CXX:C++編譯器的名稱,默認值為g++;

FC:FORTRAN編譯器的名稱,默認值為f77;

RM:文件刪除程序的名稱,默認值為rm –f;

ARFLAGS:庫文件維護程序的選項,無默認值;

ASFLAGS:匯編程序的選項,無默認值;

CFLAGS:C編譯器的選項,無默認值;

CPPFLAGS:C預(yù)編譯的選項,無默認值;

CXXFLAGS:C++編譯器的選項,無默認值;

FFLAGS:FORTRAN編譯器的選項,無默認值;

條件表達式的語法

(1)比較arg1和arg2值是否相同,如果相同則執(zhí)行text-if-true,否則執(zhí)行text-if-false。

ifeq (<arg1>, <arg2> )

text-if-true

else

text-if-false

endif

比較arg1和arg2值是否相同,如果不同則執(zhí)行text-if-true,否則執(zhí)行text-if-false,與上面的ifeq相反。

ifneq (<arg1>, <arg2> )

text-if-true

else

text-if-false

endif

(2)判斷variable是否為空,如果非空則為真,執(zhí)行text-if-true,否則執(zhí)行text-if-false。

ifdef <variable >

text-if-true

else

text-if-false

endif

判斷variable是否為空,如果為空則為真,執(zhí)行text-if-true,否則執(zhí)行text-if-false。

ifndef <variable >

text-if-true

else

text-if-false

endif

飛凌嵌入式

飛凌嵌入式

保定飛凌嵌入式技術(shù)有限公司,創(chuàng)建于2006年,是一家專注嵌入式核心控制系統(tǒng)研發(fā)、設(shè)計和生產(chǎn)的高新技術(shù)企業(yè),是國內(nèi)較早專業(yè)從事嵌入式技術(shù)的企業(yè)之一。 經(jīng)過十幾年的發(fā)展與積累,公司擁有業(yè)內(nèi)優(yōu)秀的軟硬件研發(fā)團隊,在北京及保定建立兩大研發(fā)基地,在蘇州、深圳設(shè)有華東、華南技術(shù)服務(wù)中心,并在北美、歐洲以及亞太等其他國家和地區(qū)擁有國際業(yè)務(wù)網(wǎng)絡(luò)。公司研發(fā)的智能設(shè)備核心平臺廣泛應(yīng)用于物聯(lián)網(wǎng)、工控、軌道交通、醫(yī)療、電力、商業(yè)電子、智能家居、安防、機器人、環(huán)境監(jiān)測等諸多領(lǐng)域。

保定飛凌嵌入式技術(shù)有限公司,創(chuàng)建于2006年,是一家專注嵌入式核心控制系統(tǒng)研發(fā)、設(shè)計和生產(chǎn)的高新技術(shù)企業(yè),是國內(nèi)較早專業(yè)從事嵌入式技術(shù)的企業(yè)之一。 經(jīng)過十幾年的發(fā)展與積累,公司擁有業(yè)內(nèi)優(yōu)秀的軟硬件研發(fā)團隊,在北京及保定建立兩大研發(fā)基地,在蘇州、深圳設(shè)有華東、華南技術(shù)服務(wù)中心,并在北美、歐洲以及亞太等其他國家和地區(qū)擁有國際業(yè)務(wù)網(wǎng)絡(luò)。公司研發(fā)的智能設(shè)備核心平臺廣泛應(yīng)用于物聯(lián)網(wǎng)、工控、軌道交通、醫(yī)療、電力、商業(yè)電子、智能家居、安防、機器人、環(huán)境監(jiān)測等諸多領(lǐng)域。收起

查看更多

相關(guān)推薦