<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MAKEFILE的學習

      Makefile/cmake/configure

      重點學習Cmake

      首先是簡單的MakeFile入門

      1.1 簡單Makefile

      范例1.1

      all: 
      	@echo "Hello all"
      test:
      	@echo "Hello test"
      

      運行結果如下

      范例1.2

      test:
      	@echo "hello test"
      all:
      	@echo "hello all"
      

      運行結果如下

      范例1.3

      all:test
      	@echo "hello all"
      test:
      	@echoi "hello test"
      

      運行結果如下:

      我們通過上面3個簡單的例子主要就是要解決4個比較重點的地方

      1. 目標、依賴、命令
      2. all有什么意義
      3. all和test的順序
      4. 空格符號的影響

      1.2 Makefile三要素

      1.3 MakeFile工作

      1.4.1 編譯程序

      1.4.2 編譯程序-偽對象.PHONY

      1.5.1 變量

      • CC保存編譯器名
      • RM用于指示刪除文件的命令
      • EXE存放可執行文件名
      • OBJS防止所有的目標文件名

      1.5.2 自動變量

      • \(@**用于表示一個規則中的目標。當我們的一個規則中有多個目標時,\)@所指是其中任何造成命令被運行目標**
      • $^則表示的是規則中的所有先擇條件
      • $<表示的是規則中的第一個先決條件

      1.5.3 自動變量-編譯

      • wildcard是通配符函數,通過它可以得到我們所需的文件形式:$
      • patsubst函數是用來進行字符串替換的,其形式為:$

      1.5.4 依賴第三方庫

      makefile中的函數

      我們通過上面的1.5.3的展示的已經知道了一些函數的作用了,現在我們在介紹幾個函數的使用

      addprefix 函數

      appprefix函數就是用來給字符串中的每一個子串前加上一個前綴,其形式是:$(addprefix prefix, names...)

      .PHONY: all
      without_dir = foo.c bar.c main.o
      with_dir := $( addprefix objs/, $(without_dir))
      all:
      	@echo "你好"
      	@echo $(with_dir)
      

      filter函數

      filter函數用于從一個字符串中,根據模式得到滿足模式的字符串,其形式是:$(filter pattern...,text)

      .PHONY: all
      sources = foo.c bar.c baz.s ugh.h
      sources:=$(filter %.c %.s,$(sources))
      all:
      	@echo $(sources)
      

      filter-out函數

      filter-out 函數用于從一個字符串中根據模式濾除一部分字符串,其形式是:$(filter-out pattern....,text)

      .PHONY: all
      objects= main1.o foo.o main2.o bar.o
      result = $(filter-out main%.o,$(objects))
      all:
      	@echo $(result)
      

      patsubst 函數

      patsubst 函數是用來進行字符串替換的,其形式是:$(patsubst pattern,replacement,text)

      .PHONY: all
      mixed = foo.c bar.c main.o
      objects:=$(patsubst %.c,%.o,$(mixed))
      all:
      	@echo $(objects)
      	
      

      strip函數

      strip函數用于去除變量中的多余的空格,其形式是:$(strip string)

      .PHONY:all
      original = foo.c     bar.c
      stripped := $(strip $(original))
      all:
      	@echo "original=$(original)"
      	@echo "stripped=$(stripped)"
      

      wildcard函數

      wildcard是通配符函數,通過它可以得到我們所需的文件,這個函數如果我們在windows或是linux命令行中"*",其形式為:$(wildcard pattern)

      .PHONY:all
      SRCS = $(wildcard *.c)
      all:
      	@echo $(SRCS)
      

      makefile提高部分

      我們做上面已經接觸并介紹了一些簡單的概念有關于MAKEfile的,下面我們就稍微弄一些比較難得MAKEFILE的例子,來進一步的完成我們的學習。
      我們現在有一些需求:

      • 講所有的目標文件放入源程序所在目錄的objs子目錄中。
      • 將所有最終生成的可執行程序放入源程序所在目錄的exes子目錄中,
      • 將引入用戶頭文件來模擬復雜項目的情形

      創建一個文件夾

      首先我們寫一下如何創建一個文件夾

      .PHONY: all
      MKDIR = mkdir
      DIRS = objs exes
      all:$(DIRS)
      $(DIRS):
      	$(MKDIR) $@
      
      

      但是這樣我們就會遇到這樣的一個問題,我們在第一個make時,由于OBJS和exes目錄都不存在,所以all目標將它們視作一個先決條件或者說是依賴目標,接著makefile中的第二條規則就被派上了用場。構建目錄時,第二條規則中的命令被執行,即真正的創建了objs和exes目錄,當我們第二次進行make時,此時,make仍以objs和exes為目標,但從目錄構建規則中發現,這兩個目標并沒有依賴關系,而且能從當前目錄中找到 objs 和 exes 目錄,即認為 objs 和 exes 目標都是最新的,所以不用再運行目錄構建規則中的命令來創建目錄。
      接下來我們也得為我們的 Makefile 創建一個 clean 目標,專門用來刪除所生成的目標文件和可執行文件。加 clean 規則還是相當的直觀的,如圖 2.8 所示,其中我們又增加了兩個變量,一個是RM,另一個則是 RMFLAGS,這與 simple 項目中所使用的方法是一樣的

      .PHONY: all
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr 
      DIRS = objs exes
      all:$(DIRS)
      $(DIRS):
      	$(MKDIR) $@
      clean:
      	$(RM) $(RMFLAGS) $(DIRS)
      	
      

      增加頭文件

      我們增加進去我們需要編譯的部分。
      foo.h

      #ifndef __FOO_H
      #define __FOO_H
      void foo();
      #endif
      

      foo.c

      #include<stdio.h>
      #include"foo.h"
      void foo()
      {
          printf("This is foo()!\n");
      }
      

      main.c

      #include"foo.h"
      int main()
      {
          foo();
          return 0;
      }
      

      我們再來改造一下我們的Makefile

      .PHONY: all
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr 
      CC = gcc
      EXE = complicated
      DIRS = objs exes
      SRCS = $(wildcard *.c)
      OBJS =$(SRCS:.c=.o)
      all:$(DIRS) $(EXE)
      $(DIRS):
      	$(MKDIR) $@
      $(EXE):$(OBJS)
      	$(CC) -o $@ $^
      %.o:%.c
      	$(CC) -o $@ -c $^
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      
      

      我們運行結束以后,發現所有的目標文件以及可執行文件都放在當前目錄下,而并沒有如我們所希望那樣放在objs和exes目錄中去。

      將文件放入目錄

      為了將目標文件或者可執行程序分別放入所創建的objs和exes目錄中,我們就用我們之前學到過的函數---addprefix,現在我們修改一下我們的makefile文件,以便于目標文件都放入objs目錄當中,更改后的Makefile。

      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIRS = $(DIR_OBJS) $(DIR_EXES)
      EXE = complicated
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      
      all: $(DIRS) $(EXE)
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(OBJS)
      	$(CC) -o $@ $^
      $(DIR_OBJS)/%.o: %.c
      	$(CC) -o $@ -c $^
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      

      我們已經修改了我們的MAKEfile文件,已經得到了我們想要的結果,但是生成的EXES文件還沒有在我們的EXES文件夾中,我們還需要對它進行一些細微的修改,完成我們的目的,修改如下:

      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIRS = $(DIR_OBJS) $(DIR_EXES)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      
      all: $(DIRS) $(EXE)
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(OBJS)
      	$(CC) -o $@ $^
      $(DIR_OBJS)/%.o: %.c
      	$(CC) -o $@ -c $^
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      

      更復雜的依賴關系

      到了這里,好像我們的MAKEFILE已經達到了我們想要需求,但是這是真的嗎?我們看看現在還有什么樣的問題存在著。假設我們已經對項目進行了一次編譯,接著我們再去修改一下foo.h這個頭文件,增加了一個int型的參數,而不對foo.c進行相應的更改。這樣由于函數聲明和函數定義不相同,所以理論上編譯時應該報錯。

      #ifndef __FOO_H
      #define __FOO_H
      void foo(int value);
      #endif
      


      為什么會出現這樣的情況那?那我們先make clean,然后再make會有什么結果那?的確是出錯了!那我們怎么樣才能在沒有進行make clean 之前,make就能發現需要對項目的部分(或者全部)進行重新構建那?如果我們這樣的makefile運用到現實項目中,那對于開發效率還是有影響的,因為每一次make之前都得進行clean,太費時!

      我們來分析以后為什么現在的MakeFile會出現這一問題那?我們現有的Makefile所表達的依賴關系樹及與規則的映射關系圖。

      從依賴圖中,我們可以發現,其中并沒有出現對foo.h的依賴關系,這就是為什么我們改動頭文件時,make無法發現的原因!

      最為直接的改動是我們在構建目標文件的規則中,增加對于foo.h的依賴。改動后的makefile如下:

      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIRS = $(DIR_OBJS) $(DIR_EXES)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      
      all: $(DIRS) $(EXE)
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(OBJS)
      	$(CC) -o $@ $^
      $(DIR_OBJS)/%.o: %.c foo.h
      	$(CC) -o $@ -c $<
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      

      改動的部分并不是很多,需要指出的是,在這個makefile中我們使用了自動變量$<,在這個變量與$^的區別是,其只則表示所有的先決條件中的第一個,而$^則表示全部先決條件。我們要用$<是因為,我們不希望將foo.h也作為一個文件讓GCC去編譯,這樣的話會報錯。

      這個方法暫時解決了我們遇到的問題,我們需要想一想這種解決方法的可操作性。當項目復雜時,如果我們要將每一個頭文件都寫入到makefile相對應的規則中,這將會是一個噩夢!看來我們還的找到另一種更好的方法。

      有什么工具能幫助我們列出一個源程序所包含的頭文件那就好了,這樣的話,我們或許可以在make時,動態的生成文件的依賴關系。還真是有這么樣一個工具!就是我們的編譯器--gcc。我們可以采用-M選項和-MM選項列出foo.c對其他文件的依賴關系的結果,從結果你可以看出它們會列出foo.c中直接或是間接包含的頭文件。-MM 選項與-M 選項的區別是,-MM選項并不列出對于系統頭文件的依賴關系,比如 stdio.h 就屬于系統頭文件。其道理是,絕大多數情況我們并不會改變系統的頭文件,而只會對自己項目的頭文件進行更改。
      執行

      對于采用gcc的-MM的選項所生成的結果,我們從圖中就知道,我們會遇到的問題了,我們生成的目標文件是放在objs目錄當中的,因此,我們希望依賴關系中也包含這一目錄信息,否則,在我們的makefile中,根本沒有辦法做到生成的目標放到objs目錄中,這在前面的makefile中我們是在生成的文件前加前綴的方法。在使用新的方法是,我們仍然需要實現同樣的功能。這時,我們采用的就是sed工具了,這是linux中非常常用的一個字符串處理工具。示例如下:

      gcc -MM foo.c | sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g'
      

      Gcc還有一個非常有用的選項是-E,這個命令告訴Gcc只做預處理,而不進行程序編譯,在生成依賴關系是,其實我們并不需要GCC去編譯,只要進行預處理就行了。這可以避免在生成依賴關系時出現沒有必要的warning,以及提高依賴關系的生成效率。
      接下來,我們要如何整合到我們的makefile中那?顯然,自動生成的依賴信息,不可能直接出現在我們的makefile中,因為我們不能動態的改變makefile的內容,那采用什么方法那?

      • 我們為每一個源文件通過采用GCC和sed生成一個依賴關系文件,這些文件我們采用.dep后綴結尾。
      • 從模塊化的角度來說,我們不希望.dep文件與.哦文件或者時可執行文件混放在一個目錄中。為此,創建一個新的deps目錄用于存放依賴文件更為合理。
        MakeFile
      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIR_DEPS = deps
      DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      DEPS = $(SRCS:.c=.dep)
      DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
      
      
      all: $(DIRS)  $(DEPS) $(EXE)
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(OBJS)
      	$(CC) -o $@ $^
      $(DIR_OBJS)/%.o: %.c 
      	$(CC) -o $@ -c $^
      $(DIR_DEPS)/%.dep: %.c
      	@echo "Making $@..."
      	@set -e; \
      	$(RM) $(RMFLAGS) $@.tmp;\
      	$(CC) -E -MM $^ > $@.tmp;\
      	sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g' < $@.tmp > $@ ;\
      	$(RM) $(RMFLAGS) $@.tmp
      
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      

      這里我們又有一個知識點需要注意,對于規則中的每一個命令,make都是在一個新的shell上運行它的,如果希望多個命令在同一個Shell中運行,則需要用';'將這些命令連起來。當命令很長時,為了方便閱讀,我們需要將一行命令分為多行,這需要用''。為了理解,我們可以做一個實驗,現在假設我們需要創建一個test目錄,然后,在這個test目錄再創建一個subtest目錄,你可能會寫出下面這樣的Makefile.

      .PHONY:all
      all:
      	@makedir test
      	@cd test
      	@makedir subtest
      

      我們會得到這樣的目錄結構:

      下面我們再來修改一下我們的makefile:

      .PHONY: all
      all:
      	@mkdir test ; \
      	cd test ; \
      	mkdir subtest
      

      這樣就實現了我們的要求.

      包含文件

      我們現在已經產生了我們需要的依賴(dep)文件,那如何為我們的makefile所用呢?這需要用到Makefile中的include關鍵字,它如同C/C++的#include預處理指令。現在要做的就是在Makefile中加入對所有依賴文件的包含功能,
      Makefile

      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIR_DEPS = deps
      DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      DEPS = $(SRCS:.c=.dep)
      DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
      
      
      all: $(DIRS)  $(DEPS) $(EXE)
      
      include $(DEPS)
      
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(OBJS)
      	$(CC) -o $@ $^
      $(DIR_OBJS)/%.o: %.c 
      	$(CC) -o $@ -c $^
      $(DIR_DEPS)/%.dep: %.c
      	@echo "Making $@..."
      	@set -e; \
      	$(RM) $(RMFLAGS) $@.tmp;\
      	$(CC) -E -MM $^ > $@.tmp;\
      	sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g' < $@.tmp > $@ ;\
      	$(RM) $(RMFLAGS) $@.tmp
      
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
      

      我們現在運行一下看看結果怎么樣

      發現了報錯了,找不到main.dep這個文件,我們怎么理解這個錯誤呢?我們的make對于INCLUde的處理是先于all目標構建的,這樣的話,由于依賴文件時在構建all目標時才創建的,所以在include的時候,是找不到依賴文件的。我們說第一次make的時候的確是沒有依賴文件,所以include出錯也是正常的,那么能不能讓make忽略這一錯誤呢?可以的,在Makefile中,如果在include前加上一個'-'號,當make處理這一包含指示時,如果文件不存在就會忽略這一錯誤。除此之外,需要對于Makefile中include有更加深入的理解。當make看到include指令時,會先找一下有沒有這個文件,如果有則讀入。接著,make還會看一看對于包含進來的文件,在Makefile中是否存在規則來更新它。如果存在,則運行規則去更新需被包含進來的文件,當更新完了以后再將其包含進來。在我們的MAKEfile中,的確存在用于創建(或更新)依賴的文件的規則,為什么make沒有幫助我們去創建依賴文件那?因為make想創建依賴文件時,deps目錄還沒有創建,所以無法成功的構建依賴文件。
      有了這些信息以后,我們需要對Makefile的依賴關系進行調整,即將deps目錄的創建放在構建依賴文件之前。其改動就是在依賴文件的創建規則當中增加對deps目錄的信賴,且將其當作是第一個先決條件。采用同樣的方法,我們將所有的目錄創建都放到相應的規則中去

      
      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIR_DEPS = deps
      DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      DEPS = $(SRCS:.c=.dep)
      DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
      
      
      all: $(EXE)
      
      -include $(DEPS)
      
      $(DIRS):
      	$(MKDIR) $@
      $(EXE): $(DIR_EXES) $(OBJS)
      	$(CC) -o $@ $(filter %.o,$^)
      $(DIR_OBJS)/%.o: $(DIR_OBJS) %.c 
      	$(CC) -o $@ -c $(filter %.c,$^)
      $(DIR_DEPS)/%.dep:$(DIR_DEPS) %.c
      	@echo "Making $@..."
      	@set -e; \
      	$(RM) $(RMFLAGS) $@.tmp;\
      	$(CC) -E -MM $(filter %.c,$^) > $@.tmp;\
      	sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g' < $@.tmp > $@ ;\
      	$(RM) $(RMFLAGS) $@.tmp
      clean:
      	$(RM) $(RMFLAGS) $(DIRS) 
      

      再復雜一點的依賴關系

      現在,我們再對源程序文件進行一定的修改,如圖 2.36 所示。其中的改動包括:

      • 增加 define.h 文件并在其中定義一個 HELLO 宏。
      • 在 foo.h 中包含 define.h 文件。
      • 在 foo.c 中增加對 HELLO 宏的使用。
        增加了這些改動以后,進行 make 操作

      define.h

      #ifndef __DEFINE_H
      #define __DEFINE_H
      #define HELLO “Hello”
      #endif
      

      foo.h

      #ifndef __FOO_H
      #define __FOO_H
      #include “define.h”
      void foo ();
      #endif
      

      foo.c

      #include <stdio.h>
      #include “foo.h”
      void foo ()
      {
      printf (“%s, this is foo ()!\n”, HELLO);
      }
      

      main.c

      #include “foo.h”
      int main ()
      {
      foo ();
      return 0;
      }
      

      然后我們編譯成功了以后,我們在進行一個操作

      現在對 other.h 進行更改
      other.h

      #ifndef __OTHER_H
      #define __OTHER_H
      #define HELLO "Hi"
      #endif
      

      我們再進行make編譯,發現并沒有什么變化。
      問題出來了,程序并沒有因為我們更改了 other.h 而重新編譯,問題出在哪呢?從 foo.dep 和main.dep 的內容來看,其中并沒有指出 foo.o 和 main.o 依賴于 other.h 文件,所以當我們進行 make時,make 程序沒有發現 foo.o 和 main.o 需要重新編譯。那如何解決呢?我們說,當我們進行 make時,如果此時 make 能發現 foo.dep 和 main.dep 需要重新生成的話,此時會發現 foo.o 和 main.o都依賴 other.h 文件,那自然就會發現 foo.o 和 main.o 也需要重新編譯。
      也就是說我們也需要對依賴文件采用 foo.o 和 main.o 相類似的依賴規則,為此,我們希望在Makefile 中存在如圖 2.42 所示的依賴關系。如果存在這樣的依賴關系,當我們對 define.h 進行更改以增加對 other.h 文件的包含時,通過這個依賴關系 make 就能發現需要重新生成新的依賴文件,一旦重新生成依賴文件,other.h 也就自然會成為 foo.o 和 main.o 的一個先決條件。如果這樣的話,就不會出現前面所看到的依賴關系并不重新構建的問題了。
      makefile

      .PHONY: all clean
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIR_DEPS = deps
      DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      DEPS = $(SRCS:.c=.dep)
      DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
      
      
      all: $(EXE)
      
      
      -include $(DEPS)
      
      $(DIRS):
      	$(MKDIR) $@
      
      $(EXE): $(DIR_EXES) $(OBJS)
      	$(CC) -o $@ $(filter %.o, $^)
      
      $(DIR_OBJS)/%.o: $(DIR_OBJS) %.c
      	$(CC) -o $@ -c $(filter %.c, $^)
      
      $(DIR_DEPS)/%.dep: $(DIR_DEPS) %.c
      	@echo "Making $@ ..."
      	@set -e; \
      	$(RM) $(RMFLAGS) $@.tmp ; \
      	$(CC) -E -MM $(filter %.c, $^) > $@.tmp ; \
      	sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@ ; \
      	$(RM) $(RMFLAGS) $@.tmp
      clean:
      	$(RM) $(RMFLAGS) $(DIRS)
      

      這個 Makefile 中你可以看出,我們只需在相應的規則命令中增加一個$@就行了,因為這個表示的是目標,即在創建 deps/foo.dep 時,其代表的就是 deps/foo.dep。

      條件編譯

      當 make 看到條件語法時將立即對其進行分析,這包括 ifdef、ifeq、ifndef 和 ifneq 四種語句形式。這也說明自動變量在這些語句塊中不能使用,因為自動變量的值是在命令處理階段才被賦值的。如果非得用條件語法,那得使用 Shell 所提供的條件語法而不是 Makefile 的。
      Makefile 中的條件語法有三種形式。其中的 conditional-directive 可以是 ifdef、ifeq、ifndef 和 ifneq 中的任意一個。
      conditional-directive
      text-if-true
      endif

      conditional-directive
      text-if-true
      else
      text-if-false
      endif

      conditional-directive
      text-if-one-is-true
      else conditional-directive
      text-if-true
      else
      text-if-false
      endif

      makefile

      .PHONY: all
      
      sharp = square
      desk = square
      table = circle
      
      ifeq ($(sharp), $(desk))
      result1 = "desk == sharp"
      endif
      
      ifneq "$(table)" 'square'
      result2 = "table != square"
      endif
      
      all:
      @echo $(result1)
      @echo $(result2)
      

      makefile

      .PHONY: all
      foo = defined
      
      ifdef foo
      result1 = "foo is defined"
      endif
      
      ifndef bar
      result2 = "bar is not defined"
      endif
      
      all:
      @echo $(result1)
      @echo $(result2)
      

      當進行第二次 make clean 時,make 還會先構建依賴文件,接著再刪除,這是因為我們進行 make clean 也需要包含依賴文件的緣故。顯然,其中構建依賴文件的動作有點多余,因為后面馬上又被刪除了。為了去除在 make clean 時不必要的依賴文件構建,我們可以用條件語法來解決這一問題。

      .PHONY: all clean
      
      MKDIR = mkdir
      RM = rm
      RMFLAGS = -fr
      
      CC = gcc
      
      DIR_OBJS = objs
      DIR_EXES = exes
      DIR_DEPS = deps
      DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
      
      EXE = complicated
      EXE := $(addprefix $(DIR_EXES)/, $(EXE))
      
      SRCS = $(wildcard *.c)
      OBJS = $(SRCS:.c=.o)
      OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
      DEPS = $(SRCS:.c=.dep)
      DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
      
      all: $(EXE)
      
      ifneq ($(MAKECMDGOALS), clean)
      -include $(DEPS)
      endif
      
      $(DIRS):
      $(MKDIR) $@
      $(EXE): $(DIR_EXES) $(OBJS)
      $(CC) -o $@ $(filter %.o, $^)
      $(DIR_OBJS)/%.o: $(DIR_OBJS) %.c
      $(CC) -o $@ -c $(filter %.c, $^)
      $(DIR_DEPS)/%.dep: $(DIR_DEPS) %.c
      @echo "Making $@ ..."
      @set -e; \
      $(RM) $(RMFLAGS) $@.tmp ; \
      $(CC) -E -MM $(filter %.c, $^) > $@.tmp ; \
      sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@ ; \
      $(RM) $(RMFLAGS) $@.tmp
      clean:
      $(RM) $(RMFLAGS) $(DIRS)
      

      推薦一個零聲學院免費教程,個人覺得老師講得不錯,
      分享給大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
      fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,
      TCP/IP,協程,DPDK等技術內容,點擊立即學習:
      服務器
      音視頻
      dpdk
      Linux內核

      posted @ 2022-09-16 20:15  飄雨的河  閱讀(77)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 精品久久久无码中文字幕| 你懂的在线视频一区二区| 亚洲综合国产伊人五月婷| 国产激情视频在线观看首页| 国产福利社区一区二区| 成人国产av精品免费网| 自拍日韩亚洲一区在线| 国产精品一区二区中文| 黑人av无码一区| 精品国产av最大网站| 南郑县| 四虎永久免费很黄的视频| 高清无码在线视频| 免费观看欧美猛交视频黑人| 国产成人亚洲精品成人区| 久久av色欲av久久蜜桃网| 精品精品亚洲高清a毛片| 国产综合久久99久久| 无码人妻一区二区三区四区AV| 忘忧草在线社区www中国中文| 亚洲日本国产精品一区| 亚洲欧美日韩尤物AⅤ一区| 国产影片AV级毛片特别刺激| 激情亚洲内射一区二区三区| 亚洲人成电影网站色| 日日麻批免费40分钟无码| 一卡2卡三卡4卡免费网站| 丰镇市| 天天做天天爱夜夜夜爽毛片| 久久AV中文综合一区二区| 亚洲国产综合精品2020| 少妇午夜福利一区二区三区| 国产精品人成视频免费播放| 无码一区二区三区AV免费| 国产精品大全中文字幕| 国产乱人伦真实精品视频| 99中文字幕精品国产| 大屁股国产白浆一二区| 国产综合视频精品一区二区| 国产亚洲精久久久久久无码77777| 在线精品国产中文字幕|