【问题标题】:Using make to move .o files to a separate directory使用 make 将 .o 文件移动到单独的目录
【发布时间】:2012-01-29 02:03:23
【问题描述】:

我尝试了无数次尝试将我的.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)

【问题讨论】:

  • 在第一个目标中添加mv *.o obj/ 作为最后一行不起作用吗?
  • 是的!谢谢你。将其发布为答案,我会接受你。
  • 为什么不从一开始就将文件构建到obj/ 目录中?
  • 另外,你的 makefile 有 90% 是冗余的。您是否对如何使其更易于管理感兴趣?
  • @Kos 是的,当然。我对makefile很陌生。谢谢。

标签: c++ object compilation makefile


【解决方案1】:

以下对我有用:

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)

【讨论】:

    【解决方案2】:

    要指定创建对象的位置,请使用-o

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

    你可以这样做:

    1. 指定目标文件所在的目录

      OBJDIR    =   objdir
      
    2. 通过将.cpp替换为.o,从所有.cpp文件列表中创建需要编译的目标文件列表,并为其添加前缀$(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 page

    【讨论】:

    • 不错!为了完整起见,我会提醒上面也需要依赖项。如果您不引入它们,则在每次重建后执行make clean &amp;&amp; make,这样您就不会遇到静默链接问题。
    • 依赖关系是另一篇文章的材料......我也有一个解决方案。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      针对评论,还有一些提示:

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

      $&lt;$@自动变量$@ 扩展为当前构建目标的名称,$&lt; 是第一个依赖项($^ 将是“所有依赖项",还有更多这样的变量 - 请参阅 Make manual)。

      2) 任何额外的部门(即标头):

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

      注意:对于每个.o 文件,其依赖项应包含:

      • 构建它的.cpp(依赖来自一般规则),
      • .h 文件中包含的所有 .cpp 文件(您需要稍后添加)。

      请注意,您在原始 makefile 中省略了后一部分。这有一天会给你带来一些问题。

      2) 自动生成deps

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

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

      无论哪种方式,您都需要在 makefile 中动态包含该组依赖项。这需要一些技巧,但是一旦拥有它,您就不必担心依赖关系。有一个“C++ makefile依赖”的google,应该有很多资源。


      Here's 一个关于 Make 的中肯文档。

      【讨论】:

      • +1。我真的很感激这个建议。这会很有帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 2013-04-14
      • 1970-01-01
      • 2013-02-03
      • 2015-09-25
      相关资源
      最近更新 更多