MakefileMakefileshell命令為何總是藕斷絲連?

      網友投稿 960 2025-03-31

      1 寫在前面


      博主最近在項目實踐過程中,需要深度定制項目的Makefile,其中有些復雜的流程必須得借助shell腳本才能高效地完成,為此博主特意深入學習了在Makefile種調用shell命令的方法。

      大家都知道shell命令是Linux的神器,學會靈活應用它可以大大提升執行的自動化效率。

      Makefile也是GNU的另一大神器,大家要知道,大名鼎鼎的Linux內核的編譯就是靠Makefile來支撐的,連這么龐大、復雜的系統編譯它都可以輕松駕馭,可想而知,它也是牛逼哄哄的存在。

      我們試想一下,如果把Makefile和shell命令這兩大神器聯合在一起,會有怎樣的效果,我們一起來看下。

      2 什么是Makefile?

      這個問題,我在之前的博文中就有介紹過,感興趣的可以點過去看一看:【Linux + Makefile】十分鐘教你學會Makefile的FORCE。

      下面我再總結下,到底什么是Makefile?

      Makefile的基本形式如下所示:

      TARGET : DEPENDENCES

      【Makefile】Makefile與shell命令為何總是藕斷絲連?

      CMD

      # TARGET:生成的目標,可以是一個文件,也可以是一個虛擬符號(非真實文件)

      # DEPENDENCES: 生成目標的所有依賴,它是一個集合,可以只有一個文件,或者很多文件;也可以是虛擬符號

      # CMD:把所有依賴生成目標的執行命令,其中CMD前面是一個TAB鍵,而不能是空格

      Makefile的基本規則,歸納起來就是一句話:【當一個TARGET (欲生成的目標)比它的任何一個DEPENDENCES(依賴的文件)舊時,這個TARGET就要重新生成】。

      這段話讀起來很簡單,就是Makefile在執行編譯的時候,會先去判斷TARGET和其依賴文件的時間差,如果TARGET的時間比較舊,意味著依賴文件已經更新了,那么TARGET就要重新生成;反之,如果TARGET的時間比較新,意味著在TARGET生成后,依賴文件是沒有改變過的,自然就不用重新去生成TARGET。

      說白了,就是搞清楚【TARGET 和 DEPENDENCES 的時間關系】,弄明白了這個,你就可以讀懂Makefile了。

      3 如何調試Makefile?

      以下Makefile給大家演示下如何在Makefile中寫注釋以及如何調試Makefile的變量。

      # This is an annotation for this Makefile. # Call shell cmd in these ways ... CUR_PATH = `pwd` LS_FILES = "`ls`" LS_TEST_FILES = "$(shell ls test*)" DEBUG_VARIABLE = "debug" # Debug your Makefile variables ... $(info "This is a info msg ...") $(warning "This is a warning msg ... DEBUG_VARIABLE=$(DEBUG_VARIABLE)") $(error "This is a error msg ... It will make this Makefile to exist beacuse of an 'error' accur.") # Begin you targets and dependences info: @echo "CUR_PATH = $(CUR_PATH)" @echo "LS_FILES = $(LS_FILES)" @echo "LS_TEST_FILES = $(LS_TEST_FILES)"

      我們執行下make info可以看下,輸出信息:

      分別對應info,warning,error;這三個函數是Makefile中內置的,在任意Makefile中都可以使用。但是需要注意的,這三個函數可以在Makefile的任意位置調用,但是必須符合語法規則,比如在CMD部分(見第一章節的引用內容)調用時,必須時TAB開頭。

      我們試下這個的效果:

      4 Makefile定義變量的時候調用shell命令

      還是拿上面的Makefile來分析,我們一開始定義了幾個變量:

      CUR_PATH = `pwd` LS_FILES = "`ls`" LS_TEST_FILES = "$(shell ls test*)"

      其中CUR_PATH是保存當前Makefile的路徑,我們都知道shell命令有個pwd可以獲取到當前目錄的路徑,所以 CUR_PATH 變量正是利用了這個命令來取得當前路徑。其中,值得注意的是 表示的是獲取pwd命令的返回值,這個 ,不是分號 ’ ',而是鍵盤左上角數字1左邊的那個鍵值,新手一般非常容易搞錯這一點。

      第二個變量LS_FILES的定義,使用同樣的方式調用了 ls 命令,但是它在返回值的左右,加了 “ ”;這樣做的主要目的是,ls的返回值通常是一個字符串,中間每個文件名用空格隔開的;如果我們想把這一系列的字符串連起來而不是分散的,我們就必須使用 " "把它們包起來,這樣Makefile變量就會把它當作一個字符串整體來處理。

      第三個變量LS_TEST_FILES,它就換了一種方式來調用shell命令,它的格式是 $(shell xxx),其中xxx就是一個可以在shell環境下執行的shell命令,比如本例子中,xxx就是 ls test*。

      兩者方法沒有本質的區別,結合自己的實際情況來使用即可,從易讀性來說,推薦使用$(shell xxx)的調用方式。

      5 Makefile在執行命令的時候調用shell命令

      以下面的Makefile為例子:

      # This is an annotation for this Makefile. shell_cmd: @ls test* @pwd @echo "shell_cmd test ..."

      執行make shell_cmd,我們可以看到輸出:

      只要是shell執行的命令,都可以運行,這就方便我們做一些自動化操作,比如創建目錄、刪除文件、下載文件、上傳文件等等。

      6 Makefile以函數的形式調用shell命令

      請看下面的Makefile內容

      # This is an annotation for this Makefile. DEBUG_VARIABLE = "debug" # This is a shell function. define function_test_shell param1=$1;\ local_variable=12345678;\ debug_variable=$(DEBUG_VARIABLE);\ echo "param1=$$param1";\ echo "local_variable=$$local_variable";\ echo "debug_variable=$$debug_variable";\ i=0;\ cnt=10;\ for i in `seq $$cnt`; do\ echo "i=$$i";\ done;\ ls -al;\ ls -al test* endef # Begin you targets and dependences shell_function: @$(call function_test_shell,$(DEBUG_VARIABLE))

      我們執行make shell_function可以看到輸出:

      !

      對應就是shell函數里面的操作。

      在Makefile調用shell函數的寫法上,有幾點特別需要注意:

      1)Makefile定義函數是使用define 和 endef,務必配對使用;函數里面的實現可以調用shell命令,也可以調用Makefile內置的函數,也可以調用自定義的Makefile函數;

      2)Makefile函數的調用方式是$(call function,xx,yy,zz),其中function是函數名,也就是define后面的名字,xx/yy/zz分別是函數的三個入參;當然有幾個參數就填幾個,每一個使用 , 隔開;

      3) 在函數里面使用$1 $2

      3

      獲取輸入的參數,即

      3獲取輸入的參數,即

      3獲取輸入的參數,即+數字的方式獲取入參;

      4)如果函數里面使用的是shell組合命令,請務必在每一條shell命令后面加上 ; 符號,并且每一行加上 \ 連起來;這樣對于shell解析器而言,它會認為是一條長長的組合輸入命令,而不報語法錯誤;

      5)函數內部使用shell的變量,比如是變量a,正確的寫法是$$a;而不是常規的shell寫法

      a

      ,也不是

      M

      a

      k

      e

      f

      i

      l

      e

      獲取變量的方法

      a,也不是Makefile獲取變量的方法

      a,也不是Makefile獲取變量的方法(a)或${a};這一點特別需要注意。

      6)如果函數內部訪問的是Makefile定義的變量,比如示例中的訪問DEBUG_VARIABLE變量,還是采用$(DEBUG_VARIABLE)的方式。

      好了,本期分享就到這里,有疑問的話,歡迎聯系我。

      7 更多分享

      歡迎關注我的github倉庫01workstation,日常分享一些開發筆記和項目實戰,歡迎指正問題。

      同時也非常歡迎關注我的CSDN主頁和專欄:

      【CSDN主頁-架構師李肯】

      【RT-Thread主頁】

      【C/C++語言編程專欄】

      【GCC專欄】

      【信息安全專欄】

      【RT-Thread開發筆記】

      【freeRTOS開發筆記】

      【BLE藍牙開發筆記】

      【ARM開發筆記】

      【RISC-V開發筆記】

      有問題的話,可以跟我討論,知無不答,謝謝大家。

      Makefile Shell

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:約嗎?微軟Office Mix團隊送你情人節禮物
      下一篇:如何快捷修改文檔中全部圖片的大小(怎么批量修改文檔中的圖片大小)
      相關文章
      相泽亚洲一区中文字幕| 亚洲沟沟美女亚洲沟沟| 亚洲天堂电影在线观看| 亚洲av网址在线观看| 亚洲午夜久久久久妓女影院| 久久精品国产亚洲Aⅴ香蕉 | 亚洲国产精品自产在线播放| 亚洲国产成人久久精品大牛影视| 在线观看亚洲AV日韩AV| 亚洲欧美aⅴ在线资源| 亚洲GV天堂GV无码男同| 日韩欧美亚洲国产精品字幕久久久 | 亚洲国产专区一区| 亚洲综合国产精品第一页| 亚洲天堂中文字幕在线| 国产福利电影一区二区三区,亚洲国模精品一区 | 国产亚洲午夜精品| 亚洲AV中文无码乱人伦在线视色| 亚洲成A∨人片天堂网无码| 亚洲国产人成精品| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 久久久久国产亚洲AV麻豆| 国产亚洲成人久久| 国产亚洲精品国产| 亚洲Av熟妇高潮30p| 亚洲视频国产精品| 亚洲av极品无码专区在线观看| 亚洲高清有码中文字| 亚洲精品宾馆在线精品酒店 | 成人精品国产亚洲欧洲| 亚洲国产成人VA在线观看| AV在线播放日韩亚洲欧| 亚洲精品少妇30p| 亚洲自偷自拍另类12p| 亚洲噜噜噜噜噜影院在线播放| 亚洲中文字幕一二三四区苍井空| 亚洲GV天堂GV无码男同| 亚洲片一区二区三区| 亚洲Av永久无码精品三区在线| 久久久久亚洲Av无码专| 国产亚洲精品bv在线观看|