0

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 and in several other StackOverflow questions, I'm unable to get my *.o files to be written to the desired directory; they're created in the directory containing my Makefile. Below is an excerpt from my Makefile (the dots are just rules for many more source files, omitted for brevity). Please note that the Makefile worked until I tried to change the output directory.

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

The output is as follows:

/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
Community
  • 1
  • 1
GnomeSort
  • 275
  • 3
  • 12

2 Answers2

3

Just to be clear: there is no built-in rule in make which knows how to compile a source file in one directory and put the object file into a different directory. If you want to do that, you have to write your own rule. When you write your own rule you have to provide the -o option: there's no way for the compiler to know that in your makefile you specified a different output directory, unless you tell it with the -o flag. The compiler doesn't parse your makefile!

You can write a pattern rule like this:

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

Then you don't need any explicit rules, although you do need to define the prerequisites. Other notes about your makefile:

  • It's never correct to have .o files depend on other .o files.
  • It's never correct to have executable files depend on header files.

Object files list source and header files as prerequisites. Executable files list object files (and libraries, if you have any) as prerequisites. You should write your prerequisites like this:

$(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 $@
MadScientist
  • 92,819
  • 9
  • 109
  • 136
1

Your explicit compilation rule is disabling Make's knowledge of how to compile files in subdirectories, and so you get exactly what your rule says, and nothing else. You don't specify an -o option, so you are not telling g++ where to put the output file; so it follows its built-in default, and simply creates a file ./a.out (!).

The most straightforward solution is to not override the built-in rules. Make already knows how to create an .o file from a .cpp file with the same base name; you only need to declare the dependencies and flags in your Makefile.

For legibility, I have refactored the shared dependencies into a separate variable.

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!

I wrapped the dependencies across multiple lines for legibility (notice the final backslash on the first line) but you should notice that they are a single logical line, and only specify dependencies, not how to actually compile anything.

It's not clear how the depended *.o files are supposed to figure into this; my speculation, based on your explicit rules which I am removing, is that these are not actually used in compilation, and so are not actually true dependencies.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • That was a last-ditch effort to get it to work, but I get the same error whether I put it in or not. I've removed it for clarity now. Thanks for pointing that out. – GnomeSort Jun 04 '16 at 17:09
  • Huh? Now you have a rule with no `-o` option. Without that, `g++` will not create the file you are asking for. (But the simplest solution is to not override the built-in rules, and just add the dependencies and flags you need.) – tripleee Jun 04 '16 at 17:13
  • Pardon my ignorance, but I thought I do not have to write -o *** because the existence of the rule itself says what *.o to create. The SO question that I linked does not use -o ... – GnomeSort Jun 04 '16 at 17:16
  • If you override Make's rules, you have to put in the things which the compiler needs. But the simple solution is to not override Make's built-in rules. Updated the answer. – tripleee Jun 04 '16 at 17:19
  • Thanks. Your code does not include a `-c` though. Why is this? How does `make` know which `.cpp` file to compile then? – GnomeSort Jun 04 '16 at 17:21
  • My code does not contain any compilation instructions at all. Make has them built into it already. If you truly need to override them, maybe you need to be more explicit in your question about why this is required. The rules you have look less featureful than the built-in ones, not more. – tripleee Jun 04 '16 at 17:22
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/113818/discussion-between-newdogoldtricks-and-tripleee). – GnomeSort Jun 04 '16 at 17:29