Search code examples
makefile

How to list all sub makefiles and call them using a loop


I am struggling to list all my Makefiles and call them from a master one..

I've got a directory of subprojects like this:

/awesome
  /john
    /doe
      Makefile
  /foo
    Makefile
  /bar
    Makefile
  Makefile (master one)

Let's say that each sub makefile looks like this

hell-yeah:
    echo HEY!

What i'd like to do is to search for all the submakefile, like this

SOURCES := $(wildcard **/Makefile)

Once i got them all, i'd like to run something like this make awesome

SOURCES := $(wildcard **/Makefile)

awesome: ## Run all submakefile hell-yeah rule
    for submakefile in $$SOURCES; do \
         $(MAKE) -C $$submakefile hell-yeah \
    done

How can I achieve it?

As of right now, I am getting the following error

for submakefile in $SOURCES; do \
         /Library/Developer/CommandLineTools/usr/bin/make -C $submakefile hell-yeah \
    done
/bin/sh: -c: line 1: syntax error: unexpected end of file

Thanks


Solution

  • You could write this shell script, or something like it:

    #!/bin/sh
    
    find * -mindepth 1 -name Makefile -print0 |
      sed -z 's,/Makefile,,' |
      xargs -0 -r -P1 -I{} make -C {} hell-yeah
    

    That does rely on the GNU versions of the utilities used. If relying on GNU versions is not acceptable then this variation does mostly the same thing, though it will trip over paths that contain blank or newline characters:

    #!/bin/sh
    
    find * -mindepth 1 -name Makefile -print |
      sed 's,/Makefile,,' |
      xargs -P1 -I{} make -C {} hell-yeah
    

    Both of these assume that you will run them from the top directory (/awesome), and neither runs make in that directory itself, though that could easily be added.

    You could embed either of those in a recipe in a makefile, but you shouldn't. If you want to drive all these builds from a top-level makefile then that makefile should have an explicit enumeration of the project folders to build:

    projects = \
      john/doe \
      foo      \
      bar
    
    .PHONY: $(projects)
    
    all: $(projects)
    
    $(projects): %:
            make -C $@ hell-yeah
    

    That does rely on features specific to GNU make.