トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
Make
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索
___

■ 関数(Function)(組み込み関数)


  POINT
    Make の組み込み関数は文字列操作が主な目的
    文字列置換 と同じ
    call は 関数.Call  というより 特殊な文字列置換
    


    list 中から 目的の file を選択

    変数参照に見えるが , 区切りの Argument をもつ
    何かの値に展開され, 変数への代入 , Shell にわたされる

  POINT
    Command 列を 変数に格納することで 応用範囲が広がる
    Macro, 変数 への展開結果をかえれるように Argument をわたせる

    Make の関数には 数値 という型はない( 文字列として扱う )

    # (call has-duplicate, list)

    # 数値も 文字列として比較
    #
    has-duplicate = $(filter                    \
                      $(word $1)             \
                       $(words $(sort $1)))
関数が Nest される場合は, 最下層から ひとつずつ読む

    # (call file-to-class-name  rootdir file)
    file-to-class-name := $(subst /,.,             \    # "/" -> "."
                          $(subst .java,,       \      # ".java" を除去
                            $(subst $1/,,$2)))         # "$1/" を除去


SYNTAX $(function arg[, arg...]) # Argument の参照は $N とする echo $1 # 展開するには call 組み込み関数 を利用 # call は 関数 というより # 特殊な マクロ展開 # $(call MACRONAME arg, [arg...]) POINT
     Macro, 変数 の違いは [\n] が組み込まれるかどうかだけ
WARNING [,] 以降の SPC は arg として解釈

    #  ","  の後の " " は不要
    $(call intro, yamada) -> $1 = [ yamada]

    # パターンの適用も OK
    #    [%] == 0文字以上
    $(function %.obj)

POINT Windows は File を開くと, 他の Process からの書き込みを防止するため File を Lock する POINT Make の EmbededFunc の共通点
     Text をもらって, ある操作をして 別の Text をかえす
     Argument は [,] 区切り
     Argument のひとつとして SPACE 区切りの 単語 List をもらう
       単語間の Space は区切り扱いだが, それ以外は無視

     Pattern 指定も OK
        [%] : 0 コ以上の文字
___

■ 文字列関数

___

■ filter

SYNTAX: $(filter ptn ...,text ) DESC text を " " 区切り文字として ptn 一致のものを取得 grep みたいなもの

    # ui/*.o  のみを filter する
    #
      $(ui_lib): $(filter ui/%.o,$(OBJS))
          $(AR) $(ARFLAGS) $@ $^

      words := he the hen other the%
      get-the:
        @echo he matches $(filter he, $(words))
        @echo %he matches $(filter %he, $(words))

WARNING 単語は一部を含むではなく, すべて一致する必要あり ptn[%] は一度しか使用できない 複数あれば 最初のみ ptn[%] 残りは文字あつかい( [%]という文字にマッチ )
___

■ filter-out

SYNTAX $(filter-out ptn ...,text ) DESC ptn に一致しない text 内の単語をかえす
      # ptn 不一致を取得
      $(filter-out ptn, text)

  srcs := main.c sub.c main.h sub.h

  # xxx.h を除去する
  to_compile := $(filter-out %.h, $(srcs))

___

■ findstring

SYNTAX $(findstring serStr,text) DESC text 中の serStr を検索 見つかれば serStr( 検索文字列 ) 自身をかえす wildcard[%] は使用不可 if() とあわせると便利

  TIP
    [#]: make の変換結果を見るための, echo より簡易な方法


  # 複数の Tree ( src, DebugBinary, ReleaseBinary のどこにいるか調べる)
   find-tree:
      # PWD = $(PWD)

      # Tab から始まるため, Make は SubShell への Command と解釈
      #    Make 関数で置換してから わたす
      #
      # $(findstring d:/0916, $(PWD))
      # $(findstring d:/0915, $(PWD))
      # $(findstring d:/0914, $(PWD))

___

■ subst

SYNTAX $(subst serStr,repStr,text) DESC 文字列( text ) を置換( Substitute ) [%] の指定はできない POINT

    # ext を変更するときに便利
    #  .c -> .o
    #
    SRCS := main.c sub.c foo.c
    $(subst .c,.o,$(SRCS))

WARNING
    # [,] の後の空白は文字扱いになる

    # ERROR
    #    ".c "".o"  にかわる
    $(subst .c ,.o,(SRCS))

    # ERROR
    #    "main.c"  --->  "main .o"
    $(subst .c, .o,(SRCS))

    # OK
    #  RET: main.o  sub.o  foo.o
    $(subst .c,.o,(SRCS))

___

■ patsubst

SYNTAX $(patsubst serPtn,repPtn, text) DESC wildcard 使用の検索、置換 [%]: は match した文字列に置換される WARNING
    # 末尾 の [/] を除去
    #    serPtn: text 全体で一致する必要あり
    #    途中の [/] は置換されない
    #
    strip-tail-slash = $(patsubst %/,%,$(dirPath))
  BAD
    %/ -> [aaa/bbb/]ccc
  OK
    %/ -> [aaa/bbb/ccc/]
$(variable:ser=rep) ser: 通常文字列 -> 単語の末尾に一致 -> rep に置換 OBJS := $(SRCS:.cpp=.o) ser: [%]文字列 -> patsubst 同様
___

■ words

SYNTAX $(words text) DESC 単語数をかえす

    CURPATH := $(subst /, ,$(HOME))
    words:
          echo $$HOME has $(words $(CURPATH)) Directory


    # [/] -> [SPC] 変換
    CURPATH := $(subst /, ,$(HOME))
    words:
  @echo $(HOME)
  @echo my home path has $(words $(CURPATH))dirs
  @echo first dir is $(word 1, $(CURPATH))
  @echo second dir is $(word 2, $(CURPATH))


___

■ word

SYNTAX $(word n,text) DESC [n] 番目の text を返す 1 が最初 n > nrText ならば 何も返さない POINT
    # list 最後の取得
    current := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
___

■ firstword

SYNTAX $(firstword text) DESC 1 番目の 単語をかえす == $(word 1,text)
    # 単語 List に変換
    #    "xxx.yyy.zzz" -> "xxx yyy zzz"
    #
    version_list := $(subst ., ,$(MAKE_VERSION))

    major_version := $(firstword $(version_list))


___

■ wordlist

SYNTAX $(wordlist start,end,text) DESC [start:end] list をかえす start > $(words text) start > end なら何も返さない end > $(words text) なら [start:$(words text)]をかえす

    # $(call uid_gid username)
    #
    uid_gid = $(wordlist 3,4 \
                $(subst :, ,\
                   $(shell grep "^$1:" /etc/passwd)
                  )
                )


___

■ call

SYNTAX $(call cmd,arg...)
___

■ sort

SYNTAX $(sort list) DESC 単語の重複, 前後の SPACE を除去してソートする

    # STDIN から makefile の内容を入力
    #
    make -f- < < <  'x:;@echo =$(sort a n d d c e)='


___

■ shell

SYNTAX $(shell cmd) DESC ひとつの Argument をうけつけて, 展開後に SubShell にわたす STDOUT への出力は 結果としてかえる [\] は " "に置換される STDERR, Exit Status は返されない POINT $(shell cmd) は subshell 実行後の結果に置換される

      stdout := $(shell echo normal msg)
      stderr := $(shell echo err msg 1>&2)

    # STDERR への出力は shell 関数の戻値にならない
    #
      shell-value:
          # $(stdout)
          # $(stderr)
      # RET: [Mon Sep 17 10:41:29]
      # make がこの行を解釈すれば ERR
      $(shell date)

      # こちらは OK
         $(shell oman test)
# make をはじめる前に 必要な dir を作成する # bash の for 文を利用して Directory 作成 #
    POINT
      _MKDIRS 自体は意味はない
      $(shell) が実行されることが目的

    REQ_DIRS := foo bar goo
    _MKDIRS := $(shell for d in $(REQ_DIRS);      \
                 do                             \
                   [[ -d $$d ]] || mkdir -p $$d; \
                 done)
WARNING 単純変数 と 再帰変数の違いに注意すること ST := $(shell date) CT := $(shell date) # CT が利用されるたびに評価 # date uniq file を作成 RELEASE_TAR := mpwm-$(shell date +%F).tar.gz # $(call file-to-class-name, filename) # 相対 Path を Java クラス名に変換 # file-to-class-name := $(subst /,.,$(patsubst %.java,%,$1))
___

■ file.名関数

___

■ wildcard

SYNTAX $(wildcard ptn...) DESC ptn に match した file 名に展開 一致しないなら "" TIP ptn は Target, Depend で展開されるのと同じ Shell の 展開文字 を利用する [ ~, *, ?, [...], [^...] ] "%" をまちがって利用しないように
    #  $(shell) で代用するとこうなる
    SRCS := $(shell ls *.cpp)
    # shell の ptn match 同様( Directory 込みで match )
    # RET
    #      ./dir/aaa.cpp ./dir/bbb.cpp
     $(wildcard ./dir/*.cpp)
    #  xxx.c, xxx.h   をセット
    SRCS := $(wildcard *.c *.h)

POINT Directory .cpp をすべて取得可能 SRCS := main.cpp sub.cpp ... といったベタガキは不要
   #  if と併用することで File の有無をチェック
   #
   dotemacs := $(wildcard ~/.emacs)
WARNING Current Directory 基準( 再帰的ではない )
    # Sub Directory にはマッチしない
    #  RET:
    #    ./foo.cpp ./bar.cpp
    $(wildcard *.cpp)

___

■ dir|notdir

SYNTAX $(dir list ...) DESC list の各単語の Directory 部分を返す
     # src Directory 検索
    #
     srcdir:=$(sort               \
              $(dir             \
                $(shell find . -iname "*.cpp")))

# $(call srcdir,dirlist) # WARNING # 即時評価では問題あり $(call srcdir,/pro/intp) srcdir=$(sort \ $(dir \ $(shell find $1 -iname "*.cpp"))) @echo $(call getshbody,test.sh) getshbody=$(notdir $(subst .sh,,$1))

    # File の出力先と同じ Directory で実行
    #
      $(OUT)/myfile.out: $(SRC)/src.in
              cd $(dir $@);                       \
              generate-myself $^ > $(notdir $@)
___

■ suffix

SYNTAX $(suffix name ...) DESC list から suffix をかえす
    # RET
    #    bat
     $(suffix test.bat)

      # 同一 suffix Check
      same-suffix = $(filter 1,$(words $(sort $(suffix $1))))
TIP findstring 関数と共に if() で使用
___

■ basename

SYNTAX $(basename list...) DESC File Suffix を除去した文字列をかえす
    # RET
    #     main sub
    test:
      echo $(basename main.cpp sub.cpp)

    # $(call file-to-class-name  rootdir  filename)
    file-to-class-name := $(subst /,.,           \
                            $(basename        \
                              $(subst $1/,,$2)
                            )
                          )
    # $(call get-java-class-name  filename)
    #
    #  Java のクラス名をかえす
    #
    get-java-class-name = $(notdir  $(basename $1))

___

■ addsuffix

SYNTAX $(addsuffix suffix list) DESC list の各単語に suffix 追加 POINT
    wildcard の patten は shell と同じ
    filter は [%] のみ
    # $(call find-program, %)

    find-program = $(filter $1                  # 最後に filtering
                    $(wildcard                # wildcard で検索
                        $(addsuffix /*,        #  wildcard 用に "/*" を追加
                          $(sort               # sort
                             $(subst :, ,      # PATH 区切り[:] -> " " 単語に分解
                                $(subst ::,:.:,
                                  $(patsubst :%,.:%,
                                    $(patsubst :%,:.,$(PATH)
                                   )
                                )
                             )
                          )
                        )
                    )
                  )

___

■ addprefix

SYNTAX $(addprefix pfxk,name...) DESC
      # file が空でないかテスト

      # "-a -s " が prefix
      # Command 内で利用されることを想定
      #
      validfile = test -s . $(addprefix -a -s ,$1)
___

■ join

SYNTAX $(join pfxlist,sfxlist) DESC prefix list, suffix list の各単語を連結 dir notdir で分離した単語を結合できる
      # 苗字 と 名前
      fname := yamada  suzuki
      sname := taro    itiro

      fullname := $(join $(fname),$(sname))
___

■ 実行制御

POINT 実行制御をすることで幅広い処理ができる error も本質的には 実行制御
___

■ if

SYNTAX $(if cond,then-part,else-part) DESC cond が "文字列を含めば" : 真 NULL 文字列 : 偽 cond の前後の空白は除去した後, 結果がチェックされる true ならば then-part マクロが展開 false ならば else-part マクロが展開
    # PATH 区切り文字を決める
    #
    #  $(COMSPEC) は windows のみ定義
    #
     PATH_SEP := $(if $(COMSPEC),;,:)
POINT # if - filter で 文字列のチェックをする # Version Check $(if $(filter $(MAKE_VERSION),3.80),, \ $(error this ver in not 3.80) ) POINT Macro 言語 と Programing 言語は異なる Macro 言語 は Macro の定義, 展開をして 結果をえるのが Macro 言語
___

■ error

___

■ error

SYNTAX $(error text) DESC Error 報告をして ExitCode 2 をかえす
    # make assert
    #   $(call assert cond,msg)
    #
    define assert
      $(if $1,,$(error assertion failed: $2))
    endef


    #
    # make assert
    #      $(call assert-exit-file filePtn,msg)
    #      wildcard を利用して filePtn にマッチする file があるかチェック
    #
    define assert-exit-file
      $(call assert $(wildcard $1),$1 not exist)
    endef


    # make assert
    # $(call assert-not-null makeVar)
    #
    # WARNING
    #        VOID:=aiueo
    #        $(call assert-not-null VOID) != $(VOID)
    #
    define assert-not-null
      # $($1) とあるのは 引数 として 変数をもらうため
      #
      $(call assert $($1),var $1 is null)
    endef

POINT Make の変数 は 他の変数も代入できる 変数がはいった 変数を展開するには 2 回展開する

    # NULLVAR

    # RET
    #      "NULLVAR is null"
    #
    (call assert-not-null  NULLVAR)

___

■ warning

SYNTAX $(warning text) DESC 警告 Message を表示 error とは違い, Make は終了しない POINT makefile( FILE ), LINE を表示してくれる POINT 展開されないので, すべての場所で利用できる
___

■ foreach

SYNTAX $(foreach var,list,body) DESC list の単語を順に var に設定して, body を展開 展開された body の結果は " "区切りで累積する SPC 区切りの文字列 list として展開

    # RET
    #    music_1.wmv music_2.wmv music_3.wmv ...
    #
    tmp:
        @echo $(foreach idx,1 2 3 4 5 6 7 8 9,$music_$idx.wmv)

    # $(call grep-string  serstr, list)
    #
    #    List から serstr を含む文字のみ抽出
    #
    define grep-string
      $(strip
        $(foreach w,$2
           $(if  $(findstring $1,$w),$w))))

    endef

    list := foo.h bar.h foo.cpp

    # RET
    #    "foo.h foo.cpp"
    test:
        echo $(call grep-string,foo,$(list))


POINT Make の関数は PreProcessor と同じ その場で展開するため, 展開後の結果がおきかわる
    VAR := foo

    #  TopLevel で展開された結果は ERROR
    $(call grep-string,foo,$(list))

letters := $(foreach letter,a b c d,$(letter)) show-words: # letter has $(words $(letters)) words: $(letters) VARLIST := SRCS OBJS HOME $(foreach i,$(VARLIST),\ $(if $($1),,$(shell echo $i has no value > /dev/stderr))\ )
___

■ strip

SYNTAX $(strip text) DESC 前後の空白除去と list 間の空白をひとつにする [ aaa bbb ccc ] -> [aaa bbb ccc] TIP $(if) 判定の引数をきれいにするのに利用する

    #  [,] の後の " " が arg2 に含まれてしまう
    #
    $(call func,arg1, arg2)


   VAR:= aaa         bbb       ccc

   test:
     echo $(VAR)
     echo __$(strip $(VAR))__


   # echo __aaa         bbb       ccc   __
   # __aaa bbb ccc __
   # echo __aaa bbb ccc__
   # __aaa bbb ccc__

___

■ origin

SYNTAX $(origin var) DESC 変数の出所を調べる
    undefined:            未定義
    default:              組み込み ( DB で定義すみ )
    enviroment:           ENV
    enviroment override: (-e)--enviroment-overrides
    file:                makefine 定義
    command line:         CommandLine 定義
    override :          overwride 命令
    automatic :        自動変数

      $(origin MAKE_VERSION)  # 変数名自体

      make testtgt DATE=`date`
      $(origin DATE)  # cmdline

      # 変数 宣言 チェック
      define assert-defined
        $(call assert,\
                $(filter-out undefined,$(origin $1)),\
                $1 is undefined)
      endef

___

■ 高度なユーザー定義関数

POINT Debug 機能は多くないので自前で用意すること POINT [=] を利用するのは, := では関数の評価に問題あり
    # 関数 call を Trace
    #
    debug-enter = $(if $(debug-trace),\
                    ($warning Enter $0$(echo-args)))

    debug-leave = $(if $(debug-trace),\
                    ($warning Leave $0))

    # WARNING
    #    引数の数を数えることはできない( 数も固定 )
    #
    comma := ,
    echo-args = $(subst ' ','$(comma) ',\
                  $(foreach a,1,2,3,4,5,'$($a)'))


    debug-trace = 1

    define a
      $(debug-enter)
      echo $1 $2 $3
      $(debug-leave)
    endef

    define b
      $(debug-enter)
      $(call a,$1,$2,hi)
      $(debug-leave)
    endef

    test:
        $(call b,5,$(MAKE))

___

■ eval.関数と.val

SYNTAX: $(eval exp) DESC Exp を Make の構文解析に直接渡す( eval 自体は値を返さない ) POINT EXp が make に描かれていたことを 考えれば OK POINT
     Make の関数はまず 引数が変数の場合,展開する
      $(eval SRCS:=foo.c bar.c)



# $(call pro-var,pfx,list) # # list から 変数 $1_s, $1_h $1_o に file をセットする # define pro-var $1_s = $(filter %.c,$2) $1_h = $(filter %.h,$2) $1_o = $(subst .c,.o,$(filter %.c,$2)) $($1_o): $($1_h) endef # lss=ls.c glob.c < - make が tgt としてみなした # # WARNING # TopLevel では 複数行の Macro は Error になる # [区切り文字] がない といわれる # eval はこれを解消するためにできた # # $(call pro-var,ls,ls.c ls.h glob.c glob.h) # # $(eval lss=ls.c glob.c) # 代入式が評価される # $(eval $(call pro-var,ls,ls.c ls.h glob.c glob.h)) TIP 複数行の macro を扱う 2. 関数置換後の str を再評価 2. eval の引数は 2度展開される make が eval を展開する 2. eval 自身 POINT Macro とは define によって定義される 特殊な変数 ( ie. Macro は変数のひとつ ) Macro と 変数の違いは , Macro が [\n] を含めることができること POINT eval を使う理由は, 複数の変数を展開をするため POINT 複数行に 展開される Macro を makfile の Top で利用するには eval() にわたすこと WARNING 最初の Macro の展開だけでは, Macro 内の変数の代入はされない # 展開後の 代入がされない ls_s = ls.c ls_h = ls.h ls_o = ls.o # ので これは 正しくない # 変数代入の前に参照された $(ls_o): $(ls_h) # そこで, $$ として展開を遅延させる $$($1_o) : $$($1_h) POINT まとめ eval の引数は 2 回展開される 1 回目 : Make が eval の引数を展開 2 回目 : eval 自身の展開 # これでも OK # eval を代入に利用することで, Macro 内でおこなう # define pro-var $(eval $1_s = $(filter %.c,$2)) $(eval $1_h = $(filter %.h,$2)) $(eval $1_o = $(filter %.o,$2)) $($1_o): $($1_h) endef POINT まとめとして, 次のように使う define pro-var $(eval $1_s = $(filter %.c,$2)) $(eval $1_h = $(filter %.h,$2)) $(eval $1_o = $(filter %.o,$2)) programs += $1 $1: $($1_o) $($1_o): $($1_h) endef # TopLevel で展開する # POINT # 文字列の置換にすぎないことを覚えておくこと # $(eval $(call pro-var ls,ls.c ls.h )) $(eval $(call pro-var mv,mv.c mv.h )) WARNING 複数行に展開される macro は構文 ERROR
___

■ hook.関数

POINT
     User 定義関数とは 単に 文字列を格納した変数のこと
     call は 関数という文字列  の中で  $1, $2 があれば, 引数に置換するだけ
        そのため変数に文字列がなくても何もしない
    #  $1, $2 を引数に展開
    #
     $(call func,foo,bar)

    # これは ERROR にならない
    #
     $(call invalidfunc,foo,bar)
POINT hook を利用すると 関数がさらに便利になる user は hook に自分の好きな処理を追加できる
    # ar 後 後処理を build-library-hook という macro で用意しておく
    define build-library
      $(AR) $(ARFLAGS) $@ $1
      $(call build-library-hook,$@)
    endef


    # hook を使うには
    #    hook 関数( という変数 )に処理をいれる
    #
    $(foo_lib): build-library-hook = $(RANLIB) $1
    $(foo_lib): $(fooobj)
          $(call build-library,$^)

    $(bar_lib): build-library-hook = $(CHMOD) 444 $1
    $(bar_lib): $(barobj)
          $(call build-library,$^)
___

■ 関数に値を渡す

DESC call を利用 2. 関数外の変数 3. tgt 固有変数
















NINJAIDX 6