使用make将.o文件移动到一个单独的目录

Using make to move .o files to a separate directory

本文关键字:一个 单独 make 文件 移动 使用      更新时间:2023-10-16

我已经尝试过无数次将我的.o文件移动到我的obj文件夹,但无论我做什么,它只是不工作。

从提供的makefile来看,将.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)

指定创建对象的位置,使用-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. 从当前目录下的.cpp文件编译$(OBJDIR)中所有.o对象文件的规则:

    $(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目标来清理对象:

    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.cppa.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页面

回应评论,更多提示:

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 $@

$<$@自动变量$@扩展为当前构建的目标的名称,$<是第一个依赖项($^将是"所有依赖项",有更多这样的变量-参见Make手册)。

2)任何额外的深度(即头):

displayinit.o: displayinit.h
matrix3f.o: matrix3f.h
main.o: main.h window.h displayinit.h
#etc
注意:对于每个.o文件,它的依赖项应该包含:
  • 构建它的.cpp(依赖项来自一般规则),
  • .cpp文件中包含的所有.h文件(稍后需要添加)。

注意,您在原始的makefile中省略了后面的部分。总有一天这会给你带来麻烦的。

2)自动生成深度

基本上每次在任何文件中添加#include时,您都需要修改makefile以反映.cpp/.o.h文件之间的新依赖关系。这是非常麻烦的,但幸运的是,有自动化的解决方案。这里有两种C/c++方法:

  • 使用编译器为您生成依赖项(例如gcc/g++ -MM)。
  • 使用额外的工具,如makedepend

无论哪种方式,您都需要在makefile中动态地包含该依赖集。这需要一些技巧,但是一旦你有了它,你就再也不用担心依赖了。在google上搜索"c++ makefile dependencies",应该会有很多资源。


这是一个关于Make的切题文档

我的经验如下:

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

同样,对于最终的编译,您需要从obj文件夹中取出.o文件,因此修改DEPS使其具有bin/<xyz>.o。或者,您可以在最终构建之前cd obj:

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

在第一个目标中,添加将文件移动到所需目录的命令。

$(TARGET) : $(DEPS)
    $(CC) $(CFLAGS) -o $(BIN)$(TARGET) $(DEPS) $(LIBS) $(INCLUDEPATH) 
    mv *.o obj/