0

I have a folder structure in my src folder, which I want to preserve in my obj folder, where all the .o files go. I don not want to use mkdir, since many problems arise with cross-platform use. Instead I did

$(OBJECTS) := $(patsubst %,obj/%,$(subst /,_,$(SOURCES)))

The problem now is, that the input and output file names of the rule that creates those files are different, which means doing

$(OBJECTS): obj/%.o: %.cpp
    # whatever compile command

no longer works, because for an example output of obj/Core_Graphics_Window.o the input is Core/Graphics/Window.cpp.

Can this still be done?

Post Self
  • 1,471
  • 2
  • 14
  • 34

3 Answers3

1

If you want to use a different name you cannot use implicit rules or static pattern rules. You must create explicit rules for every target. To avoid doing this by hand you'll need to do something fancier such as use an eval/call combination:

COMPILE.cxx = whatever compile command

define cxx_rule
obj/$(subst /,_,$1).o: $1.cpp
        $$(COMPILE.cxx) -c -o $$@ $$<
endef

$(foreach O,$(OBJECTS),$(eval $(call cxx_rule,$(basename $O))))

Note carefully the escaped (doubled) dollar signs. To understand more about how this works you might read this set of blog posts.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
0

Try this (because I didn't, so it might not work)

  1. Gather the list of all sources with their paths (explicitly, or https://stackoverflow.com/a/2483203/2064196), let's call them SOURCES.
  2. Create an explicit list of dependencies: echo ${SOURCES} | tr ' ' "\n" | perl -nwle '$c = $_; s!/!_!g; print "obj/$_ : $c\n\twhatever compile command"' > rules.mk
  3. Make rules.mk depend on SOURCES: rules.mk : ${SOURCES}
  4. include rules.mk

If you're dumping every object file in the same directory, I'd suggest you forget about the hierarchy in the sources. Then you can write a single

obj/%.o : %.cpp
    # whatever compile command

and pick up the sources by constructing the appropriate VPATH.

Bulletmagnet
  • 5,665
  • 2
  • 26
  • 56
  • The thing is, I can't use `obj/%.o : %.cpp`, since the file names are different; the `%` won't be the same – Post Self Jul 02 '17 at 08:39
  • That works if you give up on renaming the objects, i.e the object file for `Windows.cpp` is `obj/Windows.o`, regardless of where Windows.cpp is located. – Bulletmagnet Jul 02 '17 at 09:07
  • Why does ```$(OBJECTS): $(SOURCES) $(CXX) $^ -o $@``` not work? It always chooses the first element of `$(SOURCES)` instead of iterating over the "array" :( – Post Self Jul 02 '17 at 10:27
  • (There's a new line and indentation before `$(CXX)`) – Post Self Jul 02 '17 at 10:28
0

(This is not another answer, just an explanation to kim366's comment).

Why does $(OBJECTS): $(SOURCES) not work?

That expands to

a.o b.o c.o : a.c b.c c.c
    compiler command

This is not a rule that tells make how to create a.o from a.c, b.o from b.c and c.o from c.c

This is in fact three rules; it's equivalent to

a.o : a.c b.c c.c
    compiler command
b.o : a.c b.c c.c
    compiler command
c.o : a.c b.c c.c
    compiler command

In general, you can have two kinds of rules in (GNU) make: explicit rules (where the list of dependencies is specified by hand) and pattern/suffix rules (where the list of dependencies is deduced). In both cases, the target is a single file. In fact, make has difficulties with commands that produce more than one file (source generators like lex, yacc, protobuf, etc).

For example, you can't tell make that protoc creates both a .cc and a .h file:

%.pb.cc %.pb.h : %.proto
    protoc .... $<

This is two separate rules to make, and I've seen it launch two separate protoc processes (with the same command line) when building multiple jobs in parallel.

Bulletmagnet
  • 5,665
  • 2
  • 26
  • 56