Reputation: 4878
I have a need to generate a few object files with different load addresses. I also have a make target for invoking objdump
to show me the respective disassembly.
code0:
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) [email protected] -o [email protected]
objcopy -O binary [email protected] --only-section=.text [email protected]
code1:
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE1_RELOC) [email protected] -o [email protected]
objcopy -O binary [email protected] --only-section=.text [email protected]
dump: dump_code0 dump_code1
dump_code0: code0.bin
objdump $< -D > $<.decomp
dump_code1: code1.bin
objdump $< -D > $<.decomp
This will fail because there is no target for code.bin
, but target dump_code
depends on code.bin
being present. To prevent it from being confusing (i.e. using dependency code0
such that code0.bin
is then produced) I thought it would be easier to create a %.bin
target that will create the respective binary file associated with each object file (since there is also duplication of this code across all code*
targets anyway. This target will then be a dependency for each code*
target. However, this necessitates (or at least I think it does) the need for dynamically assigning dependencies. I tried something like this that did not work:
%.bin: $(basename $@)
objcopy -O binary $(basename $@).o --only-section=.text [email protected]
code0: code0.bin
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) [email protected] -o [email protected]
With the logic being that a dependency such as code0.bin
would cause this target to execute with the single effective dependency of code0
to first build the object file.
I may be misunderstanding how the %
character may be used to wildcard make targets. The first usesof basename
was evaluating as empty (the second worked), so the target had no dependencies. It does make sense that the dependency tree be evaluated once at invocation, but I was hoping for a more dynamic capability.
Can this be done in Make?
Upvotes: 1
Views: 3555
Reputation: 29375
What you are looking for is probably Static Pattern Rules with which you could rework your first attempt:
code0:
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE0_RELOC) [email protected] -o [email protected]
objcopy -O binary [email protected] --only-section=.text [email protected]
as:
code0.o code1.o: code%.o: code%.S
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE$*_RELOC) $< -o $@
code0.bin code1.bin: %.bin: %.o
objcopy -O binary $< --only-section=.text $@
See the principle? $*
in the recipe of the first rule is substituted by the matching stem of the static pattern rule (the digit in our case). This works but pattern-specific variables would probably be easier to understand and maintain:
# Default code reloc option
CODE_RELOC := default_code_reloc_option
# code1-specific code reloc option, if different from default
code1.o: CODE_RELOC := code1_code_reloc_option
code0.o code1.o: %.o: %.S
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE_RELOC) $< -o $@
The last part of your first makefile could also use static pattern rules, plus phony targets. Something like:
.PHONY: dump dump_code0 dump_code1
dump: dump_code0 dump_code1
dump_code0 dump_code1: dump_%: %.bin.decomp
code0.bin.decomp code1.bin.decomp: %.bin.decomp: %.bin
objdump $< -D > $@
Finally, we can use some more make tricks (discovery of source files, pattern substitutions) to automate a bit further:
CODES := $(wildcard *.S)
OBJS := $(patsubst %.S,%.o,$(CODES))
BINS := $(patsubst %.S,%.bin,$(CODES))
DECS := $(patsubst %.S,%.bin.decomp,$(CODES))
DUMPS := $(patsubst %.S,dump_%,$(CODES))
# Default code reloc option
CODE_RELOC := default_code_reloc_option
# code1-specific code reloc option, if different from default
code1.o: CODE_RELOC := code1_code_reloc_option
.PHONY: dump $(DUMPS)
dump: $(DUMPS)
$(DUMPS): dump_%: %.bin.decomp
$(DECS): %.bin.decomp: %.bin
objdump $< -D > $@
$(BINS): %.bin: %.o
objcopy -O binary $< --only-section=.text $@
$(OBJS): %.o: %.S
gcc -m32 $(CFLAGS) -Wl,$(LDFLAGS),-Ttext=$(CODE_RELOC) $< -o $@
.PHONY: clean
clean:
rm -f $(OBJS) $(BINS) $(DECS)
The clean
target is a bonus gift.
All this has a significant advantage over what you were trying to do with targets that were not real files. Here, files depend on other files, except the phony targets that are just a kind of shorthand for real target files. And this is 100% in line with make's philosophy: express inter-files dependences such that make compares files timestamps and decides what is up-to-date and what must be rebuilt. Significant savings when a lot of targets are already up-to-date.
A second advantage is that expressing all inter-files dependences is parallel safe. If you run make on this makefile with:
make -j 8
(assuming you have about 8 cores on your computer), you can expect a speed-up factor of 8. Not much if you have only two source files, but quite interesting if you have hundreds of them...
Upvotes: 3