我正在尝试找到与 avr 中的
.c
头文件相关的 #include
文件。
我想看看 avr-gcc 库中定义的一些标准库,特别是
<avr/io.h>
中包含的 PORT 定义。我在 /usr/lib/avr/include/avr
中搜索了库并找到了头文件,但是我正在寻找的是 .c
文件。这个文件存在吗?如果有的话,我在哪里可以找到它?如果不是,头文件引用的是什么?
编译器提供的库是存储在静态库中的预编译目标代码。在 gcc 中,库通常使用扩展名 .a(主要出于历史原因表示“存档”)和前缀“lib”。
在构建时,链接器将搜索库档案以查找解析对库符号的引用所需的目标代码模块。它提取所需的模块并将它们链接到正在构建的二进制映像。
在 gcc 中,库 libXXX.a 通常使用命令行开关链接
-lXXX
- 因此 libXXX.a 命名约定在这种情况下很重要。例如,标准 C 库 libc.a 通过开关 -lc
链接。
因此,为了回答您的问题,工具链提供的编译器提供的库通常没有 .c 文件。该库甚至不需要用 C 编写。
也就是说,由于是开源的,源文件(.c 或其他)可以从各个库的存储库中获得。例如,对于标准 C 库:https://www.nongnu.org/avr-libc/.
对于其他 AVR 架构和 I/O 支持库,您可以检查相关的头文件或文档。头文件通常会有一个样板注释,例如带有项目 URL。
PORTB 和其他特殊功能寄存器通常在 avr-libc 提供的头文件中定义为宏。找到您的
include/avr
目录(包含 io.h
的目录)。在该目录中,应该还有许多其他头文件。例如,iom328p.h
包含以下行,在 ATmega328P 上定义 PORTB
:
#define PORTB _SFR_IO8(0x05)
如果您也在寻找以
.a
文件形式分发的库,您应该运行 avr-gcc -print-search-dirs
。
有多种方法可以找出系统标头的位置以及包含哪些标头:
avr-gcc -v -mmcu=atmega8 foo.c ...
使用选项
-v
,GCC 将打印(以及其他内容)其中包括它正在使用的路径。检查 shell/控制台上的输出,GCC 将打印搜索路径:
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/avr/5.4.0/include
/usr/lib/gcc/avr/5.4.0/include-fixed
/usr/lib/gcc/avr/5.4.0/../../../avr/include
最后一个位置是 AVR-LibC,它提供
avr/io.h
。解决 ..
问题,该路径就是 /usr/lib/avr/include
。这些路径取决于 avr-gcc 的配置和安装方式,因此您必须在安装 avr-gcc
时运行该命令。
avr-gcc -H -mmcu=atmega8 foo.c ...
假设 C 文件
foo.c
内容为:
#include <avr/io.h>
int main (void)
{
PORTD = 0;
}
举一个简单的例子。使用
-H
,GCC 将打印出它实际包含的文件:
. /usr/lib/avr/include/avr/io.h
.. /usr/lib/avr/include/avr/sfr_defs.h
... /usr/lib/avr/include/inttypes.h
.... /usr/lib/gcc/avr/5.4.0/include/stdint.h
..... /usr/lib/avr/include/stdint.h
.. /usr/lib/avr/include/avr/iom8.h
.. /usr/lib/avr/include/avr/portpins.h
.. /usr/lib/avr/include/avr/common.h
.. /usr/lib/avr/include/avr/version.h
.. /usr/lib/avr/include/avr/fuse.h
.. /usr/lib/avr/include/avr/lock.h
avr-gcc -save-temps -g3 -mmcu=atmega8 foo.c ...
使用 DWARF-3 调试信息,宏定义将记录在调试信息中,并在预处理文件中可见(
*.i
表示 C 代码,*.ii
表示 C++,*.s
表示预处理汇编) 。因此,在foo.i
中我们可以找到PORTD
的定义为
#define PORTD _SFR_IO8(0x12)
从包含该定义的行开始,向上滚动,直到找到说明宏定义发生在哪个文件中的注释。例如
# 45 "/usr/lib/avr/include/avr/iom8.h" 3
以我的工具链安装为例。这意味着该注释后面的行遵循
/usr/lib/avr/include/avr/iom8.h
的第 45 行。
如果您想查看 PORTD 的分辨率,请向下滚动到
foo.i
的末尾,其中包含预处理的源代码:
# 3 "foo.c"
int main (void)
{
(*(volatile uint8_t *)((0x12) + 0x20)) = 0;
}
0x12
是PORTD
的I/O地址,0x20
是ATmega8的I/O地址和RAM地址之间的偏移量。这意味着编译器可以通过 PORTD = 0
来实现 out 0x12, __zero_reg__
。
最后,此命令将打印
libc.a
、libm.a
、libgcc.a
或 lib<mcu>.a
等库的位置(绝对路径)。库的位置取决于编译器的配置和安装方式,还取决于命令行选项,例如-mmcu=
。
这会指示链接器转储一个“映射”文件
foo.map
,它报告哪个符号将从哪个库中拖动哪个模块。这是一个文本文件,其中包含以下行:
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/crtatmega8.o
...
LOAD /usr/lib/gcc/avr/5.4.0/avr4/libgcc.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libm.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libc.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libatmega8.a
libgcc.a
来自编译器的C运行时,其他所有都由AVR-LibC提供。解决 ..
,ATmega8 的 AVR-LibC 文件位于 /usr/lib/avr/lib/avr4/
。