Autosar 系列教程:小柴带你学 AutoSar 总目录

# 小柴带你学 AutoSar 系列一、基础知识篇(4)编译

编译真的很重要!了解一下机器是如何工作的吧。当然啦!通过学习这篇文章还可以学习制作库文件哦!隐藏你的源码,依然可以调用函数。这样代码发给别人就不怕源码暴漏哦!🍔

image-20240601175457674

# GCC 编译

GCC 编译器是一个开源的编译器套件,用于编译多种编程语言,包括 C、C++、Objective-C、Fortran、Ada 等。它是一个功能强大且灵活的编译器,支持多种平台和架构。

# 1. 预处理阶段(Preprocessing)

在预处理阶段,GCC 将源代码中的预处理指令(以 # 开头的指令,如 #include#define )处理成纯 C 代码。预处理器会将头文件包含到源文件中,执行宏替换等操作。

生成的文件:通常,预处理后的文件会以 .i 扩展名保存,如 source.i

# 2. 编译阶段(Compilation)

编译阶段将预处理后的源文件翻译成汇编语言。GCC 使用的是内置的 C 编译器(称为 cc1 ),它将 C 代码转换成目标机器的汇编代码。

生成的文件:通常,编译后的文件会以 .s 扩展名保存,如 source.s

# 3. 汇编阶段(Assembly)

在汇编阶段,汇编器将汇编代码转换成机器码指令,生成目标文件。这些目标文件包含了二进制代码和相关的元数据。

生成的文件:通常,汇编后的文件会以 .o 扩展名保存,如 source.o

# 4. 链接阶段(Linking)

链接阶段将所有的目标文件(包括程序的主文件和所有的库文件)链接在一起,生成最终的可执行文件。链接器(ld)负责解析符号引用、符号重定位等任务,将各个目标文件中的代码和数据段组合成一个可执行文件。

生成的文件:最终生成的可执行文件通常没有扩展名,如 a.out

# 示例

假设有一个 C 源文件 hello.c

#include <stdio.h>
int main() {
    printf("Hello, world!\n");
    return 0;
}

通过 GCC 编译该文件时,可以执行以下命令:

gcc -o hello hello.c

这个命令会依次执行预处理、编译、汇编和链接四个阶段,并生成最终的可执行文件 hello

  • hello.i :预处理后的文件。
  • hello.s :编译后的汇编文件。
  • hello.o :汇编后的目标文件。
  • hello :最终的可执行文件。

这就是 GCC 编译器的工作过程以及每个阶段生成的文件。

# GHS 编译

RH850 是一种用于嵌入式系统的微控制器(MCU),通常用 Green Hills Software(GHS)编译工具进行编译和链接。GHS 工具链包含编译器、汇编器、链接器等,支持各种目标平台和架构。编译过程包括使用链接脚本,这是生成嵌入式系统二进制文件的关键步骤。下面是一个典型的 RH850 使用 GHS 编译器的编译过程,详细介绍了每个阶段及其生成的文件,特别是链接器脚本的作用。

# 1. 源代码准备

假设有一个简单的 C 源文件 main.c

#include <stdio.h>
void main(void) {
    printf("Hello, RH850!\n");
}

# 2. 预处理阶段

预处理器将处理所有的预处理指令,例如 #include#define ,生成一个预处理后的文件。

命令

ccrh850 -E main.c -o main.i

生成的文件

  • main.i :预处理后的文件。

# 3. 编译阶段

编译器将预处理后的 C 代码转换为汇编代码。

命令

ccrh850 -S main.i -o main.s

生成的文件

  • main.s :汇编代码文件。

# 4. 汇编阶段

汇编器将汇编代码转换为机器代码,生成目标文件。

命令

asrh850 main.s -o main.o

生成的文件

  • main.o :目标文件(对象文件)。

# 5. 链接阶段

链接器将多个目标文件和库文件链接在一起,生成可执行文件。链接器脚本在这个阶段非常重要,用于指定代码和数据段在内存中的布局。

链接器脚本(linker script)

一个典型的链接器脚本可能如下所示( linker.ld ):

SECTIONS
{
    .text : {
        *(.text)
    }
    .data : {
        *(.data)
    }
    .bss : {
        *(.bss)
    }
}

这个脚本指定了 .text 段(代码段)、 .data 段(数据段)和 .bss 段(未初始化数据段)的布局。

命令

librh850 main.o -T linker.ld -o main.elf

生成的文件

  • main.elf :最终的可执行文件(ELF 格式)。

# 总结

  • 预处理:

    ccrh850 -E main.c -o main.i
    
    • 生成预处理后的文件 main.i
  • 编译:

    ccrh850 -S main.i -o main.s
    
    • 生成汇编代码文件 main.s
  • 汇编:

    asrh850 main.s -o main.o
    
    • 生成目标文件 main.o
  • 链接:

    librh850 main.o -T linker.ld -o main.elf
    
    • 生成最终的可执行文件 main.elf ,使用链接器脚本 linker.ld 指定内存布局。

每个阶段都生成特定的中间文件和最终的可执行文件,链接器脚本在链接阶段至关重要,它定义了程序的内存布局,使得生成的二进制文件能够正确地运行在目标硬件上。

# 静态库.lib

通过静态库,开发者可以隐藏实现细节,仅暴露接口(头文件)。这增加了代码的安全性,并使得接口的更改不会影响到使用该库的代码,只要接口保持不变。

真的太好玩啦!

# 1. 制作静态库

  • VS 创建一个新项目

    image-20240601180016291

  • 打印一些信息,并在头文件声明这个函数

image-20240601180221362

  • 生成 lib

image-20240601180400338

看到他啦

image-20240601180440718

# 2. 使用静态库

# 1. 创建或打开你的 C 项目

首先,确保你已经在 Visual Studio 中创建了一个 C 项目或打开了现有的 C 项目。

# 2. 将静态库文件添加到项目

假设你的静态库文件是 StaticLib1.lib

  1. StaticLib1.lib 文件拷贝到你的项目目录中,通常放在一个特定的文件夹中,比如 libs 文件夹。我懒哈哈!随便放啦

image-20240601180639255

# 3. 添加库文件路径和库文件名到项目设置

  1. 打开项目属性
    • 在解决方案资源管理器中,右键点击你的项目名称,选择 “属性”( Properties )。
  2. 配置包含目录
    • 在项目属性窗口中,导航到 Configuration Properties -> C/C++ -> General
    • Additional Include Directories 字段中,添加你的头文件目录的路径。如果你的头文件在 include 文件夹中,输入相对路径 include 或者绝对路径。
  3. 配置库目录
    • 在项目属性窗口中,导航到 Configuration Properties -> Linker -> General
    • Additional Library Directories 字段中,添加你的静态库目录的路径。如果你的库文件在 libs 文件夹中,输入相对路径 libs 或者绝对路径。
  4. 添加库文件
    • 在项目属性窗口中,导航到 Configuration Properties -> Linker -> Input
    • Additional Dependencies 字段中,添加你的库文件名称 mylibrary.lib 。如果有多个库文件,用分号分隔。

最后就可以调用静态库里的函数啦!同时又看不到函数的具体实现。是不是贼有意思呢?

image-20240601180929641

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

flechazo 微信支付

微信支付

flechazo 支付宝

支付宝

flechazo 贝宝

贝宝