Использование make для перемещения .o файлов в отдельный каталог - PullRequest
9 голосов
/ 28 декабря 2011

Я пробовал многочисленные попытки переместить мои .o файлы в мою папку obj, но, что бы я ни делал, это просто не работает.

Судя по предоставленному make-файлу, как лучше всего переместить .o файлы в указанную папку?

BIN = bin/
OBJ = obj/
TARGET = opengl_03
DEPS = main.o  displayinit.o initializer.o algorithms.o matrix3f.o window.o vertex3.o
CC = g++
CFLAGS = -g 
LIBS = -lglut -lGLEW -lGL 
INCLUDEPATH = -L/usr/include/ -L/usr/lib/ -L/usr/lib/x86_64-linux-gnu/

$(TARGET) : $(DEPS)
    $(CC) $(CFLAGS) -o $(BIN)$(TARGET) $(DEPS) $(LIBS) $(INCLUDEPATH) 

displayinit.o : displayinit.cpp displayinit.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c displayinit.cpp && mv displayinit.o $(OBJ)displayinit.o
initializer.o : initializer.cpp initializer.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c initializer.cpp $(OBJ)
algorithms.o : algorithms.cpp algorithms.h
    $(CC) -c algorithms.cpp $(OBJ)
matrix3f.o : matrix3f.cpp matrix3f.h
    $(CC) $(LIBS) $(INCLUDEPATH)  -c matrix3f.cpp $(OBJ)
vertex3.o : vertex3.cpp vertex3.h
    $(CC) $(LIBS) $(INCLUDEPATH)  -c vertex3.cpp $(OBJ)
window.o : window.cpp window.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c window.cpp $(OBJ)
main.o : main.cpp
    $(CC) $(LIBS) $(INCLUDEPATH) -c main.cpp $(OBJ)

Ответы [ 4 ]

18 голосов
/ 28 декабря 2011

Чтобы указать, где создается объект, используйте -o

window.o : window.cpp window.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c window.cpp -o $(OBJ)/$@

Вот что вы можете сделать:

  1. укажите каталог, куда вы хотите поместить объектные файлы

    OBJDIR    =   objdir
    
  2. Создайте список объектных файлов, которые необходимо скомпилировать, из списка всех файлов .cpp, заменив.cpp с .o и добавьте к нему префикс $(OBJDIR)/:

    OBJ = $(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp)))
    

    Таким образом, ваш $ (OBJ) будет выглядеть так: objdir/window.o objdir/main.o и т. Д.

  3. Добавьте цель, чтобы создать каталог, если он не существует:

    $(OBJDIR):
        mkdir $(OBJDIR)
    
  4. Создайте цель каталога, прежде чем вы установите свою основную цель:

    all: $(OBJDIR) myapp
    
  5. Правило для компиляции всех объектных файлов .o в $(OBJDIR) из .cpp файлов в текущем каталоге:

    $(OBJDIR)/%.o: %.cpp
        $(GCC) $(CPPFLAGS) -c $< -o $@
    

    Это приведет к чему-то вроде:

    g++ -c main.cpp -o objdir/main.o
    
  6. Ваша основная цель неизменна:

    $(TARGET): $(OBJ)
        $(GCC) $(LDFLAGS) -o $@ $^ 
    

    Это будет выглядеть так:

    g++  -o myapp objdir/window.o objdir/main.o 
    
  7. Для полнотыдобавить clean цель для очистки объектаcts:

    clean:
        @rm -f $(TARGET) $(wildcard *.o)
        @rm -rf $(OBJDIR) 
    
  8. И определить .PHONY цели, например, они будут выполнены, даже если существуют каталоги или файлы с одинаковыми именами:

    .PHONY: all clean
    

Так это должно выглядеть следующим образом:

OBJDIR    =   objdir
OBJ       =   $(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp)))
TARGET    =   my app

.PHONY: all clean

all: $(OBJDIR) $(TARGET)

$(OBJDIR):
    mkdir $(OBJDIR)

$(OBJDIR)/%.o: %.cpp
    $(GCC) $(CPPFLAGS) -c $< -o $@

$(TARGET): $(OBJ)
    $(GCC) $(LDFLAGS) -o $@ $^ 

clean:
    @rm -f $(TARGET) $(wildcard *.o)
    @rm -rf $(OBJDIR) 

И если у вас есть такие файлы, как main.cpp и a.cpp, вот что make сделает:

> ls
Makefile a.cpp    main.cpp

> make
mkdir objdir
g++ -I. -c a.cpp -o objdir/a.o
g++ -I. -c main.cpp -o objdir/main.o
g++ -o myapp objdir/a.o objdir/main.o 

> ls
Makefile a.cpp    main.cpp objdir   myapp

> make clean
> ls
Makefile a.cpp    main.cpp

И если вы хотите узнать больше о любом из вышеперечисленных, взгляните на GNU make doc page

4 голосов
/ 28 декабря 2011

В ответ на комментарий, еще несколько советов:

1) Убрать некоторую избыточность

Эта часть очень повторяется:

displayinit.o : displayinit.cpp displayinit.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c displayinit.cpp && mv displayinit.o $(OBJ)displayinit.o
initializer.o : initializer.cpp initializer.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c initializer.cpp $(OBJ)
algorithms.o : algorithms.cpp algorithms.h
    $(CC) -c algorithms.cpp $(OBJ)
# ...

Вы можете заменить его на две части:

1) более общее правило, что-то вроде:

%.o: %.cpp
    $(CC) -c $(LIBS) $(INCLUDEPATH) $< -o $@

$< и $@ являются автоматическими переменными , $@ расширяется до имени созданной в данный момент цели, а $< является первой зависимостью ($^ будет "всеми зависимостями") Есть и другие варианты - см. Руководство по эксплуатации ).

2) любые дополнительные команды (то есть заголовки):

displayinit.o: displayinit.h
matrix3f.o: matrix3f.h
main.o: main.h window.h displayinit.h

#etc

Примечание. Для каждого файла .o его зависимости должны содержать:

  • .cpp, из которого она построена (зависимость от общего правила),
  • все .h файлы, включенные из этих .cpp файлов (которые необходимо добавить позже).

Обратите внимание, что вы пропустили последнюю часть в вашем исходном make-файле. Это может вызвать у вас некоторые проблемы.

2) Генерировать deps автоматически

Как правило, каждый раз, когда вы добавляете #include в любой из ваших файлов, вам нужно будет изменить ваш make-файл, чтобы отразить новую зависимость между файлами .cpp / .o и .h. Это очень хлопотно, но, к счастью, для этого есть автоматизированные решения. Здесь есть два подхода к C / C ++:

  • Используйте свой компилятор для генерации зависимостей для вас (например, gcc / g++ -MM).
  • Используйте дополнительный инструмент, такой как makedepend.

В любом случае, вам нужно динамически включать этот набор зависимостей в make-файл. Это требует некоторой хитрости, но если она у вас есть, вам никогда не придется беспокоиться о зависимостях. Если у вас есть Google для «зависимостей make-файлов C ++», ресурсов должно быть много.


Вот конкретный документ о Make.

0 голосов
/ 28 декабря 2011

В первой цели добавьте команду для перемещения файлов в нужную папку.

$(TARGET) : $(DEPS)
    $(CC) $(CFLAGS) -o $(BIN)$(TARGET) $(DEPS) $(LIBS) $(INCLUDEPATH) 
    mv *.o obj/
0 голосов
/ 28 декабря 2011

Следующее сработало у меня:

g++ test.cpp -c -o obj/test.o

Так, например, в вашем случае вы бы сделали следующую модификацию:

displayinit.o : displayinit.cpp displayinit.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c displayinit.cpp -o displayinit.o $(OBJ)displayinit.o

Кроме того, для окончательной компиляции вам нужно выбрать файлы .o из папки obj, поэтому измените DEPS, чтобы получить bin/<xyz>.o. В качестве альтернативы вы можете cd obj до финальной сборки:

$(TARGET) : $(DEPS)
    cd $(OBJ)
    $(CC) $(CFLAGS) -o ../$(BIN)$(TARGET) $(DEPS) $(LIBS) $(INCLUDEPATH)
...