Search code examples
makefileld

Set symbol value by -defsym in makefile


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 ?


Solution

  • 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:

    1. Separate the creation of the CRC from its usage. You can use the eval function to expand the variable.
    2. Use "command substitution", which replaces the part in back ticks with the output of the enclosed command.
    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` \