Makefile講解

最近接觸到很多C++項目,其中很多項目中含有大量的Makefile文件,但是由於環境的不同Makefile也帶來了很多問題,所以決定以ice中的多個Makefile文件爲例進行了介紹,ice中的文件結構如下:

.
├── BuildInstructions.md
├── BuildInstructionsAIX.md
├── BuildInstructionsLinux.md
├── BuildInstructionsOSX.md
├── BuildInstructionsWindows.md
├── Makefile
├── allTests.py
├── bin
│   ├── glacier2router
│   ├── icebox
│   ├── iceboxadmin
│   ├── icegridadmin
│   ├── icegriddb
│   ├── icegridnode
│   ├── icegridregistry
│   ├── icepatch2calc
│   ├── icepatch2client
│   ├── icepatch2server
│   ├── icestormadmin
│   ├── icestormdb
│   ├── slice2confluence
│   ├── slice2cpp
│   ├── slice2cs
│   ├── slice2html
│   ├── slice2java
│   ├── slice2js
│   ├── slice2objc
│   ├── slice2php
│   ├── slice2py
│   └── slice2rb
├── config
│   ├── Make.rules
│   ├── Make.rules.MINGW
│   ├── Make.xcodesdk.rules
│   ├── glacier2router.cfg
│   ├── ice.cpp.props
│   ├── ice_ca.cnf
│   ├── icegridnode.cfg
│   ├── icegridregistry.cfg
│   └── templates.xml
├── include
│   ├── Glacier2
│   ├── Ice
│   ├── IceBT
│   ├── IceBox
│   ├── IceGrid
│   ├── IceIAP
│   ├── IcePatch2
│   ├── IceSSL
│   ├── IceStorm
│   ├── IceUtil
│   └── generated
├── lib
│   ├── libGlacier2.3.7a4.dylib
│   ├── libGlacier2.37a4.dylib -> libGlacier2.3.7a4.dylib
│   ├── libGlacier2.dylib -> libGlacier2.3.7a4.dylib
│   ├── libGlacier2CryptPermissionsVerifier.3.7a4.dylib
│   ├── libGlacier2CryptPermissionsVerifier.37a4.dylib -> libGlacier2CryptPermissionsVerifier.3.7a4.dylib
│   ├── libGlacier2CryptPermissionsVerifier.dylib -> libGlacier2CryptPermissionsVerifier.3.7a4.dylib
│   ├── libIce.3.7a4.dylib
│   ├── libIce.37a4.dylib -> libIce.3.7a4.dylib
│   ├── libIce.dylib -> libIce.3.7a4.dylib
│   ├── libIceBox.3.7a4.dylib
│   ├── libIceBox.37a4.dylib -> libIceBox.3.7a4.dylib
│   ├── libIceBox.dylib -> libIceBox.3.7a4.dylib
│   ├── libIceDB.3.7a4.dylib
│   ├── libIceDB.37a4.dylib -> libIceDB.3.7a4.dylib
│   ├── libIceDB.dylib -> libIceDB.3.7a4.dylib
│   ├── libIceDiscovery.3.7a4.dylib
│   ├── libIceDiscovery.37a4.dylib -> libIceDiscovery.3.7a4.dylib
│   ├── libIceDiscovery.dylib -> libIceDiscovery.3.7a4.dylib
│   ├── libIceGrid.3.7a4.dylib
│   ├── libIceGrid.37a4.dylib -> libIceGrid.3.7a4.dylib
│   ├── libIceGrid.dylib -> libIceGrid.3.7a4.dylib
│   ├── libIceLocatorDiscovery.3.7a4.dylib
│   ├── libIceLocatorDiscovery.37a4.dylib -> libIceLocatorDiscovery.3.7a4.dylib
│   ├── libIceLocatorDiscovery.dylib -> libIceLocatorDiscovery.3.7a4.dylib
│   ├── libIcePatch2.3.7a4.dylib
│   ├── libIcePatch2.37a4.dylib -> libIcePatch2.3.7a4.dylib
│   ├── libIcePatch2.dylib -> libIcePatch2.3.7a4.dylib
│   ├── libIceSSL.3.7a4.dylib
│   ├── libIceSSL.37a4.dylib -> libIceSSL.3.7a4.dylib
│   ├── libIceSSL.dylib -> libIceSSL.3.7a4.dylib
│   ├── libIceStorm.3.7a4.dylib
│   ├── libIceStorm.37a4.dylib -> libIceStorm.3.7a4.dylib
│   ├── libIceStorm.dylib -> libIceStorm.3.7a4.dylib
│   ├── libIceStormService.3.7a4.dylib
│   ├── libIceStormService.37a4.dylib -> libIceStormService.3.7a4.dylib
│   ├── libIceStormService.dylib -> libIceStormService.3.7a4.dylib
│   ├── libIceUtil.a
│   ├── libIceXML.3.7a4.dylib
│   ├── libIceXML.37a4.dylib -> libIceXML.3.7a4.dylib
│   ├── libIceXML.dylib -> libIceXML.3.7a4.dylib
│   ├── libSlice.a
│   ├── libTestCommon.3.7a4.dylib
│   ├── libTestCommon.37a4.dylib -> libTestCommon.3.7a4.dylib
│   └── libTestCommon.dylib -> libTestCommon.3.7a4.dylib
├── msbuild
│   ├── ice.cpp.props
│   ├── ice.cpp11.props
│   ├── ice.cpp98.props
│   ├── ice.nuget.targets
│   ├── ice.nuget.uwp.arch.targets
│   ├── ice.nuget.uwp.targets
│   ├── ice.proj
│   ├── ice.test.props
│   ├── ice.test.sln
│   ├── ice.testuwp.props
│   ├── ice.testuwp.sln
│   ├── ice.uwp.props
│   ├── ice.uwp.sln
│   ├── ice.v120.sln
│   ├── ice.v140.sln
│   ├── icebuilder.cpp.props
│   ├── zeroc.ice.uwp.arch.targets
│   ├── zeroc.ice.uwp.arm.nuspec
│   ├── zeroc.ice.uwp.nuspec
│   ├── zeroc.ice.uwp.props
│   ├── zeroc.ice.uwp.x64.nuspec
│   ├── zeroc.ice.uwp.x86.nuspec
│   ├── zeroc.ice.v120.nuspec
│   ├── zeroc.ice.v120.props
│   ├── zeroc.ice.v120.targets
│   ├── zeroc.ice.v140.nuspec
│   ├── zeroc.ice.v140.props
│   └── zeroc.ice.v140.targets
├── src
│   ├── Glacier2
│   ├── Glacier2CryptPermissionsVerifier
│   ├── Glacier2Lib
│   ├── Ice
│   ├── IceBT
│   ├── IceBox
│   ├── IceDB
│   ├── IceDiscovery
│   ├── IceGrid
│   ├── IceGridLib
│   ├── IceIAP
│   ├── IceLocatorDiscovery
│   ├── IcePatch2
│   ├── IcePatch2Lib
│   ├── IceSSL
│   ├── IceStorm
│   ├── IceStormLib
│   ├── IceUtil
│   ├── IceXML
│   ├── Slice
│   ├── icegriddb
│   ├── iceserviceinstall
│   ├── slice2confluence
│   ├── slice2cpp
│   ├── slice2cs
│   ├── slice2html
│   ├── slice2java
│   ├── slice2js
│   ├── slice2objc
│   ├── slice2php
│   ├── slice2py
│   └── slice2rb
├── test
│   ├── Common
│   ├── Glacier2
│   ├── Ice
│   ├── IceBox
│   ├── IceDiscovery
│   ├── IceGrid
│   ├── IceSSL
│   ├── IceStorm
│   ├── IceUtil
│   ├── Slice
│   ├── include
│   ├── ios
│   └── uwp
└── tree

先看ice/cpp 下的Makefile文件:

#定義變量

top_srcdir  := ..
lang_srcdir := $(top_srcdir)/cpp

#包含其他Makefile
include $(top_srcdir)/config/Make.rules
include $(lang_srcdir)/config/Make.rules

#
# Create projects for all the Slice translators from src/slice2* and load source projects.
#
projects :=
$(foreach t,$(wildcard $(lang_srcdir)/src/slice2*),$(eval $(call create-translator-project,$(call project,$t))))
include $(shell find $(lang_srcdir)/src -name Makefile.mk)
$(call make-projects,$(projects),make-cpp-src-project)

#
# Now, create and load test projects.
#
projects :=
tests := $(call tests-without-project-makefile,cpp)
include $(shell find $(lang_srcdir)/test -name Makefile.mk)
$(foreach t,$(tests),$(eval $(call create-cpp-test-project,$(t))))
$(call make-projects,$(projects),make-cpp-test-project)

install:: | $(DESTDIR)$(install_configdir)
    $(Q)$(INSTALL) $(lang_srcdir)/config/templates.xml $(DESTDIR)$(install_configdir)

foreach函數

foreach函數和別的函數非常的不一樣。因爲這個函數是用來做循環用的,Makefile中的foreach函數幾乎是仿照於Unix標準Shell(/bin/sh)中的for語句,或是C-Shell(/bin/csh)中的foreach語句而構建的。它的語法是:

$(foreach <var>,<list>,<text> )

這個函數的意思是,把參數list中的單詞逐一取出放到參數var所指定的變量中,然後再執行text所包含的表達式。每一次text會返回一個字符串,循環過程中,text的所返回的每個字符串會以空格分隔,最後當整個循環結束時,text所返回的每個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。

所以,var最好是一個變量名,list可以是一個表達式,而text中一般會使用var這個參數來依次枚舉list中的單詞。舉個例子:

names := a b c d
files := $(foreach n,$(names),$(n).o)

上面的例子中,$(name)中的單詞會被挨個取出,並存到變量n中,$(n).o每次根據$(n)計算出一個值,這些值以空格分隔,最後作爲foreach函數的返回,所以,$(files)的值是a.o b.o c.o d.o。

注意

foreach中的參數是一個臨時的局部變量,foreach函數執行完後,參數的變量將不在作用,其作用域只在foreach函數當中。

wildcard函數

在Makefile規則中,通配符會被自動展開。但在變量的定義和函數引用時,通配符將失效。這種情況下如果需要通配符有效,就需要使用函數”wildcard”,它的用法是:$(wildcard PATTERN…) 。在Makefile中,它被展開爲已經存在的、使用空格分開的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函數會忽略模式字符並返回空。

eval函數

函數原型 $(eval text)
它的意思是 text 的內容將作爲makefile的一部分而被make解析和執行。
例如:

define MA
aa:aa.c
 gcc  -g -o aa aa.c
endef 
$(eval $(call MA) )
會產生一個這樣的編譯:
gcc -g -o aa aa.c

call函數

call函數是唯一一個可以用來創建新的參數化的函數。你可以寫一個非常複雜的表達式,這個表達式中,你可以定義許多參數,然後你可以用call函數來向這個表達式傳遞參數。其語法是:

    $(call ;,;,;,;...)

當make 執行這個函數時,;參數中的變量,如(1) (2),$(3)等,會被參數;, ;,;依次取代。而;的返回值就是call函數的返回值。例如:

   reverse =  $(1) $(2)
   foo = $(call reverse,a,b)

那麼,foo的值就是“a b”。當然,參數的次序是可以自定義的,不一定是順序的,如:

    reverse =  $(2) $(1)
    foo = $(call reverse,a,b)

此時的foo的值就是“b a”。

參考資料

  1. Makefile 中:= ?= += =的區別
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章