Linux Makefile通用模板詳解

2023-08-08 10:21:57 來源:CSDN-Acuity.

1、寫在前面

對(duì)于Windows下開發(fā),很多IDE都集成了編譯器,如Visual Studio,提供了“一鍵編譯”,編碼完成后只需一個(gè)操作即可完成編譯、鏈接、生成目標(biāo)文件。


(資料圖片)

Linux開發(fā)與Windows不同,Linux下一般用的的gcc/g++編譯器,如果是開發(fā)ARM下的Linux程序,還需用到arm-linux-gcc/arm-linux-g++交叉編譯器。

Linux下也可以實(shí)現(xiàn)“一鍵編譯”功能,此時(shí)需要一個(gè)編譯腳本“Makefile”,Makefile可以手動(dòng)編寫,也可以借助自動(dòng)化構(gòu)建工具(如scons、CMake)生成。手動(dòng)編寫Makefile是Linux和Windows程序員的區(qū)別之一,一般地一個(gè)通用的Makefile能夠適合大部分Linux項(xiàng)目程序。

2、3個(gè)Makefile模板

2.1 編譯可執(zhí)行文件Makefile

VERSION=1.00CC=gccDEBUG=-DUSE_DEBUGCFLAGS=-WallSOURCES=$(wildcard./source/*.c)INCLUDES=-I./includeLIB_NAMES=-lfun_a-lfun_soLIB_PATH=-L./libOBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=app#links$(TARGET):$(OBJ)@mkdir-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(TARGET)$(VERSION)@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

【要點(diǎn)說明】

【1】程序版本

開發(fā)調(diào)試過程可能產(chǎn)生多個(gè)程序版本,可以在目標(biāo)文件后(前)增加版本號(hào)標(biāo)識(shí)。

VERSION=1.00$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(TARGET)$(VERSION)

【2】編譯器選擇

Linux下為gcc/g++;arm下為arm-linux-gcc;不同CPU廠商提供的定制交叉編譯器名稱可能不同,如Hisilicon“arm-hisiv300-linux-gcc”。

CC=gcc

【3】宏定義

開發(fā)過程,特殊代碼一般增加宏條件來選擇是否編譯,如調(diào)試打印輸出代碼。-D是標(biāo)識(shí),后面接著的是“宏”。

DEBUG=-DUSE_DEBUG

【4】編譯選項(xiàng)

可以指定編譯條件,如顯示警告(-Wall),優(yōu)化等級(jí)(-O)。

CFLAGS=-Wall-O

【5】源文件

指定源文件目的路徑,利用“wildcard”獲取路徑下所有依賴源文件。

SOURCES=$(wildcard./source/*.c)

【6】頭文件

包含依賴的頭文件,包括源碼文件和庫文件的頭文件。

INCLUDES=-I./include

【7】庫文件名稱

指定庫文件名稱,庫文件有固定格式,靜態(tài)庫為libxxx.a;動(dòng)態(tài)庫為libxxx.so,指定庫文件名稱只需寫“xxx”部分,

LIB_NAMES=-lfun_a-lfun_so

【8】庫文件路徑

指定依賴庫文件的存放路徑。注意如果引用的是動(dòng)態(tài)庫,動(dòng)態(tài)庫也許拷貝到“/lib”或者“/usr/lib”目錄下,執(zhí)行應(yīng)用程序時(shí),系統(tǒng)默認(rèn)在該文件下索引動(dòng)態(tài)庫。

LIB_PATH=-L./lib

【9】目標(biāo)文件

調(diào)用“patsubst”將源文件(.c)編譯為目標(biāo)文件(.o)。

OBJ=$(patsubst%.c,%.o,$(SOURCES))

【10】執(zhí)行文件

執(zhí)行文件名稱

TARGET=app

【11】編譯

%.o:%.c$(CC)$(INCLUDES)$(DEBUG)$(CFLAGS)$<-o$@

【12】鏈接

可創(chuàng)建一個(gè)“output”文件夾存放目標(biāo)執(zhí)行文件。鏈接完輸出目標(biāo)執(zhí)行文件,可以刪除編譯產(chǎn)生的臨時(shí)文件(.o)。

$(TARGET):$(OBJ)@mkdir-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(TARGET).$(VERSION)@rm-rf$(OBJ)

【13】清除編譯信息

執(zhí)行“make clean”清除編譯產(chǎn)生的臨時(shí)文件。

.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

2.2 編譯靜態(tài)庫Makefile

VERSION=CC=gccDEBUG=CFLAGS=-WallAR=arARFLAGS=rvSOURCES=$(wildcard*.c)INCLUDES=-I.LIB_NAMES=LIB_PATH=OBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=libfun_a#link$(TARGET):$(OBJ)@mkdir-poutput$(AR)$(ARFLAGS)output/$(TARGET)$(VERSION).a$(OBJ)@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

【要點(diǎn)說明】

基本格式與“編譯可執(zhí)行Makefile”一致,不同點(diǎn)包括以下。

【1】使用到“ar”命令將目標(biāo)文件(.o)鏈接成靜態(tài)庫文件(.a)。靜態(tài)庫文件固定命名格式為:libxxx.a。

2.3 編譯動(dòng)態(tài)庫Makefile

VERSION=CC=gccDEBUG=CFLAGS=-fPIC-sharedLFLAGS=-fPIC-sharedSOURCES=$(wildcard*.c)INCLUDES=-I.LIB_NAMES=LIB_PATH=OBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=libfun_so#link$(TARGET):$(OBJ)@mkdir-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)$(LFLAGS)-ooutput/$(TARGET)$(VERSION).so@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

【要點(diǎn)說明】

基本格式與“編譯可執(zhí)行Makefile”一致,不同點(diǎn)包括以下。

【1】編譯選項(xiàng)和鏈接選項(xiàng)增加“-fPIC -shared ”選項(xiàng)。動(dòng)態(tài)庫文件固定命名格式為libxxx.so。

3、Demo

3.1 編譯應(yīng)用程序

編寫測(cè)試?yán)蹋募娣拍夸浗Y(jié)構(gòu)如下,頭文件存放在“include”目錄,庫文件存放在“l(fā)ib”目錄,源文件存放在“source”目錄,Makefile在當(dāng)前目錄下。

源碼1:

/*頭文件*/#ifndef_FUN0_H_#define_FUN0_H_#endifexternvoidfun0_printf(void);externvoidfun1_printf(void);/*源文件*/#include#include"fun0.h"voidfun0_printf(void){printf("Call"fun0".");}

源碼2:

/*頭文件*/#ifndef_FUN1_H_#define_FUN1_H_#endifexternvoidfun1_printf(void);/*源文件*/#include#include"fun1.h"voidfun1_printf(void){printf("Call"fun1".");}

主函數(shù)源碼:

/*源文件*/#include#include"fun0.h"#include"fun1.h"#include"fun_lib_a.h"#include"fun_lib_so.h"intmain(void){#ifdefUSE_DEBUGprintf("DebugApplicationstartup.");#endiffun0_printf();fun1_printf();fun_lib_a_printf();fun_lib_so_printf();return0;}

庫文件,“./lib”目錄下存放兩個(gè)庫文件,一個(gè)靜態(tài)庫libfun_a.a,一個(gè)動(dòng)態(tài)庫libfun_so.so。

Makefile文件即為“2.1節(jié)”的Makefile模板。

測(cè)試運(yùn)行:

【如果執(zhí)行文件提示無“l(fā)ibfun_so.so”,則需拷貝“l(fā)ibfun_so.so”到根目錄下的“/lib”或者“/usr/lib”目錄下,因?yàn)橄到y(tǒng)執(zhí)行程序,默認(rèn)從該路徑引腳動(dòng)態(tài)庫】

3. 2 生成靜態(tài)庫

編寫測(cè)試?yán)蹋a(chǎn)的庫文件即為“3.1節(jié)”調(diào)用的庫文件(libfun_a.a)。文件存放目錄結(jié)構(gòu)如下:

源文件:

/*頭文件*/#ifndef_FUN_LIB_A_H_#define_FUN_LIB_A_H_#endifexternvoidfun_lib_a_printf(void);/*源文件*/#include#include"fun_lib_a.h"voidfun_lib_a_printf(void){printf("Call"fun_lib_a".");}

Makefile文件即為“2.2節(jié)”的Makefile模板。

編譯生成靜態(tài)庫:

3. 3 生成動(dòng)態(tài)庫

編寫測(cè)試?yán)蹋a(chǎn)的庫文件即為“3.1節(jié)”調(diào)用的庫文件(libfun_so.so)。文件存放目錄結(jié)構(gòu)如下:

源文件:

/*頭文件*/#ifndef_FUN_LIB_SO_H_#define_FUN_LIB_SO_H_#endifexternvoidfun_lib_so_printf(void);/*頭文件*/#include#include"fun_lib_so.h"voidfun_lib_so_printf(void){printf("Call"fun_lib_so".");}

編譯生成動(dòng)態(tài)庫:

審核編輯:湯梓紅

標(biāo)簽:

上一篇:解析C語言斷言函數(shù)的使用
下一篇:最后一頁