英文:
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 results in compilation error:
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?
英文:
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 ?
答案1
得分: 0
为什么会出现这个错误?
变量赋值设置了一个Shell变量,而不是一个Make变量。然而,Make尝试展开$(SRECOUT)
,这依赖于SRECOUT
的存在。我们不知道,因为你只提供了Makefile的一部分。
不过,这并不重要,因为在下一行中会出现相同的效果。Make尝试展开$(CRC_FROM_FILE)
,这很可能不存在。因此,展开为空,导致命令行参数为-defsym=CRC=
。
现在链接器将其诊断为语法错误。(如果你查看shell中执行的命令,这是显而易见的。不幸的是,你在问题中没有提供它。)
实际上,这是一个链接错误,而不是编译错误。
关于Make变量的一些注意事项...
Make以不同的方式扩展其变量,有时会有一些令人惊讶的方式,通常不是我们所期望的。
大多数扩展是在第一个配方执行之前完成的。
在读取时,定义会被扩展。
使用:=
(或POSIX兼容的::=
)定义的变量只会被扩展一次。
使用=
定义的变量在每次替换时都会被扩展。
Make手册提供了详细信息...
这个示例展示了两种你可以使用的替代方法:
- 将CRC的创建与其使用分开。你可以使用
eval
函数来展开变量。 - 使用“命令替换”,将反引号中的部分替换为封闭命令的输出。
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)
运行结果为:
$ 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
它是如何工作的?
替代方法1 利用了只有在请求其目标时才会执行配方的行的事实。然而,由于Make需要读取其所有行,eval
函数在第一个shell命令运行之前执行。
替代方法2 推迟了对结果文件的读取,并将其交给了shell。由于相应的行在结果文件接收到新内容后执行,我们得到了预期的效果。
就我个人而言,我不会把事情搞得比必要的还要复杂,我会选择替代方法2:
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=`cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g'` \
或者更简洁一点:
cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g' > $(SRECOUT).crc
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=`cat $(SRECOUT).crc` \
英文:
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:
- Separate the creation of the CRC from its usage. You can use the
eval
function to expand the variable. - 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` \
答案2
得分: -1
你在Makefile中使用$(CRC_FROM_FILE)
来动态设置符号时遇到的问题是由于Makefile上下文中如何处理变量展开而引起的。
当你写-defsym=CRC=$(CRC_FROM_FILE)
时,Makefile将$(CRC_FROM_FILE)
解释为一个Makefile变量,这个变量可能已经定义,也可能没有定义,这导致了你看到的错误消息。
为了解决这个问题,你可以在Makefile中使用shell
函数来执行命令并捕获其输出。以下是如何修改你的代码:
CRC_FROM_FILE := $(shell cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g')
$(OBJCOPY) -O binary --only-section=.text $(APPNAME).elf $(APPNAME).bin
$(SREC_CAT) $(APPNAME).bin $(SRECFLAGS) -Output $(SRECOUT).txt --hex-dump
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=$(CRC_FROM_FILE) \
# 其余的编译和链接命令
在这段代码中,$(shell ...)
函数执行命令并捕获其输出,将其赋值给CRC_FROM_FILE
变量。然后,你可以在链接命令中直接使用$(CRC_FROM_FILE)
,不会出现问题。
确保将这段代码放在Makefile中需要动态符号定义生效的位置。这应该解决你遇到的语法错误。
英文:
The issue you're encountering with the dynamic setting of the symbol using $(CRC_FROM_FILE)
in your Makefile is due to how the variable expansion is being handled within the Makefile context.
When you write -defsym=CRC=$(CRC_FROM_FILE)
, the Makefile interprets $(CRC_FROM_FILE)
as a Makefile variable, which may or may not have been defined, resulting in the error message you're seeing.
To address this, you can use the shell
function in the Makefile to execute the command and capture its output. Here's how you can modify your code:
CRC_FROM_FILE := $(shell cat $(SRECOUT).txt | cut -c 10-21 | sed 's/\ //g')
$(OBJCOPY) -O binary --only-section=.text $(APPNAME).elf $(APPNAME).bin
$(SREC_CAT) $(APPNAME).bin $(SRECFLAGS) -Output $(SRECOUT).txt --hex-dump
$(LD) -Bstatic -nostdlib --gc-sections -defsym=CRC=$(CRC_FROM_FILE) \
# rest of your compilation and linking commands
In this code, the $(shell ...)
function executes the command and captures its output, assigning it to the CRC_FROM_FILE
variable. Then, you can use $(CRC_FROM_FILE)
directly in the linker command without issues.
Make sure to place this code within your Makefile where you want the dynamic symbol definition to take effect. This should resolve the syntax error you were encountering.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论