GCC 的專案建置器 -- Make

高等 C 語言

簡介

字串

指標與陣列

函數

結構

物件導向

記憶體

檔案

錯誤處理

巨集處理

C 與組合語言

資料結構

動態字串

動態陣列

鏈結串列

雜湊表

開發環境

Make

Cygwin

MinGW

DevC++

wxDevC++

編譯器

gcc 編譯器

TinyCC 編譯器

LCC 編譯器

應用主題

CGI 程式

GNU 程式

視窗程式

影像處理

練習題

訊息

相關網站

參考文獻

最新修改

簡體版

English

程式碼列表

假定有三個檔案,分別如下所示:

// file:StackMain.c
#include <stdio.h>
#include "Stack.h"

int main() {
int x;
push(3);
x= pop();
printf("x=%d\n", x);
return 0;
}

// file: StackFunc.h
#include "Stack.h"

void push(int x) {
stack[top++] = x;
}

int pop() {
return stack[—top];
}

// file: Stack.h
extern int stack[];
extern int top;

void push(int x);
int pop();

// file: StackType.c

int stack[128];
int top = 0;

那麼,我們可以使用以下指令對這些檔案進行編譯、建函式庫、連結等動作,如下所示:

gcc -c StackType.c -o StackType.o -I . -L .
gcc -c StackFunc.c -o StackFunc.o -I . -L .
ar -r libstack.a StackType.o StackFunc.o
ar: creating libstack.a
gcc StackMain.c -lstack -o stack -I . -L .

您也可以將這樣的程序寫為 Shell 等批次檔,然後執行整個專案的建置動作。

但是這樣就必須不斷的重複撰寫 gcc -c … -o -I . -L . 的指令,有多少 C 語言檔就必須有多少行這種指令,並不方便。

簡易建置檔 (Make0)

因此 GNU 發展出了 make 建置檔,這種建置檔後來也被用在其他的編譯工具上,成為撰寫 C 語言的重要工具。

建置檔的語法如下,其中上方的 target:target1 target2 … 代表 target (目標文件) 依賴於 target1 target2 … 等元素,這條描述了依賴關係。底下的 rule 之前必須有的 TAB 鍵,代表當 target 被觸發後,必須執行的動作。

target :target1 target2, ...
    rule

因此對於上述專案而言,以下是建置檔 (Makefile) 可以用來建置整個專案。

all: stack

clean: 
    rm *.o *.exe *.a

stack: ar
    gcc StackMain.c -lstack -o stack -I . -L .

ar : StackType.o StackFunc.o
    ar -r libstack.a StackType.o StackFunc.o

StackFunc.o : StackFunc.c
    gcc -c StackFunc.c -o StackFunc.o -I . -L .

StackType.o : StackType.c
    gcc -c StackType.c -o StackType.o -I . -L .

變數設定 (Make1)

CC = gcc # 定義 CC 變數為 "gcc"
AR = ar
OBJS = StackType.o StackFunc.o
BIN = stack
RM = rm -f
INCS = -I .
LIBS = -L .
CFLAGS = $(INCS) $(LIBS)

all: $(BIN)

clean: 
    ${RM} *.o *.exe *.a

$(BIN): $(AR)
    $(CC) StackMain.c -lstack -o $(BIN) $(CFLAGS)

$(AR) : $(OBJS)
    $(AR) -r libstack.a $(OBJS)

StackFunc.o : StackFunc.c
    $(CC) -c StackFunc.c -o StackFunc.o $(CFLAGS)

StackType.o : StackType.c
    $(CC) -c StackType.c -o StackType.o $(CFLAGS)

執行結果

D:\cp\Make1>make
gcc -c StackType.c -o StackType.o -I . -L .
gcc -c StackFunc.c -o StackFunc.o -I . -L .
ar -r libstack.a StackType.o StackFunc.o
ar: creating libstack.a
gcc StackMain.c -lstack -o stack -I . -L .

D:\cp\Make1>stack
x=3

樣式比對

%.o:  %.c 
    $(CC) -c -o $*.o $< $(CFLAGS)

其中的 %.o 與 %.c 中的 % 稱為樣式,我們可以用 $* 取出這個樣式。

自動變數 (Make2)

Makefile有三個非常有用的變數。分別是$@,$^,$<代表的意義分別是:

$@ : 目的檔案,$^ : 所有的依賴項目,$< : 第一個依賴項目。

符號 代表意義 範例
$@ 目標項目
$* 樣式或副檔名規則中對應到的字串 (即 % 所對應到的)
$< 第一個依賴項目
$? 同一個規則的所有先決條件名
$^ 所有的依賴項目,但是有的make像solaris make可能不認得這個自動變數。
CC = gcc
AR = ar
OBJS = StackType.o StackFunc.o
BIN = stack
INCS = -I .
LIBS = -L .
CFLAGS = $(INCS) $(LIBS)

all: $(BIN)

clean: 
    ${RM} *.o *.exe *.a

$(BIN): $(AR)
    $(CC) StackMain.c -lstack -o $(BIN) $(CFLAGS)

$(AR) : $(OBJS)
    $(AR) -r libstack.a $(OBJS)

%.o:  %.c 
# 這條也可以簡寫為 .c.o
    $(CC) -c -o $*.o $< $(CFLAGS) 
    # 其中的 $< 代表第一個依賴文件 %.c

內隱規則 (Make3)

由於上述寫法對每一個 C 語言程式都要寫一條規則,實在太麻煩了,因此就有一種稱為內隱規則的寫法,預設套用在每一種程式語言上,舉例而言,對 C 語言程式預設套用的規則為 $(CC) -c # $(CPPFLAGS) $(CFLAS) xxx.c。

而且系統通常會預設了一些變數,例如:

AR = ar
CC = cc
MAKE = make
CXX = g++

因此我們可以將上述 Makefile 簡化如下:

CC = gcc
OBJS = StackType.o StackFunc.o
BIN = stack
INCS = -I .
LIBS = -L .
CFLAGS = $(INCS) $(LIBS)

all: $(BIN)

clean: 
    ${RM} *.o *.exe *.a

$(BIN): $(AR)
    $(CC) StackMain.c -lstack -o $(BIN) $(CFLAGS)

$(AR) : $(OBJS)
    $(AR) -r libstack.a $(OBJS)

附檔名規則

還有更古老的一種叫suffix rule的方法來做,這種方法就有限制性 了,因為只能用在副檔名的規則。例如

.c.o:
    $(CC) -c -o $*.o $<
.S.o:
    $(CC) -c -o $*.o $<

prequeite 比對條件中的項目

target : prequeite

$@ Target的檔名

$% 程式庫成員中的檔名元素

$< 第一個prequeite的檔名

$? Timestamp 在Target之後的Prequeite

$^ 所有的Prequeite的檔名 但不包含重複部分

$+ 所有的Prequeite的檔名

$* Target的主檔名

$(@D) $(<D) 指的是Target的檔案路徑

$(@F) $(<F) 指的是Target的檔案名稱

參考文獻

  1. Linux下C语言编程基础(Makefile) 2005-01-18 10:28:23 来自:赛迪网
  2. Makefile的一些用法 — http://deanjai.blogspot.tw/2008/02/objs-foo.html

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License