RiaD
RiaD

Reputation: 47658

Compile files only if needing

I have couple of cpp and hpp files in directory ./src. I compile all cpp files in one binary file, say ./bin/run. I want to re-compile only if I need i.e it or one of its header was changed.

I, probably, can create Makefile where file will be recompiled if and only if it was changed, but it's quite uncomfortable because big part of my code is in the headers. (It's not going to be changed, because the product is header itself and cpp files are tests).

I want to store temporary .o files in ./build

I know about g++ -MM function but I'm not sure how to use it.

I'll glad to see solutions that use not necessary make but any other system possible if they are easy enough.

UPD I'll try to clarify, what's the problem is:

New cpp's maybe created, includes may be added or gone, etc. I don't want to edit my makefile each time.

Upvotes: 0

Views: 687

Answers (4)

Shep
Shep

Reputation: 8380

You mention g++ -MM, which can do what you're trying to do:

include $(ALLOBJ:%.o=%.d)

%.d: %.cxx
    @echo making dependencies for $<
    @g++ -MM -MP $(CXXFLAGS) $< -o $@
    @sed -i 's,$*\.o,& $@ ,g' $@

Basically this defines a rule that creates .d files from .cxx files. The .d files are, in turn, required by the include statement, which requires one for each .o file in ALLOBJ.

The last line in the dependency rule is the 'sed magic' that makes the dependency files regenerate themselves. If you think regular expressions are hacks at best, and evil more often than not, you can use the -MT flag.

Upvotes: 1

Beta
Beta

Reputation: 99172

To solve the problem I mentioned (-include is not a good solution), I use something like this:

build/%.o: %.cpp
    @$(CC) -MD -c -Wall -o $@ $<
    @cp build/$*.d build/$*.P
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
         -e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d
    @rm build/$*.P

-include build/*.d

No `%.d rule is needed.

EDIT:

@JackKelly has [*cough*, *choke*] shown me a better way to get effectively the same dependency file:

build/%.o: %.cpp
    @$(CC) -MD -c -Wall -o $@ $<
    @$(CC) -MM -MP -Wall -o $*.d $<

-include build/*.d

Ye, you can have multiple rules for the same target, as long as only one of them has commands; the prerequisites accumulate. The idea is to get a file like this:

file.o: file.cpp headerfile.h
headerfile.h:

The second line (headerfile.h:) is a rule for headerfile.h that has no prerequisites or commands. It does nothing, but it's a rule, so if headerfile.h is missing, Make is satisfied.

Upvotes: 2

anatolyg
anatolyg

Reputation: 28300

The outline of a solution is as follows:

  • Use auxiliary dependency files for each source file (that is, create foo.dep for foo.c, bar.dep for bar.c etc)
  • Use gcc -MM to create the dependency files
  • In order to force make to do this automatically, use foo.c as a prerequisite for foo.dep and foo.o; this requires some minor sed magic on the output of gcc -MM
  • Include all the dependency files in your main makefile; this is a key step that makes this approach possible.

The last step is written as follows:

-include $(dependency_files)

This is very tricky but possible; see the GNU make manual for more information.

Upvotes: 1

slugonamission
slugonamission

Reputation: 9642

You can do this with Make, you just need to specify the headers in your rule's sensitivity list. For example

myfile.o: myfile.cpp
    gcc -c myfile.o myfile.cpp ${LDFLAGS}    # This is optional. make can infer this line.

Turns into

myfile.o: myfile.cpp myfile.h
    gcc -c myfile.o myfile.cpp ${LDFLAGS}    # Again, optional.

Now, whenever myfile.h changes, myfile.cpp will be rebuild. More headers can be chained in a similar way.

Upvotes: 0

Related Questions