159

I'm getting some unexpected results calling one makefile from another. I have two makefiles, one called /path/to/project/makefile and one called /path/to/project/gtest-1.4.0/make/Makefile. I'm attempting to have the former call the latter. In /path/to/project/makefile, I have

dev: $(OBJ_FILES)
  $(CPPC) $(LIBS) $(FLAGS_DEV) $(OBJ_FILES) -o $(BIN_DIR)/$(PROJECT)
  $(MAKE) -f ./gtest-1.4.0/make/Makefile

clean:
  rm -f ./*~ ./gmon.out ./core $(SRC_DIR)/*~ $(OBJ_DIR)/*.o
  rm -f ../svn-commit.tmp~
  rm -f $(BIN_DIR)/$(PROJECT)
  make -f gtest-1.4.0/make/Makefile clean

And in /path/to/project/gtest-1.4.0/make/Makefile I have

all: $(TESTS)

clean:
  rm -f $(TESTS) gtest.a gtest_main.a *.o

Issuing the following:

cd /path/to/project
make

Outputs:

make -f ./gtest-1.4.0/make/Makefile
make[1]: Entering directory `/path/to/project'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/path/to/project'

However, when I issue these commands:

cd /path/to/project
make clean

I see:

make -f gtest-1.4.0/make/Makefile clean
make[1]: Entering directory `/path/to/project'
rm -f  gtest.a gtest_main.a *.o
make[1]: Leaving directory `/path/to/project'

I don't understand: In both cases, /path/to/project/makefile is telling me it's entering the current working directory. In the first case, it doesn't think it has work to do (when it does) and in the second case, it's able to find the appropriate directive (when the output is telling me it's looking in the wrong directory) yet it tries to run the rm command in /path/to/project, instead of /path/to/makefile/gtest-1.4.0/make/.

Am I missing something fundamental to calling makefiles from one another? Have I made an egregious conceptual mistake, or hit a common pitfall? How do I effectively change directories and call a second makefile from within the first? My understanding was that simply calling make -f <name> would be enough.

This is make/gmake 3.81 in bash.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Chris Tonkinson
  • 13,823
  • 14
  • 58
  • 90
  • 3
    I think, instead of `make -f gtest-1.4.0/make/Makefile clean` you better say `$(MAKE) -C gtest-1.4.0/make clean`. Why you haven't defined phony targets? – dma_k Jun 22 '10 at 15:43
  • http://stackoverflow.com/questions/3494999/subdirectories-and-makefiles – Jared Burrows Jun 08 '14 at 15:34

4 Answers4

153

I'm not really too clear what you are asking, but using the -f command line option just specifies a file - it doesn't tell make to change directories. If you want to do the work in another directory, you need to cd to the directory:

clean:
    cd gtest-1.4.0 && $(MAKE) clean

Note that each line in Makefile runs in a separate shell, so there is no need to change the directory back.

kenorb
  • 155,785
  • 88
  • 678
  • 743
  • 81
    Instead of manually `cd`'ing to the `gtest-1.4.0` dir, you should use the `-C` option of `make`. – Tader May 02 '12 at 14:40
  • 34
    Or at the very least, you should definitely use `&&` between the cd and make command. Otherwise if the cd fails it will still run `make clean`... in the wrong directory!! Also you should always ONLY use `$(MAKE)`, never the bareword `make`, when recursing. So something like: `cd gtest-1.4.0 && $(MAKE) clean` – MadScientist May 03 '12 at 15:36
  • 3
    @Tader: `-C` is not in [the spec](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html) – Janus Troelsen Oct 02 '15 at 12:24
  • 3
    This question about gnu-make and `-C` is in the spec: https://www.gnu.org/software/make/manual/make.html#Recursion – Cas May 11 '18 at 13:51
141

Instead of the -f of make you might want to use the -C <path> option. This first changes the to the path '<path>', and then calles make there.

Example:

clean:
  rm -f ./*~ ./gmon.out ./core $(SRC_DIR)/*~ $(OBJ_DIR)/*.o
  rm -f ../svn-commit.tmp~
  rm -f $(BIN_DIR)/$(PROJECT)
  $(MAKE) -C gtest-1.4.0/make clean
Tader
  • 25,802
  • 5
  • 26
  • 27
  • 2
    This way seems to the best. Come of the other replies which use `cd` cause the terminal to get into a infinite loop. – gbmhunter May 30 '13 at 00:31
  • 1
    $(MAKE) -C gtest-1.4.0/make clean does not work for me. I think it should be $(MAKE) -C gtest-1.4.0 clean – Arigion Jul 31 '20 at 15:45
56

http://www.gnu.org/software/make/manual/make.html#Recursion

 subsystem:
         cd subdir && $(MAKE)

or, equivalently, this :

 subsystem:
         $(MAKE) -C subdir
Aadishri
  • 1,341
  • 2
  • 18
  • 26
1

It seems clear that $(TESTS) is empty so your 1.4.0 makefile is effectively

all: 

clean:
  rm -f  gtest.a gtest_main.a *.o

Indeed, all has nothing to do. and clean does exactly what it says rm -f gtest.a ...

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
  • $(TESTS) is defined with a `wildcard` and a `patsubst`, however these are returning empty from the main makefile, because the directory is not being effectively changed. Good eye. – Chris Tonkinson Feb 05 '10 at 17:47