3

My question is an extension of the question Can I compile all .cpp files in src/ to .o's in obj/, then link to binary in ./?

My project has the similar structure, but I have far more then one src folder, including folders, that are outside of my root /project dir:

/somedir
  /project
    Makefile
    main
    /src1
      main.cpp
      foo.cpp
      foo.h
    /src2
      bar.cpp
      bar.h
    ...
    /srcn
      baz.cpp
      baz.cpp
    /obj
      main.o
      foo.o
      bar.o
      ...
      baz.o
      alpha.o
      betta.o
      ...
      zetta.o
  /ext_src1
    alpha.cpp
  /ext_src2
    betta.cpp
  ...
  /ext_srcn
    zetta.cpp

In my Makefile I have list of all cpp's I need, collected partly manually, partly with the help of wildcard. I assume, that the names of all cpp files are different (and their objects can safely be put into one dir). Now, how can I compile all them, into my obj folder?

I managed to do almost what I want in the following way:

SOURCES=${wildcard src1/*.cpp} 
SOURCES+=${wildcard src2/*.cpp} 
...
SOURCES+=../ext_srcn/zetta.cpp 

OBJECTS=$(SOURCES:.cpp=.o)

main: $(OBJECTS)
    $(CC) $(LD_FLAGS) -o $@ $^

.cpp.o:
    $(CC) $(CFLAGS) -c $< $(INCLUDES) -o $(addprefix obj/,$(notdir $@))

But now, of course, all my sources are recompiled every time, even when no changes are made. That is terrible. How can I trace the origin of my .o target on obj ? Or may be there is another way to solve my task ?

Community
  • 1
  • 1
Meteorite
  • 903
  • 1
  • 9
  • 13
  • This is hardly c++, I don't think `.cpp` constitutes using the tag :/ – Syntactic Fructose Jun 03 '14 at 17:56
  • 1
    @SyntacticFructose It specifically has to do with `C++` compilation, so the tag is okay here. – Cory Kramer Jun 03 '14 at 17:59
  • 1
    You may try setting [`VPATH`](https://www.gnu.org/software/make/manual/html_node/General-Search.html) and specify your target `.o` with the wanted build path (while ensuring this one exists!). Also generate [dependency files](http://scottmcpeak.com/autodepend/autodepend.html) for your object files and include these. – πάντα ῥεῖ Jun 03 '14 at 18:06

1 Answers1

1

You can keep the source path in the obj directory:

TOP := $(realpath ../)
SOURCES := $(wildcard $(TOP)/project/src1/*.cpp)
SOURCES += $(wildcard $(TOP)/project/src2/*.cpp)
...
SOURCES += $(TOP)/ext_srcn/zetta.cpp 

OBJECTS := $(addprefix $(TOP)/project/obj,$(patsubst $(TOP),,$(SOURCES:%.cpp=%.o)))

main: $(OBJECTS)
    $(CC) $(LD_FLAGS) -o $@ $^

$(OBJECTS): $(TOP)/project/obj/%.o: $(TOP)/%.cpp
    $(CC) $(CFLAGS) -c $< $(INCLUDES) -o $@

This way you will have something like this:

/somedir
  /project
    Makefile
    main.cpp
    /src1
      foo.cpp
      foo.h
    /src2
      bar.cpp
      bar.h
    ...
    /srcn
      baz.cpp
      baz.h
    /obj
      /project
        main.o
        /src1
          foo.o
        /src2
          baz.o
        ...
        /srcn
          baz.o
      /ext_src1
        alpha.o
      /ext_src2
        beta.o
      ...
      /ext_srcn
        zetta.o
  /ext_src1
    alpha.cpp
  /ext_src2
    betta.cpp
  ...
  /ext_srcn
    zetta.cpp

And, - normally - the dependencies will work well.

jmlemetayer
  • 4,774
  • 1
  • 32
  • 46
  • I've adopted another technique, based on VPATH as suggested by πάντα ῥεῖ. But your proposal seems to be somewhat more general, as it allows .cpp files with the same names in different folders. That's why I mark your answer as accepted. – Meteorite Jun 07 '14 at 05:27