Makefile not allowing me to specify directory for object files

时间:2016-06-04 17:00:06

标签: c++ makefile

My Makefile is located in the current working directory. I am trying to put all my object files in the directory ./bin/obj and my executable in the directory ./bin. However, when I follow the method described here: How to place object files in separate subdirectory以及其他一些StackOverflow问题,我无法将*.o个文件写入所需目录;它们是在包含我的Makefile的目录中创建的。下面是我的Makefile的摘录(这些点只是更多源文件的规则,为简洁起见省略)。请注意,Makefile一直有效,直到我尝试更改输出目录。

CXX=g++
CXXFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3
LINKFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3

SRC=src
BIN=bin
OBJ=$(BIN)/obj

BAREBONES=$(SRC)/universal.h $(SRC)/parameters.h
HEADERS=$(wildcard *.h)
ALLOBJS=$(OBJ)/assignDomain.o $(OBJ)/assignDomains.o ...    
all: $(BIN)/ngl.x

$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(OBJ)/Kingdom.o $(SRC)/Sp.h $(OBJ)/Sp.o
    $(CXX) $(CXXFLAGS) -c $(SRC)/assignDomain.cpp

$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o $(SRC)/assignDomains.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(SRC)/Sp.h $(OBJ)/Sp.o
    $(CXX) $(CXXFLAGS) -c $(SRC)/assignDomains.cpp

#...more rules...

$(BIN)/ngl.x: $(BAREBONES) $(ALLOBJS) $(wildcard *.h)
    $(CXX) $(ALLOBJS) $(LINKFLAGS) -o $(BIN)/ngl.x

#...more rules...

clean:
    rm -f $(OBJ)/*.o $(OBJ)/*.gch $(BIN)/ngl.x

.phony: all clean

输出如下:

/usr/local/include/eigen3 -c ./src/assignDomain.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/assignDomains.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/evict.cpp
g++ ./bin/obj/assignDomain.o ./bin/obj/assignDomains.o /usr/local/include/eigen3 -o ./bin/ngl.x
g++: error: ./bin/obj/assignDomain.o: No such file or directory
g++: error: ./bin/obj/assignDomains.o: No such file or directory

#...same error, for the other rules...

g++: fatal error: no input files
compilation terminated.
Makefile:94: recipe for target 'bin/ngl.x' failed
make: *** [bin/ngl.x] Error 1

2 个答案:

答案 0 :(得分:3)

请注意:make中没有内置规则,它知道如何在一个目录中编译源文件并将目标文件放入另一个目录中。如果你想这样做,你必须编写自己的规则。当您编写自己的规则时,您必须提供-o选项:编译器无法知道您指定的 makefile 一个不同的输出目录,除非你用-o标志告诉它。编译器没有解析你的makefile!

您可以编写如下的模式规则:

$(OBJ)/%.o : $(SRC)/%.c
        $(CXX) $(CXXFLAGS) -c $< -o $@

然后,您不需要任何明确的规则,但您确实需要定义先决条件。关于makefile的其他说明:

  • 让.o文件依赖于其他.o文件永远不正确。
  • 让可执行文件依赖于头文件永远不正确。

对象文件列出源文件和头文件作为先决条件。可执行文件列出目标文件(和库,如果有的话)作为先决条件。你应该写下这样的先决条件:

$(OBJ)/assignDomain.o: $(SRC)/assignDomain.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
$(OBJ)/assignDomains.o: $(SRC)/assignDomains.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
  ...other prerequisites...
$(BIN)/ngl.x: $(ALLOBJS)
        $(CXX) $^ $(LINKFLAGS) -o $@

答案 1 :(得分:1)

您的显式编译规则是禁用了解如何编译子目录中的文件,因此您可以获得您的规则所说的内容,而不是其他任何内容。您没有指定-o选项,因此您没有告诉g++放置输出文件的位置;因此它遵循其内置默认值,只需创建一个文件./a.out(!)。

最直接的解决方案是不要覆盖内置规则。 Make已经知道如何使用相同的基本名称从.o文件创建.cpp文件;您只需要在Makefile

中声明依赖项和标记

为了易读,我已将共享依赖项重构为单独的变量。

SHAREDDEPS := $(SRC)/Domain.h $(OBJ)/Domain.o \
    $(SRC)/Kingdom.h \
    $(SRC)/Sp.h $(OBJ)/Sp.o

$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp \
        $(SHAREDDEPS) $(OBJ)/Kingdom.o
    # No $(CXX) anything here!

$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o \
        $(SRC)/assignDomains.cpp $(SHAREDDEPS)
    # Here either!

我将依赖项包装在多行中以便于读取(注意第一行的最后反斜杠),但是你应该注意到它们只是一条逻辑行,指定依赖项,而不是如何实际编译任何东西。

不清楚依赖的*.o文件应该如何计算出来;根据你要删除的明确规则,我的推测是这些实际上并没有在编译中使用,因此实际上并不是真正的依赖。