makefile學習


title: 2017-6-15makefile
tags:makefile的書寫和熟悉


示例

# 指令編譯器和選項  
CC=gcc  
CFLAGS=-lssl -lcrypto -ldl -Wall -g -DDEBUG -std=gnu99  
# 宏定義  
DEFS = -DTEST_ADD -DTEST_SUB=1  
CFLAGS += $(DEFS)  
# 頭文件查找路徑
INC = -Iport -I../../modbus/rtu \  
  -I../../modbus/ascii -I../../modbus/include -I../../modbus/tcp  
  
# 靜態鏈接庫  
LDFLAGS =   
LDLIBS = -lpthread
# 目標文件  
      
TARGET=test  
# 源文件  
SRCS = test.c \  
  ./test-add/test-add.c \  
  ./test-sub/test-sub.c  
# 頭文件查找路徑  
INC = -I./test-add -I./test-sub  
# 目標文件  
OBJS = $(SRCS:.c=.o)  
# 鏈接為可執行文件  
$(TARGET):$(OBJS)  
#   @echo TARGET:$@  
#   @echo OBJECTS:$^  
[tab]$(CC) -o $@ $^  
clean:  
[tab]rm -rf $(TARGET) $(OBJS)  
# 連續動作,請清除再編譯鏈接,最后執行  
exec:clean $(TARGET)  
[tab]@echo 開始執行  
[tab]./$(TARGET)  
[tab]@echo 執行結束  
# 編譯規則 $@代表目標文件 $< 代表第一個依賴文件  
%.o:%.c  
[tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $< 
# 指定編譯器  
CC = gcc  
  
# CFLAG包括頭文件目錄  
CFLAGS = -g -Wall  
  
# 頭文件查找路徑  
INC = -Iport -I../../modbus/rtu \  
  -I../../modbus/ascii -I../../modbus/include -I../../modbus/tcp  
  
# 靜態鏈接庫  
LDFLAGS =   
LDLIBS = -lpthread  
# 目標  
TARGET = tcpmodbus  
# 源文件  
SRC = demo.c port/portother.c \  
 port/portevent.c port/porttcp.c \  
 ../../modbus/mb.c ../../modbus/tcp/mbtcp.c \  
 ../../modbus/functions/mbfunccoils.c \  
 ../../modbus/functions/mbfuncdiag.c \  
 ../../modbus/functions/mbfuncholding.c \  
 ../../modbus/functions/mbfuncinput.c \  
 ../../modbus/functions/mbfuncother.c \  
 ../../modbus/functions/mbfuncdisc.c \  
 ../../modbus/functions/mbutils.c  
  
# 源文件編譯為目標文件  
OBJS = $(SRC:.c=.o)  
  
# 鏈接為可執行文件  
$(TARGET): $(OBJS)  
[tab]$(CC) $^ -o $@ $(LDFLAGS) $(LDLIBS)  
  
# 清除可執行文件和目標文件  
clean:  
[tab]rm -f $(OBJS)  
[tab]rm -f $(TARGET)  
  
# 編譯規則 加入頭文件 $@代表目標文件 $< 代表第一個依賴文件  
%.o:%.c  
[tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $<

主要目的

是為了把一些可以變化的參數,編譯到文件里面。
所以要關注#define 的作用域。

不管是typedef還是define,其作用域都不會擴展到別的文件,即使是同一個程序的不同文件,也不能互相使用。

語法概要

          target... : prerequisites ...
          command

【target】 也就是一個目標文件,可以是Object File,也可以是執行文件。還可以是一個標簽(Label)。
【prerequisites】 就是,要生成那個target所需要的文件或是目標。
【command】 也就是make需要執行的命令。(任意的Shell命令)

這個是一個大概的格式,后邊所有的語法和變量都是為了簡化這種寫法。

【:】冒號是表示的依賴關系。依賴關系的實質上就是說明了目標文件是由哪些文件生成的,換言之,目標文件是哪些文件更新的。
make會一層又一層地去找文件的依賴關系,直到最終編譯出第一個目標文件。也就是【target】。

在Makefile中的命令,必須要以[Tab]鍵開始。

Makefile里主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和注釋。
顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
隱晦規則。由于我們的make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支持的。
變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,這個有點你C語言中的宏,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。
文件指示。其包括了三個部分,一個是在一個Makefile中引用另一個Makefile,就像C語言中的include一樣;另一個是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;還有就是定義一個多行的命令。有關這一部分的內容,我會在后續的部分中講述。
注釋。Makefile中只有行注釋,和UNIX的Shell腳本一樣,其注釋是用“#”字符,這個就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進行轉義,如:“#”。

GNU的make工作時的執行步驟入下:(想來其它的make也是類似)

  1.    讀入所有的Makefile。
    
  2.    讀入被include的其它Makefile。
    
  3.    初始化文件中的變量。
    
  4.    推導隱晦規則,并分析所有規則。
    
  5.    為所有的目標文件創建依賴關系鏈。
    
  6.    根據依賴關系,決定哪些目標要重新生成。
    
  7.    執行生成命令。
    

規則包含兩個部分,一個是依賴關系,一個是生成目標的方法。

make一般是使用環境變量SHELL中所定義的系統Shell來執行命令,默認情況下使用UNIX的標準Shell——/bin/sh來執行命令。

變量

在 Makefile中的定義的變量,就像是C/C++語言中的宏一樣,他代表了一個文本字串,在Makefile中執行的時候其會自動原模原樣地展開在所使用的地方。其與C/C++所不同的是,你可以在Makefile中改變其值。在Makefile中,變量可以使用在“目標”,“依賴目標”,“命令”或是 Makefile的其它部分中。

變量在聲明時需要給予初值,而在使用時,需要給在變量名前加上“$”符號,但最好用小括號“()”或是大括號“{}”把變量給包括起來。如果你要使用真實的“$”字符,那么你需要用“$$”來表示。變量可以使用在許多地方,如規則中的“目標”、“依賴”、“命令”以及新的變量中。

$@--目標文件,$^--所有的依賴文件,$<--第一個依賴文件。

= 是最基本的賦值
:= 是覆蓋之前的值
?= 是如果沒有被賦值過就賦予等號后面的值
+= 是添加等號后面的值

模式規則

%.o : %.c ; <command ......>

其含義是,指出了怎么從所有的[.c]文件生成相應的[.o]文件的規則。如果要生成的目標是"a.o b.o",那么"%c"就是"a.c b.c"

BUG記錄

用makefile定義了宏-DKEY="hello world"

但是gcc這樣宏會忽略雙引號。如果當成左值,則會把這句話(just)當成了聲明變量。

并且

宏中有#運算符時,參數不會被展開
為了能讓參數被順利展開所以就不可以使用"#"符號,最終的宏定義如下

#define HELLO hello world  
#define _A(str) _TMP(str)  
#define _TMP(str) #str  
  
std::cout << _A(HELLO) << std::endl;  

1.展開_A,由于沒有"#"符號,HELLO被順利展開,變為 _TMP(hello world)
2._TMP把參數hello world轉換為字符串,也就是加上雙引號,變為 "hello world"

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 來自陳浩的一片老文,但絕對營養。 示例工程:3 個頭文件*.h,和 8 個 C 文件*.c。 初 編譯過程,源文件...
    周筱魯閱讀 4,742評論 0 17
  • makefile關系到整個工程的編譯規則,一個工程中的源文件不計其數,按其類型、功能、模塊分別放在若干的目錄當中,...
    Joe_HUST閱讀 1,898評論 0 3
  • 1. 概述 1.1 前言 之前在Linux下寫C/C++都是直接輸命令行,雖然有使用make的經歷,但沒有自己動手...
    kophy閱讀 3,917評論 0 19
  • Makefile學習筆記 概述 什么是makefile?或許很多Windows程序員都不知道這個東西,因為那些Wi...
    龍曜閱讀 933評論 0 0
  • Makefile學習 參考自《跟我一起寫Makefile》陳皓 Makefile 的語法規則 基本語法 翻譯成中文...
    techping閱讀 750評論 0 1