我知道我回答这个问题已经过去了大约2年,但我认为仍然没有正确深入的答案。
让我们从一点理论开始:
当您调用GCC时,它通常会进行预处理、编译、汇编和链接。 "总体选项" 允许您在中间阶段停止此过程。例如,-c选项表示不运行链接器。然后输出由汇编器输出的目标文件。
其他选项传递给处理的某个阶段。有些选项控制预处理器,其他选项控制编译器本身。还有其他选项控制汇编器和链接器;这些大多数都没有在此处记录,因为您很少需要使用它们。
来源:
GCC Online Docs
LDFLAGS
给编译器在它们应该调用链接器 'ld' 时提供额外的标志,例如 -L。 库(-lfoo)应添加到LDLIBS变量中。
来源:
GNU make Manual
正如你所看到的,这取决于GCC(我将称之为这种方式以区别于实际编译器;你可以发现它被称为C编译器前端或简单地称为编译器)哪些选项将传递给哪些工具,似乎
-On
选项没有传递给链接器(你可以通过给GCC加上选项
-v
来检查它)。因此,在只进行链接时调用GCC时不需要使用该选项。
真正的问题是在链接时没有向GCC提供-mmcu=dev
选项。因此,它无法找到适当的文件(C运行时),也无法告诉链接器将其链接起来;你的应用程序最终没有任何初始化代码。
因此,请注意,无论它的用途是什么(预处理/编译/汇编/链接),都必须在LDFLAGS中包含
-mmcu=dev
选项或将其传递给GCC。我已经在互联网上看到了一些没有在LDFLAGS中包含此选项的makefile,所以要小心。
现在是练习的时候了——假设您的源代码在
test.c
文件中,发出以下命令(在Linux上):
avr-gcc -mmcu=attiny13a -DF_CPU=1200000 -Wall -O1 -c -o testO1.o test.c
avr-gcc -mmcu=attiny13a -DF_CPU=1200000 -Wall -Os -c -o testOs.o test.c
avr-gcc -o testO1_nodev.elf testO1.o
avr-gcc -v -o testOs_nodev.elf testOs.o > testOs_nodev.log 2>&1
avr-gcc -v -mmcu=attiny13a -o testOs_correct.elf testOs.o > testOs_correct.log 2>&1
我会翻译中文。这段内容与编程有关,建议只保留必要选项和
-Wall
,对于ATtiny13a,需要使用
-mmcu=attiny13a
而不是
-mmcu=attiny13
。请查看
testOs_nodev.log
和
testOs_correct.log
,并执行以下命令:
diff testOs_nodev.log testOs_correct.log
你将会看到类似于:
2c2
< Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-avr2
---
> Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-attiny13a
10,12c10,12
< LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/
< COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_nodev.elf' '-specs=device-specs/specs-avr2'
< /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccqBjM6T.res \
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \
-o testOs_nodev.elf -L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib \
testOs.o --start-group -lgcc -lm -lc --end-group
---
> LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack/:\
/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/:\
/usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/
> COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_correct.elf' '-specs=device-specs/specs-attiny13a' \
'-mmcu=avr25' '-msp8'
> /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccV919rY.res \
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \
-plugin-opt=-pass-through=-lattiny13a -mavr25 -o testOs_correct.elf \
/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/crtattiny13a.o \
-L/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack \
-L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib testOs.o \
--start-group -lgcc -lm -lc -lattiny13a --end-group
区别在于没有使用-mmcu=dev
选项时,GCC默认使用avr2规范文件并不链接任何CRT文件。
使用avr-objdump检查目标文件(*.o
)和输出文件(*.elf
):
avr-objdump -xd testOs_nodev.elf
您会发现
*_nodev.elf
文件不包含有关架构的正确信息(avr而不是avr:25),也没有任何启动代码(将
testOs_correct.elf
与
testOs_nodev.elf
进行比较)。代码部分似乎是从对象文件中提供的逐字复制。
如果我的解释有任何不清楚或需要额外的说明,请随时提问(评论)。
-O1
和-O2
之间是相同的(只有标签名称改变)。你怎么可能有不同的行为却使用相同的代码? - ouah