多目錄時Makefile 的編寫方法

多目錄時Makefile 的編寫方法

1 make分中預定義變量表

  • $* 不包含擴展名的目標文件名稱。
  • $+ 所有的依賴文件,以空格分開,並以出現的先後爲序,可能包含重複的依賴文件。
  • $< 第一個依賴文件的名稱。
  • $? 所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚。
  • $@ 目標的完整名稱。
  • $^ 所有的依賴文件,以空格分開,不包含重複的依賴文件。
  • $% 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱。例如,如果目標名稱
  • 爲 mytarget.so(image.o),則 @mytarget.so % 爲 image.o。
  • AR 歸檔維護程序的名稱,默認值爲 ar。
  • ARFLAGS 歸檔維護程序的選項。
  • AS 彙編程序的名稱,默認值爲 as。
  • ASFLAGS 彙編程序的選項。
  • CC C 編譯器的名稱,默認值爲 cc。
  • CCFLAGS C 編譯器的選項。
  • CPP C 預編譯器的名稱,默認值爲 $(CC) -E。
  • CPPFLAGS C 預編譯的選項。
  • CXX C++ 編譯器的名稱,默認值爲 g++。
  • CXXFLAGS C++ 編譯器的選項。
  • FC FORTRAN 編譯器的名稱,默認值爲 f77。
  • FFLAGS FORTRAN 編譯器的選項。

2 典型例子

CC := g++  
CFLAGS := -g  
TARGET := test  
SRCS := $(wildcard *.cpp)  
OBJS := $(patsubst %cpp,%o,$(SRCS))  

all:$(TARGET)  
%.o:%.cpp  
    $(CC) $(CFLAGS) -c $< -o $@ 
$(TARGET):$(OBJS)  
    $(CC) $(CFLAGS) -o $@  
clean:  
    rm -rf $(TARGET) *.o  

2.1 常見賦值操作的含義

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

2.2 := 和 = 的區別

“=”

make會將整個makefile展開後,再決定變量的值。也就是說,變量的值將會是整個makefile中最後被指定的值。看例子:

x = foo
y = $(x) bar
x = xyz

在上例中,y的值將會是 xyz bar ,而不是 foo bar 。

“:=”

“:=”表示變量的值決定於它在makefile中的位置,而不是整個makefile展開後的最終值。

x := foo
y := $(x) bar
x := xyz

在上例中,y的值將會是 foo bar ,而不是 xyz bar 了。

3 多個文件時,如何編寫Makefile

例子1:將 bin src obj include 單獨存放時,Makefile文件的通用編寫方法

文件存放說明:

  • bin: 存放編譯生成的二進制文件
  • src: 存放源文件 (add.c multis.c sub.c main.c)
  • obj: 存放編譯生成的目標文件
  • include: 存放頭文件 (add.h multis.h sub.h)
  • Makefile 文件和 bin、src、include處於同一級目錄。

Makefile文件的寫法:

INC_DIR=./include
BIN_DIR=./bin
SRC_DIR=./src
OBJ_DIR=./obj

SRC=${wildcard ${SRC_DIR}/*.c}
OBJ=${patsubst %.c, $(OBJ_DIR)/%.o, ${notdir ${SRC}}}

#用於查看變量的值
#test:
#   echo $(SRC)
#   echo $(OBJ)

TARGET=main
BIN_TARGET=${BIN_DIR}/${TARGET}

CC=gcc
CFLAGS= -g -Wall -I${INC_DIR}

${BIN_TARGET}:${OBJ}
    ${CC} ${OBJ} -o $@

${OBJ_DIR}/%.o:${SRC_DIR}/%.c
    ${CC} ${CFLAGS} -c $< -o $@

clean:
    find ${OBJ_DIR} -name *.o -exec rm -rf {} \;

說明:

  • notdir ${SRC}: 去除.c 文件中的目錄,如:./src/mytest.c, 通過notdir之後得到 mytest.c。
  • $(wildcard .cpp /xxx/xxx/.cpp) 爲獲取當前目錄下和/xxx/xxx/目錄下所有.cpp文件名
  • (patsubst (SRC))爲替換所有的.cpp爲.o
  • find ${OBJ_DIR} -name *.o -exec rm -rf {} \;輸入man find,查看find命令中 -exec的具體用法。

Execute command; true if 0 status is returned. All following arguments to find are taken to be argu‐
ments to the command until an argument consisting of ;' is encountered. The string{}’ is replaced
by the current file name being processed everywhere it occurs in the arguments to the command, not just
in arguments where it is alone, as in some versions of find. Both of these constructions might need to
be escaped (with a `\’) or quoted to protect them from expansion by the shell. See the EXAMPLES sec‐
tion for examples of the use of the -exec option. The specified command is run once for each matched
file. The command is executed in the starting directory. There are unavoidable security problems
surrounding use of the -exec action; you should use the -execdir option instead.

例子2:多個文件存放在不同的目錄時,Makefile的寫法。

文件存放說明:

  • add 目錄 (add.c add.h)
  • sub 目錄 (sub.c sub.h)
  • mutis 目錄 (mutis.c mutis.h)
  • main 目錄(main.c Makefile)

Makefile文件的寫法:

CUR_DIR=add/sub/mutis/main文件所處的目錄

ADD_DIR=${CUR_DIR}/add
SUB_DIR=${CUR_DIR}/sub
MUL_DIR=${CUR_DIR}/multis
MAIN_DIR=${CUR_DIR}/main

INC_DIR= -I${ADD_DIR} \
         -I${SUB_DIR} \
         -I${MUL_DIR} \
         -I${MAIN_DIR}

SRC = ${wildcard  ${ADD_DIR}/*.c} \
      ${wildcard  ${SUB_DIR}/*.c} \
      ${wildcard  ${MUL_DIR}/*.c} \
      ${wildcard  ${MAIN_DIR}/*.c}

OBJ = ${patsubst %.c, %.o, ${SRC}}

TARGET=main
CC=gcc
CCFLAGS=-g -Wall ${INC_DIR}

${TARGET}: ${OBJ}
    ${CC} ${notdir ${OBJ} } -o $@
    echo "Compile done."
${OBJ}:${SRC}
    $(CC) ${CCFLAGS} -c $? 

clean:
    rm -f ${OBJ}
    rm -f *.o
    rm -f *~
    rm -f ${TARGET}
    echo "Clean done."

改進版本:

CUR_DIR=/home/xiaojie/Desktop/demo_multi_makefile/test3

ADD_DIR=${CUR_DIR}/add
SUB_DIR=${CUR_DIR}/sub
MUL_DIR=${CUR_DIR}/multis
MAIN_DIR=${CUR_DIR}/main

INC_DIR= -I${ADD_DIR} \
         -I${SUB_DIR} \
         -I${MUL_DIR} \
         -I${MAIN_DIR}

SRC = ${wildcard  ${ADD_DIR}/*.c} \
      ${wildcard  ${SUB_DIR}/*.c} \
      ${wildcard  ${MUL_DIR}/*.c} \
      ${wildcard  ${MAIN_DIR}/*.c}
OBJ = ${patsubst %.c, %.o, ${SRC}}

TARGET=main
CC=gcc
CCFLAGS=-g -Wall ${INC_DIR}


${TARGET}: ${OBJ}
    ${CC} ${OBJ} -o $@
    @echo "Compile done."

#${OBJ}:${SRC}
#   $(CC) ${CCFLAGS} -c $? 

$(OBJ):%.o:%.c
    @echo "Compiling $< ==> $@"
    ${CC} ${CCFLAGS} -c $< -o $@

clean:
    @rm -f ${OBJ}
    @echo "Clean object files done."

    @rm -f *~
    @echo "Clean tempreator files done."

    @rm -f ${TARGET}
    @echo "Clean target files done."

    @echo "Clean done."

說明:

1.@ echo "" 表示執行該條命令,但不輸出該命令的內容。

2.改進版本中將

${OBJ}:${SRC}
    $(CC) ${CCFLAGS} -c $? 

替換成了,

$(OBJ):%.o:%.c
    @echo "Compiling $< ==$@"
    ${CC} ${CCFLAGS} -c $< -o $@

參考鏈接

發佈了101 篇原創文章 · 獲贊 51 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章