Evan Laforge
Evan Laforge

Reputation: 979

separate builds in separate directories

I'm sure this is a totally normal thing to do, but I can't figure out how to get make to do this.

I have a compiler that generates make dependencies of the usual form:

M/A.o : M/A.hs
M/B.o : M/A.o

So I write a rule to compile %.hs into %.o, add a rule to link the binary, include the dependencies file, and all is well. But I want to have several binary targets with different flags. E.g. I want build/test built with -DTESTING and build/profile built with -prof. So I need to keep the .o files in a separate tree, where they will be compiled with special flags.

The straightforward way I can think of would be to have dependencies that look something like this:

build/test/M/A.o : M/A.hs
build/test/M/B.o : build/test/M/A.o

build/profile/M/A.o : M/A.hs
... etc.

And then rules so that %.hs to build/test/%.o compiles with -DTESTING, etc. I think this would work, but it's clumsy, means preprocessing the deps file to add all that build/whatever/ prefix stuff, and would multiply its size by however many kinds of builds.

VPATH appears to be designed for this sort of thing and my idea was that I could set the VPATH and compiler flags depending on the target, and it almost works, but:

%.o: %.hs
    @mkdir -p build/M
    cp $< build/$@

VPATH = build

main: M/A.o M/B.o
    cat $^ >$@

M/A.o : M/A.hs
M/B.o : M/B.hs

The first time the main target wants to run 'cat M/A.o M/B.o >main' which seems contrary to the gnu make documentation that says $^ should include the include the VPATH directory in which the dependency was found. Curiously, if I remove 'main' and make again, this time it uses the correct path. This is GNU make, 3.81.

What's going on here? Is there a better way to build with different flags? VPATH seems like a clumsy tool, surely there is a better way?

Upvotes: 0

Views: 218

Answers (2)

thiton
thiton

Reputation: 36049

If you haven't solved your problem by now or are experiencing further problems, best give the autotools (automake and autoconf) a chance. They'll quickly build you a Makefile that supports more configurable and flexible out-of-tree builds.

Upvotes: 0

Beta
Beta

Reputation: 99084

Make is working correctly. It tries cat M/A.o M/B.o >main the first time because it can't find the prerequisites it needs, but it knows a rule for M/A.o' andM/B.o(<em>not</em>build/M/A.o' and build/M/B.o) and expects that that is what the rule will produce. If you remove main and try again, it will find build/M/A.o' andbuild/M/B.o` via VPATH.

Let's modify this makefile in stages. First we change the VPATH so that it can find the .hs files (Make is good at using things there to build things here, not vise-versa, and that's what VPATH is good for), and change the rules slightly:

build/%.o: %.hs
    cp $< $@

VPATH = M

main: build/A.o build/B.o
    cat $^ > $@

Now for the different object directories.

build/test/%.o build/project/%.o: %.hs
    cp $< $@

VPATH = M

test: build/test/A.o build/test/B.o
    cat $^ > $@

project: build/project/A.o build/project/B.o
    cat $^ > $@

Then we simplify those last two rules, so that it's easy to add more object files and binary targets:

OBJECTS = A.o B.o

test: $(addprefix build/test/,$(OBJECTS))
project: $(addprefix build/project/,$(OBJECTS))

test project:
    cat $^ > $@

Now for the different compiler flags:

build/test/%.o: FLAGS += test_flags
build/project/%.o: FLAGS += proj_flags

build/test/%.o build/project/%.o: %.hs
    @echo building $@ from $^ using flags $(FLAGS)
    cp $< $@

Finally the dependencies. This is a little tricky. Suppose you want the dependency B.o : A.hs to apply to however many object you have. This is one approach:

OBJECT_PATHS = build/test/ build/project/

# The following is from the included file generated by the compiler
$(addsuffix B.o,$(OBJECT_PATHS)) : A.hs

To generate lines like that, I'd pipe the raw lines (e.g. B.o: A.hs) through sed 's/\(.*\):\(.*\)/\1:\2/', and note that if you want to put this in a makefile command, don't forget to double the $ signs to preserve them for the shell.

I know that's a lot to absorb. Take it one step at a time and let us know how it works out.

Upvotes: 1

Related Questions