4

I have a makefile for my program but I got everything recompiled every time I run it, even if I modify nothing. Every time I run make it recompiles simHwIntf.cpp showHelp.cpp and sendFromFile.cpp

This is my make file:

IDIR    = inc
LDIR    = -L/usr/lib/x86_64-linux-gnu/
SDIR    = src
ODIR    = obj
BINDIR  = bin
LDLIBS  = -luhd
OBJ     = $(patsubst %,$(ODIR)/%,$(O_FILES))

CC      = g++
CFLAGS  = -Wall -std=c++11 -I $(IDIR) #-Werror

BINARIES= main

C_FILES = simHwIntf.cpp showHelp.cpp  sendFromFile.cpp
H_FILES = simHwIntf.h
O_FILES = $(C_FILES:.cpp=.o)

all: $(BINARIES)
@echo "Make file executed"

$(BINARIES): $(O_FILES)
$(CC) $(CFLAGS) -o $(BINDIR)/$@ $(OBJ) $(LDIR) $(LDLIBS) 

fileCreator: fileCreator.o 
$(CC) $(CFLAGS) -o $(BINDIR)/$@ $(ODIR)/fileCreator.o

fileHandler: fileHandler.o
$(CC) $(CFLAGS) -o $(BINDIR)/$@ $(ODIR)/fileHandler.o

backYard: backYard.o
$(CC) $(CFLAGS) -o $(BINDIR)/$@ $(ODIR)/backYard.o

%.o: $(SDIR)/%.cpp $(IDIR)/$(H_FILES)
$(CC) $(CFLAGS) -c -o $(ODIR)/$@ $<

clean: 
-rm -rf $(ODIR)/*.o *~

distclean: clean
-rm -rf $(BINDIR)/*

Each time the output in the shell is:

g++ -Wall -std=c++11 -I inc  -c -o obj/simHwIntf.o src/simHwIntf.cpp
g++ -Wall -std=c++11 -I inc  -c -o obj/showHelp.o src/showHelp.cpp
g++ -Wall -std=c++11 -I inc  -c -o obj/sendFromFile.o src/sendFromFile.cpp
g++ -Wall -std=c++11 -I inc  -o bin/main obj/simHwIntf.o obj/showHelp.o obj/sendFromFile.o -L/usr/lib/x86_64-linux-gnu/ -luhd 
Make file executed

I've already search and read this: (How do I make Makefile to recompile only changed files?) but didn't help much.

Anybody that could give me a hand with this ?

I have a doubt with the directories, maybe one or several directories are re-created each time I run make and this causes everything inside to look like new to the compiler.

Thanks

Community
  • 1
  • 1
PabloMon
  • 41
  • 3
  • I know just a little about Makefiles, but I would investigate whether `make` is capable of correctly matching the rule `%.o` with the output `$(ODIR)/$@` (because of the directory mismatch between them). – Angew is no longer proud of SO Jun 03 '16 at 08:12
  • Every single one of your rules breaks one of the most important [rules of makefiles](http://make.mad-scientist.net/papers/rules-of-makefiles/): the output file must match the target. Instead your rule for `fileCreator` for example doesn't create `fileCreator`, it creates `bin/fileCreator`, so it's no surprise that make recreates the files each time, it checks for `fileCreator` and doesn't find anything. The same applies to your other rules. – user657267 Jun 03 '16 at 12:23

3 Answers3

6

You can see what triggered the build by echoing the dependencies that changed. Add this to your %.o target :

@echo [triggered by changes in $?]

You should also use the VPATH special variable instead of specifying the sources path in your %.o target. See GNU make VPATH documentation

Tim
  • 1,853
  • 2
  • 24
  • 36
  • Yup, well I got this: `g++ -Wall -std=c++11 -I inc -c -o obj/simHwIntf.o src/simHwIntf.cpp [triggered by changes in src/simHwIntf.cpp inc/simHwIntf.h] g++ -Wall -std=c++11 -I inc -c -o obj/showHelp.o src/showHelp.cpp [triggered by changes in src/showHelp.cpp inc/simHwIntf.h] g++ -Wall -std=c++11 -I inc -c -o obj/sendFromFile.o src/sendFromFile.cpp [triggered by changes in src/sendFromFile.cpp inc/simHwIntf.h] g++ -Wall -std=c++11 -I inc -o bin/main obj/simHwIntf.o obj/showHelp.o obj/sendFromFile.o Make file execute` But it's not true, well at least I didn't change this files. – PabloMon Jun 03 '16 at 12:23
  • Did you try to use VPATH and to only have %.cpp as a prerequisite for your target, instead of $(SDIR)/%.cpp ? I wouldn't bet it's the answer but I think it's worth a try. I've already read here and there about make taking the folder last modification time instead of the file last modification time itself. – Tim Jun 03 '16 at 12:31
  • Well yes, the VPATH fixed it but it let me a bad taste because it just does a search in every directory instead of correctly search in the good directory. It's like a joker. – PabloMon Jun 03 '16 at 12:55
  • I understand that very well, even more since I have some projects with sources in multiple directories containing some files with the same name. Anyway this is commonly considered as a bad thing so I wouldn't be too mad about make in this case. – Tim Jun 03 '16 at 13:01
3

Please try replacing

%.o: $(SDIR)/%.cpp $(IDIR)/$(H_FILES)
     $(CC) $(CFLAGS) -c -o $(ODIR)/$@ $<

with

$(ODIR)/%.o: $(SDIR)/%.cpp $(IDIR)/$(H_FILES)
     $(CC) $(CFLAGS) -c -o $(ODIR)/$@ $<
GMichael
  • 2,726
  • 1
  • 20
  • 30
  • I did it, nothing changed. Anyway the makefile was putting the obj files in the right directories. – PabloMon Jun 03 '16 at 12:18
  • Sorry, now I did it (forgot to save), but it doesn't work. Actually if you put $(ODIR) make doesn't find the rule for the obj files. – PabloMon Jun 03 '16 at 12:28
  • Can you show the results of `ls -l simHwIntf.cpp showHelp.cpp sendFromFile.cpp simHwIntf.h` and `date`? – GMichael Jun 03 '16 at 12:30
  • Please change also the command to `$(CC) $(CFLAGS) -c -o $@ $<` – GMichael Jun 03 '16 at 12:37
  • `Jun 2 10:06 sendFromFile.cpp Jun 3 08:54 showHelp.cpp Jun 3 11:26 simHwIntf.cpp` My current time is 13:37 and ti is still compiling every file, so it must be the directories – PabloMon Jun 03 '16 at 12:37
0

Directories matter when you define targets.

If a define a rule

myexec: objdir/myexec.o
    $(CC) $(CFLAGS) -o bindir/myexec objdir/myexec.o $(LDFLAGS)

Make believes that that this would create the file myexec in the working directory. When you rerun make the target myexec wasn't found, so it will be created again. Add the paths in the targets and it should work.

Try replacing

BINARIES= main

with

BINARIES= $(BINDIR)/main

and the rule

$(CC) $(CFLAGS) -o $(BINDIR)/$@ $(OBJ) $(LDIR) $(LDLIBS)

with

$(CC) $(CFLAGS) -o $@ $^ $(LDIR) $(LDLIBS)

And change the other rules similarly.

Note, in general it is a bad idea to use $@ in combination with a path when creating the target in some rule (as in $(BINDIR)/$@), because this will never create the actual target file. A bare $@ should be sufficient.

  • Thanks for the answer, but it doesn't fix the problem. The only way I found is using the VPATH variable as TimF said. – PabloMon Jun 06 '16 at 14:19