英文:
Set symbol value by -defsym in makefile
问题
我想通过makefile动态地设置链接器脚本中定义的符号。
在目标规则中,我有以下代码:
$(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 \
这段代码运行良好。
但是现在我想通过以下方式动态设置它:
$(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) \
这样编译时会出现以下错误:
c:\gcc-arm-8.2-2018.08-i686-mingw32-arm-eabi\bin\arm-eabi-ld.exe:--defsym:0: syntax error
所以我的问题是为什么会出现这个错误?
英文:
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)
而没有问题。
确保将这段代码放在你希望动态符号定义生效的位置。这应该解决你遇到的语法错误。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论