GCC编译

GCC编译

本笔记为作者再学习嵌入式Linux的一些心得体会,如有不对的地方,请包含与谅解!我主要是采用香橙派5来作为我们学习嵌入式Linux的环境。

------------by wsoz

Hello程序代码

c 复制代码
#include <stdio.h>

int main(int argc,char **argv)
{
    if(argc > 1)
    {
        printf("Hello, %s!\n", argv[1]);
    }
    else
    {
        printf("Hello, World!\n");
    }
    return 0;
}

代码编译过程如下:

此处我们先对程序做一个简单的介绍:

c 复制代码
int main(int argc,char**argv)

这个是C程序入口标准函数声明

  • int 作为返回值
    • 0--表示程序正常结束
    • 非0--出错或者异常
  • int argc表示命令行参数个数
    • 包含了程序名/路径本身
  • char **argv表示的是命令行参数,每个参数都是字符串
    • 比如输入 ./hello world,会输出hello world!
    • 其中参数argv[0]:程序名/路径
    • argv[1]:world

GCC编译四阶段

阶段 命令示例 输入 输出 作用说明
预处理 (Preprocessing) gcc -E hello.c -o hello.i .c 源文件 .i 预处理文件 • 展开所有宏定义(#define) • 处理#include指令,插入头文件内容 • 删除所有注释 • 处理条件编译(#ifdef等) • 添加行号和文件标识
编译 (Compilation) gcc -S hello.i -o hello.s .i 预处理文件 .s 汇编文件 • 将C代码翻译成汇编代码 • 进行语法检查和语义分析 • 进行代码优化 • 生成目标平台的汇编指令
汇编 (Assembly) gcc -c hello.s -o hello.o .s 汇编文件 .o 目标文件 • 将汇编代码转换为机器码 • 生成二进制目标文件 • 包含符号表和重定位信息 • 此时还不能直接执行
链接 (Linking) gcc -o hello hello.o .o 目标文件 可执行文件 • 链接所需的库文件(如libc.so) • 解析符号引用 • 重定位代码和数据段 • 生成最终可执行程序

💡 一步完成所有阶段

bash 复制代码
gcc -o hello hello.c  # 自动完成预处理→编译→汇编→链接

GCC 常用编译选项

常用选项 描述
-E 预处理
-S 编译
-c 汇编
-o 指定输出文件
-I(大小i) 指定头文件目录
-L 指定链接时库文件目录
-l(小写L) 指定链接哪一个库文件
-v 详细查看编译过程

多文件代码示例

c 复制代码
#include <stdio.h>
#include "name.h"

int main(int argc,char **argv)
{
    if(argc > 1)
    {
        printf("Hello, %s!\n", argv[1]);
    }
    else
    {
        printf("Hello, World!\n");
    }
    fun();
    return 0;
}
c 复制代码
#include <stdio.h>

void fun(void)
{
    printf("I am WSOZ\r\n");
}

此时多文件进行编译的话我们通常可以分成两种方法进行

  • 方法1
bash 复制代码
gcc -o hello hello.c name.c

直接一步到位,直接包含所有的文件即可,简单快速

  • 方法2
bash 复制代码
#分开汇编
gcc -c hello.c -o hello.o
gcc -c name.c -o name.o
#统一链接
gcc -o hello hello.o name.o

我们对多程序的情况下一般采取分开汇编,然后统一进行链接,此种方法在有少数文件需要修改的情况更加适用

动态库和静态库

库(Library)的作用:把通用功能封装起来复用,避免每个项目都重复写代码。

静态库(.a)作用

在链接阶段把库代码"拷贝"进你的可执行文件里。

  • 优点:部署简单(一个程序就能跑)、不怕目标机缺库
  • 缺点:可执行文件变大;多个程序各带一份,浪费存储/内存;库升级要重新编译程序

动态库(.so)作用

程序里只保留"引用",运行时再加载库。

  • 优点:可执行文件更小;多个程序可共享同一个库;升级库更方便
  • 缺点:运行依赖库文件和版本(可能出现"找不到so"或版本不匹配)

制作与使用库

对于库的制作,本质上就是将编译后的 .o 打包成对应格式,然后在链接阶段复用。

  • 第一步生成目标文件 .o(动态库建议加 -fPIC

    bash 复制代码
    gcc -fPIC -c name.c -o name.o
  • 第二步打包成静态库/动态库

    bash 复制代码
    # 动态库
    gcc -shared -o libmy.so name.o
    # 静态库
    ar crs libmy.a name.o

下面就是对于库的使用了,大致有两种方法

方法1:把库放到系统目录(如 /usr/local/lib

动态库和静态库都可以放进去;只是链接/运行行为不同。

bash 复制代码
# 安装到系统库目录(推荐 /usr/local/lib)
sudo cp libmy.so /usr/local/lib/
sudo cp libmy.a  /usr/local/lib/
sudo ldconfig

1)使用动态库(.so)

bash 复制代码
gcc -o hello hello.c -lmy
./hello

2)使用静态库(.a)

bash 复制代码
# 最直接:显式写静态库文件路径
gcc -o hello hello.c /usr/local/lib/libmy.a
./hello

方法2:不放系统目录,通过 -L 指定路径

1)使用动态库(.so)

bash 复制代码
# 链接阶段找到库
gcc -o hello hello.c -L. -lmy

# 运行阶段还要能找到 .so(2选1)
LD_LIBRARY_PATH=. ./hello
# 或者
gcc -o hello hello.c -L. -lmy -Wl,-rpath,'$ORIGIN'
./hello

2)使用静态库(.a)

bash 复制代码
# 最直接:显式写静态库文件路径
gcc -o hello hello.c ./libmy.a
./hello

关键区别

  • -L 只影响链接阶段;
  • .so 运行时还要能被系统找到;
  • .a 在链接时已拷贝进可执行文件,运行时不再依赖该库文件。
bash 复制代码
# 检查可执行文件依赖
ldd ./hello
相关推荐
xlq223222 小时前
26(下).库的理解与加载
linux·运维·服务器
wbs_scy2 小时前
Linux 动静态库完全指南:制作、使用、原理与实战
linux·运维·服务器
孙同学_2 小时前
【Linux篇】Socket编程TCP
linux·网络·tcp/ip
侯侯Hou2 小时前
Linux系统安装OpenClaw
linux
七七肆十九3 小时前
PTA 习题9-1 时间换算
c语言·算法
济6173 小时前
STM32F103 时钟系统从原理到实战:8MHz 到 72MHz 配置与 LED 闪烁实验---STM32 HAL库专栏
stm32·嵌入式·stm32hal库编程
charlie1145141913 小时前
2026年IMX6ULL正点原子Alpha开发板学习方案——U-Boot完全移植概览:从官方源码到你的自制板,这条路有多远
linux·学习·嵌入式·uboot·嵌入式linux·工程实践·编程指南
条tiao条3 小时前
从 “Top-K 问题” 入门二叉堆:C 语言从零实现与经典应用
c语言·算法·深度优先
Zevalin爱灰灰3 小时前
零基础入门学用物联网(ESP8266) 第一部分 基础知识篇(二)
单片机·物联网·嵌入式·esp8266