2
votes

I have the following makefile:

OUTPUTDIR = build

all: v12target v13target
v12target: INTDIR = v12
v12target: DoV12.avrcommontargets
v13target: INTDIR = v13
v13target: DoV13.avrcommontargets

%.avrcommontargets: $(OUTPUTDIR)/%.elf
    @true

$(OUTPUTDIR)/%.elf: $(OUTPUTDIR)/$(INTDIR)/main.o
    @echo TODO build ELF file from object file: destination $@, source $^
    @echo Compiled elf file for $(INTDIR) > $@

$(OUTPUTDIR)/$(INTDIR)/%.o: %.c
    @echo TODO call GCC to compile C file: destination $@, source $<
    @echo Compiled object file for $<, revision $(INTDIR) > $@

$(shell rm -rf $(OUTPUTDIR))
$(shell mkdir -p $(OUTPUTDIR)/v12 2> /dev/null) $(shell mkdir -p $(OUTPUTDIR)/v13 2> /dev/null)

.SECONDARY:

The idea is that there are several different code configurations that need to be compiled from the same source code. The "all" target depends on v12target and v13 target, which set a number of variables for that particular build. It also depends on an "avrcommontargets" pattern, which defines how to actually do the compiling. avrcommontargets then depends on the ELF file, which in turn depends on object files, which are built from the C source code.

Each compiled C file results in an object file (*.o). Since each configuration (v12, v13, etc.) results in a different output, the C file needs to be built several times with the output placed in different subdirectories. For example, "build/v12/main.o", "build/v13/main.o", etc.

Sample output:

TODO call GCC to compile C file: destination build//main.o, source main.c
TODO build ELF file from object file: destination build/DoV12.elf, source build//main.o
TODO build ELF file from object file: destination build/DoV13.elf, source build//main.o

The problem is that the object file isn't going into the correct subdirectory. For example, "build//main.o" instead of "build/v12/main.o". That then prevents the main.o from being correctly rebuilt to generate the v13 version of main.o.

I'm guessing the issue is that $(INTDIR) is a target specific variable, and perhaps this can't be used in the pattern targets I defined for %.elf and %.o.

The correct output would be:

TODO call GCC to compile C file: destination build/v12/main.o, source main.c
TODO build ELF file from object file: destination build/DoV12.elf, source build/v12/main.o
TODO call GCC to compile C file: destination build/v13/main.o, source main.c
TODO build ELF file from object file: destination build/DoV13.elf, source build/v13/main.o

What do I need to do to adjust this makefile so that it generates the correct output?

1

1 Answers

1
votes

You redirected the "Compiled elf file" lines from your output, which look like:

Compiled elf file for v13

While the target-specific variable substitution works in general, it seems it is done after the selection of targets - which is fair enough, since doing otherwise would be fairly hard to implement.

You could use $(foreach) and $(eval) to produce one rule per target. However, I'd like to point out again that you are re-engineering out of tree builds here. The best alternative is to go on with the autotools. The second best is making your out-of-tree build logic complete and use one build tree per target, with a small configure sh script inserting the compilation flags in a Makefile.

Elaborating on the second solution:

Let the regular make run in subdirectories, one per target. Have a switch in your main makefile that controls execution of the sub-make's. Your main Makefile looks like:

TARGETS = v12 v13

CFLAGS_v12 = -foo
CFLAGS_v13 = -bar

ifeq ($(TARGET),)
all :
    mkdir --parents $(TARGETS)
    $(foreach t,$(TARGETS),SRCDIR=.. CFLAGS="$(CFLAGS_$t)" TARGET=$t $(MAKE) -C $t -f ../Makefile &&) true
clean :
    rm -rf $(TARGETS)
else
all : main.elf
endif

%.elf : %.o
    echo "Linking $@ from $< with $(CFLAGS)"

%.o : $(SRCDIR)/%.c
    echo "Compiling $@ from $< with $(CFLAGS)"

.PHONY : all