1. 程式人生 > 其它 >Makefile例項分析—Flex程式編譯

Makefile例項分析—Flex程式編譯

技術標籤:程式編譯flex詞法解析器c語言linux

Makefile三要素:
目標、依賴、命令
詳解可見https://blog.csdn.net/lzb19890920/article/details/88432116

Makefile中常用函式和自動化變數:
wildcard-擴充套件萬用字元
例:OBJECTS=$(wildcard *.o)
該找到目標檔案下的所有後綴為.c的檔名並將它們全都賦給OBJECT(即,OBJECT是.o檔案的集合,並且這個函式中的OBJECTS是個任意命名的變數,但是$(wildcard .o)是這個實現找出.o檔案的Makefile函式),要注意的是在wildcard和.o之間是是通過空格隔開的)。

patsubst-替換萬用字元
obj=$(patsubst %, $(LIBPATH)/%/$(LIB_TYPE), $(LINKDIRS))
該函式的功能是在LINKDIRS(第三個引數的集合)中取出各個單元(庫所在目錄名), 將所有包含第一個引數的部分替換成第二個引數的部分。要注意的是在這個函式中patsubst 和%之間是沒有逗號將它們兩個隔開的,它們兩個之間只有空格,%, $(LIBPATH)/%/$(LIB_TYPE), $(LINKDIRS)之間則使用逗號隔開。
foreach-迴圈函式
也可使用類似於Shell的for迴圈語句:

for name in $(FILES); do \ 
 echo "$$name"; \ 
done 

注意, 在makefile中的shell變數要用2個$號表示變數名稱
其他函式可參見https://blog.csdn.net/yangxuan0261/article/details/52060582

Makefile三個自動化變數:
[email protected] 規則中的目標集合,在模式規則中,如果有多個重複目標的話,“[email protected]” 表示匹配模式中定義的目標集合
$% 當目標是函式庫的時候表示規則中的目標成員名,如果目標不是函式庫檔案,那麼其值為空
$< 依賴檔案集合中的第一個檔案,如果依賴檔案是以模式(即“%”)定義的,那麼“$<” 就是符合模式的一系列的檔案集合,多次呼叫則向後順移讀取

$? 所有比目標新的依賴目標集合,以空格分開
$^ 所有依賴檔案的集合,使用空格分開,如果在依賴檔案中有多個檔案“$^” 會去除重複的依賴檔案,值保留一份
$+ 和“$^”類似,但是當依賴檔案存在重複的話不會去除重複的依賴檔案
$* 這個變量表示目標模式中"%"及其之前的部分,如果目標是式為a.%.c,那麼“$*”就是test/a.test

makefile允許命令列傳參,通常用於指定巨集編譯
例項解析可見https://blog.csdn.net/qq849635649/article/details/51576155
makefile可以使用自動化構建工具CMake生成

Makefile中常見預定義變數
AR 庫檔案維護程式的名稱,預設值為ar,建立靜態庫.a
AS 彙編程式的名稱,預設值為as
CC C編譯器的名稱,預設值為cc
CPP C預編譯器的名稱,預設值為$(CC) –E
CXX C++編譯器的名稱,預設值為g++
FC FORTRAN編譯器的名稱,預設值為f77
RM 檔案刪除程式的名稱,預設值為rm –f
ARFLAGS 庫檔案維護程式的選項,無預設值
ASFLAGS 彙編程式的選項,無預設值
CFLAGS C編譯器的選項,無預設值
CPPFLAGS C預編譯的選項,無預設值
CXXFLAGS C++編譯器的選項,無預設值
FFLAGS FORTRAN編譯器的選項,無預設值

GCC編譯選項CFLAGS引數
-c 用於把原始碼檔案編譯成.o物件檔案,不進行連結過程
-o 用於連線生成可執行檔案,在其後可以指定輸出檔案的名稱
-g 用於在生成的目標可執行檔案中,新增除錯資訊,可以使用GDB進行除錯
-Idir 用於把新目錄新增到include路徑上,可以使用相對和絕對路徑,“-I.”、“-I./include”、“-I/opt/include”
-Wall 生成常見的所有告警資訊,且停止編譯,具體是哪些告警資訊,請參見CC手冊,一般用這個足矣!
-w 關閉所有告警資訊
-O 表示編譯優化選項,其後可跟優化等級0\1\2\3,預設是0,不優化
-fPIC 用於生成位置無關的程式碼
-v (在標準錯誤)顯示執行編譯階段的命令,同時顯示編譯器驅動程式,前處理器,編譯器的版本號

GCC連結選項LDFLAGS引數
-llibrary 連結時在標準搜尋目錄中尋找庫檔案,搜尋名為liblibrary.a 或 liblibrary.so
-Ldir 用於把新目錄新增到庫搜尋路徑上,可以使用相對和絕對路徑,“-L.”、“-L./include”、“-L/opt/include”
-Wl,option 把選項 option 傳遞給聯結器,如果 option 中含有逗號,就在逗號處分割成多個選項
-static 使用靜態庫連結生成目標檔案,避免使用共享庫,生成目標檔案會比使用動態連結庫大
另外,LDFLAGS告訴連結器從哪裡尋找庫檔案,LIBS告訴連結器要連結哪些庫檔案。

接下來利用一個簡單地例項進行說明,安裝Flex編譯一個文字識別的小demo。Flex的源程式(定義詞法解析處理規則)需要經過Flex工具形成完成的詞法解析程式,最後和Main程式連結到一起。
編寫testMain.c

#include <stdio.h>

extern int yylex();

extern int chars;
extern int words;
extern int lines;

void main(int argc, char **argv)
{
 yylex();
 printf("line: %d, word: %d, char: %d\n", lines, words, chars);
}

編寫testFlex.l

%{
 int chars = 0;
 int words = 0;
 int lines = 0;
%}
%%
[a-zA-Z]+ { words++; chars += strlen(yytext); }
\n    { chars++; lines++; }
.     { chars++; }
%%

根據編譯過程,編寫一個直觀的Makefile

ECHO = echo    #將編譯器選項定義為變數,提高makefile檔案的可移植性     
CC  = CC
FLEX = flex

target: start testDemo      #make命令預設執行第一個target及其依賴項
 @$(ECHO) compiling is finished!
start:
 @$(ECHO) compiling......
testDemo: testMain.o testFlex.o
 $(CC) -o testDemo testMain.o testFlex.o -lfl -Wall
testMian.o: testMain.c
 $(CC) -c testMian.c
testFlex.o: testFlex.c
 $(CC) -c testFlex.c
testFlex.c: testFlex.l
 $(FLEX) -o testFlex.c testFlex.l
clean:        #make clean執行非第一個target子程式的clean target
 @$(ECHO) cleaning......
 rm testFlex.c ./*.o testDemo

根據編譯過程,編寫一個使用自動化變數的Makefile

ECHO = echo    #將編譯器選項定義為變數,提高makefile檔案的可移植性     
CC  = gcc
FLEX = flex

OBJECTS = testMain.o
OBJECTS += testFlex.o

TARGET = ./testDemo
CFLAGS = -Wall
LIBS  = -lfl

TARGET: $(OBJECTS) #make命令預設執行第一個target及其依賴項
 $(CC) -o $(TARGET) $(OBJECTS) $(LIBS) $(CFLAGS)
 @$(ECHO) compiling is finished!

#.c.o :  一種舊格式寫法
%.o : %.c
 $(CC) -o [email protected] -c $<

#.l.c :
%.c : %.l
 $(FLEX) -o [email protected] $<

clean:        #make clean執行非第一個target子程式的clean target
 @$(ECHO) cleaning......
 rm testFlex.c ./*.o testDemo

.PHONY : clean

在clean目標中需要配合使用偽目標宣告,這個偽目標宣告是指噹噹前路徑下含有以clean命令的檔案或者是目錄的時候,則在使用命令make clean的時候,就會導致結果無法執行。
解決這種問題,只需要在makefile中加入一個偽目標宣告即可,格式為 .PHONY.clean。
具體說明可見http://blog.chinaunix.net/uid-28458801-id-3452277.html
另外,關於Makefile特殊目標的詳細說明可見https://www.xuebuyuan.com/1938993.html