2017-02-13 9 views
0

Цель состоит в том, чтобы указать директорию для сборки, где .o и исполняемый файл будет находиться после сборки проектауменьшить количество дублирующих правил в Makefile

В настоящее время я написал это Makefile, который делает это, но я должен указать для каждого объектного файла его каталог вручную.

PROGNAME = parkingLotApp 

CXX   = g++ 

SRC   = main.cpp \ 
     parking_car.cpp \ 
     parking_lot.cpp \ 
     shader.cpp \ 
     shader_manager.cpp 


OBJS  = main.o \ 
     parking_car.o \ 
     parking_lot.o \ 
     shader.o \ 
     shader_manager.o \ 


BUILDIR  = build 

CXXFLAGS = -Wall -c -std=c++11 

LDFLAGS  = -Wall 

LIBS  = -lGL -lGLEW -lglfw 


$(PROGNAME): $(OBJS) 
    $(CXX) $(BUILDIR)/*.o $(LDFLAGS) $(LIBS) -o $(BUILDIR)/$(PROGNAME) 

main.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o 

parking_car.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) parking_car.cpp -o $(BUILDIR)/parking_car.o 

parking_lot.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) parking_lot.cpp -o $(BUILDIR)/parking_lot.o 

shader.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) shader.cpp -o $(BUILDIR)/shader.o 

shader_manager.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) shader_manager.cpp -o $(BUILDIR)/shader_manager.o 


.PHONY: clean 

clean: 
    rm $(BUILDIR)/*.o $(BUILDIR)/$(PROGNAME) 

Опять же, это работает, как я ожидал, но я хочу, чтобы избавиться от ручного указания каталога ($ (BUILDIR) /someobject.o) для каждого файла .o

Я попытался это вместо дублирующих линий выше

$(OBJS): 
     $(CXX) $(CXXFLAGS) $(INCDIR) $(SRC) -o $(patsubst %, $(BUILDIR)/%, $(OBJS)) 

но это дало ошибку для всех билда/*. о

говоря, что

нет такого файла или каталога

Почему он не работает?

ответ

2

Ваша попытка объединить все правила объектного файла не удалась, потому что компилятор не знал, что вы хотите скомпилировать все исходные файлы отдельно.

Мы начинаем с правилами объектных файлов:

main.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o 

... 

Тогда мы понимаем, что эти правила не строят то, что они утверждают, что строить; это правило претендует на сборку main.o, но на самом деле оно строит build/main.o. Это вызовет проблемы позже, поэтому мы фиксируем его:

$(BUILDIR)/main.o: 
    $(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o 

... 

Тогда мы замечаем, что мы забыли сказать о качестве пререквизитов источника files-- Make не знает, что он должен восстановить эту цель, если main.cpp изменилось. Таким образом, мы исправим:

$(BUILDIR)/main.o: main.cpp 
    $(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o 

... 

Затем мы используем automatic variables, чтобы уменьшить избыточность:

$(BUILDIR)/main.o: main.cpp 
    $(CXX) $(CXXFLAGS) $(INCDIR) [email protected] -o [email protected] 

... 

Затем мы замечаем, что все эти правила объектно-файл потенциал имеет точно такую ​​же команду, поэтому мы комбинируем их в pattern rule:

$(BUILDIR)/%.o: %.cpp 
    $(CXX) $(CXXFLAGS) $(INCDIR) [email protected] -o [email protected] 

(Вы можете сделать их в шаблонное правило в статический, но это достаточно в течение одного дня)

EDIT:.

Мы также должны изменить PROGNAME правило, чтобы дать ему правильное имя и предпосылки, а также использовать автоматические переменные:

$(BUILDIR)/$(PROGNAME): $(addprefix $(BUILDIR)/, $(OBJS)) 
    $(CXX) $^ $(LDFLAGS) $(LIBS) -o [email protected] 
+0

первая благодарность за помощь ... но когда я делаю $ (BUILDIR) /main.o, он не помещает выходной объект в каталог сборки (но вместо него вместо файлов .cpp), тогда как без этого, почему это так?Я должен получить все .o и исполняемый файл в одном и том же каталоге – ampawd

+0

@ampawd: Я сделал небольшую ошибку (написав 'BUILDDIR' вместо вашего' BUILDIR') и главный (забыв исправить правило 'PROGNAME'. отредактирует. Если он все еще не работает, сообщите мне, и мы пройдем его шаг за шагом. – Beta