2

I am working on a Makefile which has a¹ receipt producing some file using M4. It uses some complex shell constructions to compute macro values which have to be passed to M4. How can I organize code to avoid redundant declarations displayed in the following example?

M4TOOL= m4
M4TOOL+= -D PACKAGE=$$(cd ${PROJECTBASEDIR} && ${MAKE} -V PACKAGE)
M4TOOL+= -D VERSION=$$(cd ${PROJECTBASEDIR} && ${MAKE} -V VERSION)
M4TOOL+= -D AUTHOR=$$(cd ${PROJECTBASEDIR} && ${MAKE} -V AUTHOR)
M4TOOL+= -D RDC960=$$(openssl rdc960 ${DISTFILE} | cut -d ' ' -f 2)
M4TOOL+= -D SHA256=$$(openssl sha256 ${DISTFILE} | cut -d ' ' -f 2)

Portfile: Portfile.m4
    ${M4TOOL} ${.ALLSRC} > ${.TARGET}

¹ Actually a lot!

Tim Enghel
  • 215
  • 2
  • 12
  • Can you be more specific? Which redundant declarations do you want to avoid? – Andrej Adamenko Aug 29 '14 at 17:54
  • Even if you could define a subroutine, the bigger problem is that you'd still be calling `make` 3 times. You can group multiple uses of `-V` to cut that down to one, but you'd need some extra shell to parse that into 3 separate `-D` options for `m4`. There's not much you can do about combining the two calls to `openssl`. – chepner Aug 29 '14 at 17:55
  • @AndrejAdamenko I would like to reduce redundancy of `cd … && ${MAKE} -V` and find a “phonier” way to put things. – Tim Enghel Aug 29 '14 at 18:31
  • @chepner I can live with the many calls to `make`, I have more a readability/maintainance issue. It could be efficienter to include a second makefile defining the appropriate values or to wrap the `m4` call in a true script. – Tim Enghel Aug 29 '14 at 18:33

1 Answers1

3

You should define pseudo-commands using the -c option of the shell, like this:

PROJECTVARIABLE=sh -c 'cd ${PROJECTBASEDIR} && ${MAKE} -V $$1' PROJECTVARIABLE
OPENSSLHASH=sh -c 'openssl $$1 $$2 | cut -d " " -f 2' OPENSSLHASH

Note the use of $ or $$ to use bsdmake variable expansion or shell variable expansion. With these defintions you can reorganise your code like this:

M4TOOLS+= -D PACKAGE=$$(${PROJECTVARIABLE} PACKAGE)
M4TOOLS+= -D VERSION=$$(${PROJECTVARIABLE} VERSION)
M4TOOLS+= -D AUTHOR=$$(${PROJECTVARIABLE} AUTHOR)
M4TOOLS+= -D RMD160=$$(${OPENSSLHASH} rmd160 ${DISTFILE})
M4TOOLS+= -D SHA256=$$(${OPENSSLHASH} sha256 ${DISTFILE})

The result is arguably easier to read and maintain. When you write such scripts, remember to use error codes and stderr to report errors.

PS: You can take a look at the COPYTREE_SHARE macro in /usr/ports/Mk/bsd.port.mk on a FreeBSD system. It illustrates well the technique.

Michaël Le Barbier
  • 6,103
  • 5
  • 28
  • 57