Jak wywołać Makefile z innego Makefile?

125

Otrzymuję nieoczekiwane wyniki podczas wywoływania jednego pliku makefile z innego. Mam dwa pliki makefile, jeden o nazwie /path/to/project/makefilei jeden o nazwie /path/to/project/gtest-1.4.0/make/Makefile. Staram się, aby ten pierwszy zadzwonił do drugiego. W / path / to / project / makefile mam

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

I /path/to/project/gtest-1.4.0/make/Makefilemam

all: $(TESTS)

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

Wydanie następujących dokumentów:

cd /path/to/project
make

Wyjścia:

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'

Jednak gdy wydaję te polecenia:

cd /path/to/project
make clean

Widzę:

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'

Nie rozumiem: w obu przypadkach /path/to/project/makefilemówi mi, że przechodzi do bieżącego katalogu roboczego. W pierwszym przypadku uważa, że ​​nie ma pracy do wykonania (kiedy ma), aw drugim przypadku jest w stanie znaleźć odpowiednią dyrektywę (gdy wynik mówi, że szuka w złym katalogu), ale próbuje aby uruchomić rmpolecenie /path/to/project, zamiast /path/to/makefile/gtest-1.4.0/make/.

Czy brakuje mi czegoś podstawowego do wywoływania makefile od siebie? Czy popełniłem rażący błąd koncepcyjny lub napotkałem powszechną pułapkę? Jak skutecznie zmieniać katalogi i wywoływać drugi plik makefile z pierwszego? Zrozumiałem, że wystarczy zadzwonić make -f <name>.

To jest make / gmake 3.81 w bash.

Chris Tonkinson
źródło
3
Myślę, że zamiast make -f gtest-1.4.0/make/Makefile cleanciebie lepiej powiedz $(MAKE) -C gtest-1.4.0/make clean. Dlaczego nie zdefiniowałeś fałszywych celów?
dma_k

Odpowiedzi:

113

Nie jestem zbyt jasny, o co pytasz, ale użycie -fopcji wiersza poleceń po prostu określa plik - nie mówi make do zmiany katalogów. Jeśli chcesz wykonać pracę w innym katalogu, musisz przejść cddo katalogu:

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

Zwróć uwagę, że każdy wiersz Makefiledziała w oddzielnej powłoce, więc nie ma potrzeby zmiany katalogu z powrotem.

kenorb
źródło
67
Zamiast ręcznie cdprzechodzić do katalogu gtest-1.4.0, należy skorzystać z -Copcji make.
Tader
29
A przynajmniej zdecydowanie powinieneś używać &&między poleceniem cd i make. W przeciwnym razie, jeśli płyta nie powiedzie się, nadal będzie działać make clean... w niewłaściwym katalogu !! Powinieneś także zawsze używać TYLKO $(MAKE), nigdy nie używaj go make, gdy powtarzasz. Coś w stylu: cd gtest-1.4.0 && $(MAKE) clean
MadScientist
3
@Tader: -Cnie ma w specyfikacji
Janus Troelsen
1
To pytanie o gnu-make i -Cjest w specyfikacji: gnu.org/software/make/manual/make.html#Recursion
Cas
123

Zamiast -fz makewas może chcieć użyć -C <path>opcji. To najpierw zmienia ścieżkę ' <path>', a następnie wywołuje makeją.

Przykład:

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
źródło
1
Ta droga wydaje się najlepsza. Kolejne odpowiedzi, które używają, cdpowodują, że terminal wpada w nieskończoną pętlę.
gbmhunter
$ (MAKE) -C gtest-1.4.0 / make clean nie działa dla mnie. Myślę, że powinno być $ (MAKE) -C gtest-1.4.0 clean
Arigion
1

Wydaje się jasne, że $(TESTS)jest pusty, więc plik makefile 1.4.0 działa skutecznie

all: 

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

Rzeczywiście, wszystko nie ma nic wspólnego. a clean robi dokładnie to, co mówirm -f gtest.a ...

John Knoeller
źródło
$ (TESTY) są zdefiniowane za pomocą a wildcardi a patsubst, jednak zwracają one puste z głównego pliku makefile, ponieważ katalog nie jest skutecznie zmieniany. Dobre oko.
Chris Tonkinson,