3
votes

Currently, whenever I do make my makefile tells me

make: `some/obj/file.o' is up to date.

regardless of whether I've edited any of the files involved in generating that object file. How do I make it detect changes? Here is a simple makefile that reproduces the problem:

SHELL := /bin/bash
src := src
sources := $(shell find $(srcDir) -name "*.cpp")                                
objects := $(sources:%.cpp=%.o)                                                 

-include $(sources:%.cpp=%.d)                                                   

all: prog                                                                       

prog:   $(objects)                                                              
    g++ $(objects) -o /a.out                                                    

%.o: %.cpp                                                                      
    $(CXX) $(CXXFLAGS) -MMD -MP -c $< -I $(srcDir) -o $@                        

clean:                                                                          
    find $(srcDir) -type f -iname "*.o" -delete                                 
    find $(srcDir) -type f -iname "*.d" -delete 

currently I have to run make clean everytime to get it to recompile, which obviously isn't ideal!

EDIT: Here is my attempt based on Chnossos's answer:

EXE := a.out                                                                    
SRCDIR := src                                                                   
SRC := $(shell find $(srcDir) -name "*.cpp")                                    
DIR := .obj                                                                     
OBJ := $(SRC:%.cpp=$(DIR)/%.o)                                                  
DEP := $(OBJ:.o=.d)                                                             

CXXFLAGS += -std=c++11                                                          
CXXFLAGS += -I /home/arman/lib/eigen-eigen-6b38706d90a9                  
CXXFLAGS += -I /home/arman/lib/boost_1_55_0                              
CXXFLAGS += -I /home/arman/lib/lodepng/                                  
CXXFLAGS += -L /home/arman/lib/boost_1_55_0/stage/lib                    
CPPFLAGS += -MMD -MP                                                            

.PHONY: all clean                                                               

-include $(DEP)                                                                 

all: $(EXE)                                                                     

$(EXE):   $(OBJ)                                                                
        $(CXX) $(OBJ) -o $@                                                     

$(DIR)/%.o: %.cpp                                                               
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< -I $(SRCDIR)                 

clean:                                                                          
        $(RM) -f $(DIR)                                                         

I am now getting the following error:

src/core/file1.cpp:839:1: fatal error: opening dependency file .obj/./src/core/file1.d: No such file or directory

Note that I have the following directory structure:

/prog/makefile -> The makefile /prog/dir1/ -> some cpp/hpp files /prog/dir2/ -> more cpp/hpp files /prog/ ->there are some cpp/hpp files here too

I have many folders (more than just dir1 and dir2) so I'd like to not have to specify them each time.

2

2 Answers

3
votes
SRC         := $(wildcard *.cpp)
OBJ         := $(SRC:.cpp=.o)
DEP         := $(OBJ:.o=.d)

CPPFLAGS    += -MMD -MP -I.

.PHONY: all clean

all: prog

prog:   $(OBJ)
    $(CXX) $(LDFLAGS) $^ $(LDLIBS)

-include $(DEP)

clean:
    $(RM) $(OBJ) $(DEP)

You can also with a little efforts compile your .o and .d files into a hidden folder like this :

EXE         := a.out
SRC         := $(wildcard *.cpp)
DIR         := .obj
OBJ         := $(SRC:%.cpp=$(DIR)/%.o)
DEP         := $(OBJ:.o=.d)

CPPFLAGS    += -MMD -MP -I.

.PHONY: all clean

all: $(EXE)

$(EXE):   $(OBJ)
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(DIR)/%.o: %.cpp | $(DIR)
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<

$(DIR):
    @mkdir $@

-include $(DEP)

clean:
    $(RM) -r $(DIR)

EDIT: Here is my attempt for your edit :

Some quick note, the $(LDLIBS) is here for your -l flags, whereas $(LDFLAGS) is meant for -L flags.

SRCDIR := src
OBJDIR := .obj

EXE := a.out
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)

LDFLAGS += -L /home/arman/lib/boost_1_55_0/stage/lib
CXXFLAGS += -std=c++11
CPPFLAGS += -I $(SRCDIR)
CPPFLAGS += -I /home/arman/lib/eigen-eigen-6b38706d90a9
CPPFLAGS += -I /home/arman/lib/boost_1_55_0
CPPFLAGS += -I /home/arman/lib/lodepng/
CPPFLAGS += -MMD -MP

.PHONY: all clean

all: $(EXE)

$(EXE): $(OBJ)
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@    

.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(@D)/
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<

%/:
    mkdir $@

-include $(DEP)

clean:
    $(RM) -r $(OBJDIR)

Tell me if something is missing.

1
votes

-M family of gcc options (-MM, -MMT) generate the makefile fragments you need. A standard technique is

DEPS := $(SOURCES:.c=.d)

.c.d:
    $(CC) -o $< -MM $(CFLAGS)

-include $(DEPS)