functions in makefiles?
Asked Answered
C

3

30

I have a slew of makefile targets that do the same thing:

${SOME_FILE}:
    ${FILES} | ${DIST_DIR}

    @@cat ${FILES} |                     \
        sed 's/@DATE/'"${DATE}"'/' |     \
        sed 's/@VERSION/'"${CR_VER}"'/'  \
        > ${OUT_FILE};

where ${FILES} and ${OUT_FILE} are the only things changing. I'm trying to figure out if it's possible to simplify these targets to something like:

${SOME_FILE}:
    compile(${FILES},${OUT_FILE})

Thanks for any insight.

Calesta answered 21/7, 2011 at 21:47 Comment(0)
E
21

GNU make has this:

To define a multi-line function, you would use this syntax:

Erik answered 21/7, 2011 at 23:21 Comment(3)
Using define ... endef does nothing for me. It just ignores the line completely. I tried using $(var-name) and $(call var-name). I can just use a single line variable though and wrap the lines with a semi-colon, ;, and a backslash, \. I'm using Ubuntu 14.04 and my GNU make version is 3.81.Ludovico
Important note: when you define a function that calls $(MAKE), you must add the @+ after the equality sign. So like: sub_make = @+$(MAKE) -C $(TOPDIR)/subdir/$(1) $(2). Otherwise make won't pass descriptors and options it ought to to submake calls, which would manifest itself as a warning: jobserver unavailable: using -j1. Add '+' to parent make rule.Aristippus
answers should be "Just" links because links can go away (even if these haven't)Roede
G
36

Links to docs (like in the accepted answer) are good but good example is better :)

define my_func
    $(eval $@_PROTOCOL = "https:")
    $(eval $@_HOSTNAME = $(1))
    $(eval $@_PORT = $(2))
    echo "${$@_PROTOCOL}//${$@_HOSTNAME}:${$@_PORT}/"
endef

my-target:
    @$(call my_func,"example.com",8000)

Take into consideration the following:

  • There are no custom "functions" in Makefile language. So "my_func" is actually a variable that simply contains a text.
  • That "function" doesn't have its own scope. All the content of that "function" is copied into the recipe as is. All variables in the body will be used after that as a part of the recipe.
  • Don't use spaces near the commas to prettify param list of "call" function.
  • Args are passed like $(1), $(2), ... that is not very handy, so re-declare them with meaningful names. This is optional but recommended for bigger "function" bodies.
  • Variables are declared with $@_ prefix that makes them "local" to the rule (actually not local but prefixed by the target name).

So we have imitation of functions with imitation of local variables but generally this works good.

Groceryman answered 9/12, 2022 at 11:49 Comment(1)
I took inspiration from this answer to write a gist: gist.github.com/lulingar/f84ab70b86b37104dbbd7be0581c69edMariahmariam
E
21

GNU make has this:

To define a multi-line function, you would use this syntax:

Erik answered 21/7, 2011 at 23:21 Comment(3)
Using define ... endef does nothing for me. It just ignores the line completely. I tried using $(var-name) and $(call var-name). I can just use a single line variable though and wrap the lines with a semi-colon, ;, and a backslash, \. I'm using Ubuntu 14.04 and my GNU make version is 3.81.Ludovico
Important note: when you define a function that calls $(MAKE), you must add the @+ after the equality sign. So like: sub_make = @+$(MAKE) -C $(TOPDIR)/subdir/$(1) $(2). Otherwise make won't pass descriptors and options it ought to to submake calls, which would manifest itself as a warning: jobserver unavailable: using -j1. Add '+' to parent make rule.Aristippus
answers should be "Just" links because links can go away (even if these haven't)Roede
R
6

If you don't want to restrict yourself to GNUmake, your best bet is probably to generate makefile fragments yourself and then include them.

Rite answered 22/7, 2011 at 6:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.