1

I don't know why the Make recompiles all the files every time including the unchanged files, it takes a long time. I searched the Stack Overflow and found some solutions, but I still couldn't resolve my problem.

How should I change this makefile so that it won't compile all the files including the unchanged files?

This is my make file:

CXX = g++
CXXFLAGS = -g -Wall -O2 -std=c++11
BIN = bin
SRC = src
OBJ = obj
COMPILER = $(BIN)/compiler

LEX_CPP = $(SRC)/lex.cpp
UTIL_CPP = $(SRC)/util.cpp
TOKEN_CPP = $(SRC)/token.cpp
MAIN_CPP = $(SRC)/main.cpp
TEST_CPP = $(SRC)/test.cpp
PARSER_CPP = $(SRC)/parser.cpp
COMPILER_CPP = $(SRC)/compiler.cpp

COMPILER_OBJS = parser.o compiler.o test.o token.o lex.o util.o main.o 

dir_guard=@mkdir -p $(OBJ)

compiler: $(COMPILER_OBJS)
    $(CXX) $(CXXFLAGS) -o $(COMPILER) $(OBJ)/lex.o $(OBJ)/compiler.o $(OBJ)/parser.o $(OBJ)/test.o $(OBJ)/token.o $(OBJ)/util.o $(OBJ)/main.o 

main.o:
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/main.o -c $(MAIN_CPP)
lex.o: 
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/lex.o -c $(LEX_CPP)
util.o: 
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/util.o -c $(UTIL_CPP)
token.o: 
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/token.o -c $(TOKEN_CPP)
test.o:
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/test.o -c $(TEST_CPP)
compiler.o:
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/compiler.o -c $(COMPILER_CPP)
parser.o:
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/parser.o -c $(PARSER_CPP)

clean:
    rm $(OBJ)/*.o

I want to put all the .o files to the obj folder, and put the exe file to the bin folder.

My OS is Ubuntu 15.04 and using GNU Make 4.0.

Any help is appreciated, thank you in advance!

Jiahao Cai
  • 1,222
  • 1
  • 11
  • 25
  • 2
    You've not specified any dependencies, therefore MAKE does not know what files to look at to see if anything changed. See http://kirste.userpage.fu-berlin.de/chemnet/use/info/make/make_4.html – djgandy May 02 '17 at 15:33
  • @djgandy: That's an answer, not a comment. – MSalters May 02 '17 at 15:34
  • It's not an answer, it's a comment... because it's not the reason why things are being rebuilt constantly, which is the question being asked. If there are no prerequisites then the targets would NOT be rebuilt at all if they existed, even if the source changed. – MadScientist May 02 '17 at 17:53

3 Answers3

6

Just to be very clear: your makefile is broken in various ways which djgandy and Norman Gray have correctly diagnosed. But the specific answer to your specific question of why files are being constantly rebuilt is this:

token.o: 
    $(dir_guard)
    $(CXX) $(CXXFLAGS) -o $(OBJ)/token.o -c $(TOKEN_CPP)

Leaving aside all the other issues, here you tell make: "if you want to build a file token.o, then you can do it with this recipe". But the recipe doesn't build token.o, it builds $(OBJ)/token.o. This is wrong, because after the recipe is run the target (token.o) still doesn't exist. So the next time you run make, it says "oh, I need to build token.o... gee, it doesn't exist so I guess I have to build it... oh, here's a rule that can build it...` which still doesn't actually build it.

Your makefile is violating the second rule of Makefiles: Every non-.PHONY rule must update a file with the exact name of its target.

Your rules should always build $@ as that always has the path to the target that make believes that you should be building.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thank you for your great answer! – Jiahao Cai May 03 '17 at 00:52
  • +1 This adds what was only implicit in my answer, that your original rule wasn't updating the object it ‘promised’ to. Also, the fact that your rule `token.o:` didn't mention a dependency means that as long as `token.o` existed (by whatever occult means) it would never be considered out of date (meaning ‘older than its dependency’), and so would never be _re_-built. – Norman Gray May 03 '17 at 14:18
4

You're repeating yourself a lot in that Makefile – that's what make is supposed to avoid.

Consider the following

MODULES=parser compiler test token lex util main
COMPILER_OBJS=$(MODULES:%=$(OBJ)/%.o)

$(OBJ)/%.o: %.c
    @test -d $(OBJ) || mkdir $(OBJ)
    $(CXX) $(CXXFLAGS) -c -o $@ $<

compiler: $(COMPILER_OBJS)
    $(CXX) $(CXXFLAGS) -o $(COMPILER) $(COMPILER_OBJS)

That is, you're using a ‘pattern rule’ to tell Make how to make an object file from a .c file and, slightly non-standardly but reasonably, having that file placed in another directory.

Using the pattern-based variable reference to set COMPILER_OBJS means that you only have to specify the list of modules in one place.

The end result should be (I haven't tested this) that make compiler (or indeed just make, as long as compiler remains the first target in the file) will build the compiler binary, rebuilding whichever .o files are out of date at that point.

There's a constant tendency to make Makefiles over-complicated, but using pattern rules and pattern-based variable references are useful core functionality, so you should make sure you understand how those lines work (though note that both of these features are specific to GNU Make).

Norman Gray
  • 11,978
  • 2
  • 33
  • 56
1

You've not specified any dependencies for each object. Make doesn't have any way of knowing whether the headers that source files depend on have changed or any other dependencies of a source file. For example if some 'definition' file changes, you might need to regenerate headers, which in turn requires re-compilation of dependent source files.

In order to have Make conditionally compile based on dependents you must tell Make what the dependencies are. Be warned though, if you get this wrong you can end up in a nasty situation where you make changes that are not picked up because your dependency list is incorrect, or only partially picked up by some files.

I'd suggest looking at these topics on auto generation of dependencies. Manually managing them is OK for very tiny projects but scales poorly with many files. In addition, maintaining complex Makefiles is a task very few enjoy.

Makefile (Auto-Dependency Generation)

Makefile, header dependencies

For MAKE reference see: http://kirste.userpage.fu-berlin.de/chemnet/use/info/make/make_4.html

Community
  • 1
  • 1
djgandy
  • 1,125
  • 6
  • 15
  • 1
    There's a second problem: The rule for e.g. `main.o` actually creates `$(OBJ)/main.o`, so it is never considered up to date. – melpomene May 02 '17 at 16:07
  • djgandy you're right that this is a problem, but it's not the reason that all the files are being rebuilt which is the question being asked. melpomente is the right answer. – MadScientist May 02 '17 at 17:54