开发者

How to generate Makefile rule

开发者 https://www.devze.com 2023-02-15 21:33 出处:网络
I want to do generate rules in Makefile by this: # $(call cc-defs, ccfiles) define cc-defs $1.files = $(patsubst %.cc,%.proto,$1)

I want to do generate rules in Makefile by this:

# $(call cc-defs, ccfiles)
define cc-defs
    $1.files = $(patsubst %.cc,%.proto,$1)
    $1: $1.files
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))

but failed with error message:

Makefile:19: *** commands commence before first target.  Stop.

Instea开发者_Python百科d that, I can do this by:

# $(call cc-defs, ccfiles)
define cc-defs
    $1.files = $(patsubst %.cc,%.proto,$1)
endef

$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
$(foreach ccfile,$(ccfiles), $(eval $(ccfile):$($(ccfile).files)))

How to make the 1st method works?


Which version of make are you using? $(eval) only appeared in 3.80 (and it only properly works in 3.81 IMHO).

To debug makefiles you'll often have to revert to printf debugging. To see what's going on, replace eval with warning. This shows what you are giving to make:

$ make --warn
Makefile:6: warning: undefined variable `ccfiles'
make: *** No targets.  Stop.

(Aside: --warn-undefined-variables is always useful. Undefined variables are untidy.)

O.K., so we need to define $ccfiles. Now we get the for loop firing:

$ make --warn ccfiles=1.cc
Makefile:6:    1.c.files = 1.cc
               1.cc:  1.c.files
make: *** No targets.  Stop.

Fine. You have given make no recipes, nor a default target. You also have missed out on some variable expansion, and have an extra space in the $(for) invocation (naughty!). Try this:

$ cat Makefile
# $(call cc-defs,ccfiles)
define cc-defs
  $1.files = $(patsubst %.cc,%.proto,$1)
  $1: $$($1.files) ; echo '[$$@]'
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs,$(ccfile))))

$ make ccfiles=1.cc
make: *** No rule to make target `1.proto', needed by `1.cc'.  Stop.


Note that if all you want to do is for all files in a variable to depend on (or be made from) .proto files, you don't need $(eval).

A pattern rule will do (and will work in older versions of GNU Make too):

$(ccfiles): %.cc: %.proto
        echo '[$@]'

This does have the side effect of complaining when the ccfiles variable contains any entries not named *.cc (although it still executes the rule in that case).

$ make ccfiles=hello.cc
make: *** No rule to make target `hello.proto', needed by `hello.cc'.  Stop.
$ touch hello.proto
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
Makefile:1: target `hello.c' doesn't match the target pattern
[hello.c]

If the variable can contain many things but you only want to add this processing to .cc files, simply add a filter:

$(filter %.cc,$(ccfiles)): %.cc: %.proto
        echo '[$@]'

This then results in:

$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
make: *** No targets.  Stop.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号