Czy mogę skompilować wszystkie pliki .cpp w src / do .o's w obj /, a następnie połączyć się z binarnym w ./?


116

Mój katalog projektu wygląda następująco:

/project
    Makefile
    main
    /src
        main.cpp
        foo.cpp
        foo.h
        bar.cpp
        bar.h
    /obj
        main.o
        foo.o
        bar.o

Chciałbym, aby mój .cppplik makefile skompilował wszystkie pliki w /srcfolderze do .oplików w /objfolderze, a następnie połączył wszystkie .opliki w /objwyjściowym pliku binarnym w folderze najwyższego poziomu /project.

Nie mam prawie żadnego doświadczenia z Makefiles i nie jestem pewien, czego szukać, aby to osiągnąć.

Poza tym, czy jest to „dobry” sposób na zrobienie tego, czy też istnieje bardziej standardowe podejście do tego, co próbuję zrobić?



6
@aaa: Zgaduję, że OP chce rozwiązania, które nie wymaga jawnego wymieniania każdego pliku źródłowego.
— Cascabel

7
Nie chcę określać każdego pliku źródłowego, który mam i próbowałem wcześniej przeczytać ten podręcznik, ale uważam, że jest on chaotyczny i trudny do zrozumienia. Dużo lepiej uczę się z rzeczywistego przykładu, który robi to, czego oczekuję i jest dobrze wyjaśniony, a nie suchych instrukcji technicznych.
— Austin Hyde,

w porządku. Ale dokumentacja jest doskonała z dobrymi przykładami (nie jest to próba podręcznika technicznego). szukasz reguł wzorców: gnu.org/software/make/manual/make.html#Pattern-Rules
— Anycorn

11
To wygląda trochę bardziej jak to, czego chcę. Chociaż, IMHO, instrukcja tworzenia jest trochę sucha, ponieważ wydaje się być bardziej ukierunkowana na programistów, którzy są na średnim poziomie z marką, a poza tym jest bardzo obszerna i dogłębna. Być może za bardzo.
— Austin Hyde,

Odpowiedzi:


180

Makefile część pytania

Jest to dość łatwe, chyba że nie musisz generalizować, spróbuj czegoś takiego jak poniższy kod (ale zamień wcięcie spacji na tabulatory w pobliżu g ++)

SRC_DIR := .../src
OBJ_DIR := .../obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LDFLAGS := ...
CPPFLAGS := ...
CXXFLAGS := ...

main.exe: $(OBJ_FILES)
   g++ $(LDFLAGS) -o $@ $^

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
   g++ $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

Automatyczne generowanie wykresów zależności

Funkcja „obowiązkowa” dla większości systemów marki. Za pomocą GCC można to zrobić w jednym przebiegu jako efekt uboczny kompilacji, dodając -MMDflagę do CXXFLAGSi -include $(OBJ_FILES:.o=.d) na końcu treści makefile:

CXXFLAGS += -MMD
-include $(OBJ_FILES:.o=.d)

I jak już wspomnieliśmy, zawsze miej pod ręką Podręcznik tworzenia GNU , jest on bardzo pomocny.


11
Ach, pokonałeś mnie o kilka sekund. Ale proponuję OBJ_FILES = $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES)).
— Beta

1
Musiałem to zmienić, aby działało: $<powinno być $^dla reguły main.exe i myślę, że jest literówka z obj/%.o: src/%cpp.

1
@bobah Brakuje „.” in your objects rule for the cpp
— regomodo

1
specjalne zmienne są prawdopodobnie warte wyjaśnienia, ponieważ są specyficzne dla makefile i trudne do wyszukania: gnu.org/software/make/manual/html_node/Automatic-Variables.html
— Blake

2
Wiem, że to stare pytanie, ale trochę zmodyfikowałem zgodnie z moim projektem, ale nie działa. Oto mój plik makefile: pastebin.com/4CksG9Wc Otrzymuję w konsoli:make: *** No rule to make target '/main.o', needed by 'bin/main'. Pare.
— Mateus Felipe,

5

Znaki wieloznaczne również działają u mnie, ale chciałbym wspomnieć o tych, którzy używają zmiennych katalogowych. Zawsze używaj ukośnika dla drzewa folderów (nie odwrotnego ukośnika), w przeciwnym razie nie powiedzie się:

BASEDIR = ../..
SRCDIR = $(BASEDIR)/src
INSTALLDIR = $(BASEDIR)/lib

MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)

miałeś na myśli cięcie do przodu? Twój przykład pokazuje, co tradycyjnie jest uważane za ukośnik. W szczególności, te „pochylony w prawo” są uważane za „do przodu”, a te są uważane za pozostawione za „plecami”
— Evan Teran

Tak, masz rację, mam na myśli tylko „slash”. Zaktualizowałem post.
— xesf
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.