I want to set a symbol defined in the linker script dynamically by makefile.
In the target rules I've the following code :
$(OBJCOPY) -O binary --only-section=.text $(APPNAME).elf $(APPNAME).bin
$(SREC_CAT) $(APPNAME).bin $(SRECFLAGS) -Output $(SRECOUT).txt --hex-dump
CRC_FROM_FILE= cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g'
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=0x11223344 \
This code is working fine.
But now I want to set it dynamically by :
$(OBJCOPY) -O binary --only-section=.text $(APPNAME).elf $(APPNAME).bin
$(SREC_CAT) $(APPNAME).bin $(SRECFLAGS) -Output $(SRECOUT).txt --hex-dump
CRC_FROM_FILE= cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g'
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=$(CRC_FROM_FILE) \
which result at compilation :
c:\gcc-arm-8.2-2018.08-i686-mingw32-arm-eabi\bin\arm-eabi-ld.exe:--defsym:0: syntax error
So my question is why ?
Why do you get this error?
The variable assignment sets a shell variable, not a Make variable. However, Make tries to expand $(SRECOUT)
, which depends on the existence of SRECOUT
. We don't know, because you provided just an excerpt of your Makefile.
Anyway, this does not matter because in the next line the same effect arises. Make tries to expand $(CRC_FROM_FILE)
, which most probably does not exist. In consequence, the expansion is empty, resulting in the command line argument -defsym=CRC=
.
Now the linker diagnoses this as a syntax error. (If you look at the executed command in your shell, it is obvious. Unfortunately you do not provide it in your question.)
Actually, it is a linkage error, not a compilation error.
A few notes on Make variables...
Make expands its variables in different and sometimes surprising ways, generally not as we expect.
Most of the expansions are done before the first recipe is executed.
Definitions are expanded at the time they are read.
Definitions with :=
(or POSIX conformant ::=
) are expanded only once at all.
Definitions with =
are expanded on each substitution.
The Make manual has the detailed information...
This example shows two alternatives you can use:
eval
function to expand the variable.all: step1 step2 step3
step1:
@echo mark content as old
echo "old content" > result.txt
step2:
@echo generate new content
echo "new content" > result.txt
$(eval CONTENT = $(shell cat result.txt))
@echo result.txt via make variable still has $(CONTENT)
@echo result.txt via command substitution has now `cat result.txt`
step3:
@echo use new content
$(eval CONTENT = $(shell cat result.txt))
@echo result.txt via make variable has now $(CONTENT)
Running results in:
$ make
mark content as old
echo "old content" > result.txt
generate new content
echo "new content" > result.txt
result.txt via make variable still has old content
result.txt via command substitution has now new content
use new content
result.txt via make variable has now new content
How does it work?
Alternative 1 takes advantage of the fact that the lines of a recipe are executed only if its target is requested. However, since Make needs to read all its lines, the eval
function is executed before the first shell command of the recipe runs.
Alternative 2 defers the reading of the result file and gives it over to the shell. As the respective line executes after the result file receives the new content, we get the expected effect.
Personally, I would not make life harder than necessary, and would go with alternative 2:
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=`cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g'` \
Or less dense:
cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g' > $(SRECOUT).crc
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=`cat $(SRECOUT).crc` \