3

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.

quant
  • 21,507
  • 32
  • 115
  • 211

2 Answers2

4
EXE := a.out
SRC := $(wildcard *.cpp)
OBJ := $(SRC:.cpp=.o)
DEP := $(OBJ:.o=.d)

CPPFLAGS := -MMD -MP -I.

.PHONY: all clean

all: $(EXE)

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

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

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

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

-include $(DEP)

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)

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

.PHONY: all clean

all: $(EXE)

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

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

%/:
    mkdir -p $@

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

-include $(DEP)

Tell me if something is missing.

Chnossos
  • 9,971
  • 4
  • 28
  • 40
  • Thanks Chnossos, I've tried adapting that but have had some trouble. Please take a look at the example I've posted at the end of the OP, with an explanation of my file structure. What do I need to change to make it work? – quant May 04 '14 at 07:55
1

-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)
user58697
  • 7,808
  • 1
  • 14
  • 28
  • That looks like a good answer, but can you rephrase it for a make-noob like myself? How would I make this work with the existing makefile i've cobbled together? – quant May 04 '14 at 01:41
  • The key thing that he's missing is the rule to regenerate the .d files from the .cpp files -- he already has the rest. Also please change .c to .cpp and $(CC) to $(CXX). – j_random_hacker May 04 '14 at 01:41