gcc 命令详解及最佳实践

article/2025/10/5 17:10:59

介绍

GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。

GCC 原名为 GNU C语言编译器,因为它原本只能处理 C 语言,但如今的 GCC 不仅可以编译 C、C++ 和 Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、Go 和 D 语言等等。

编译过程

GCC 的编译过程可以划分为四个阶段:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)以及链接(Linking)。

Linux 程序员可以根据自己的需要控制 GCC 的编译阶段,以便检查或使用编译器在该阶段的输出信息,帮助调试和优化程序。以 C 语言为例,从源文件的编译到可执行文件的运行,整个过程大致如下。

各文件后缀说明如下:

后缀描述后缀描述
.cC 源文件.s/.S汇编语言源文件
.C/.cc/.cxx/.cppC++ 源文件.o/.obj目标文件
.hC/C++ 头文件.a/.lib静态库
.i/.ii经过预处理的 C/C++ 文件.so/.dll动态库

语法

gcc [options] file...

选项

  • -pass-exit-codes :从一个阶段以最高错误代码退出。
  • --target-help :显示特定于目标的命令行选项。
  • --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...] :显示特定类型的命令行选项(使用 -v --help 显示子进程的命令行选项)。
  • -dumpspecs :显示所有内置规范字符串。
  • -dumpversion :显示编译器的版本。
  • -dumpmachine :显示编译器的目标处理器。
  • -print-search-dirs :显示编译器搜索路径中的目录。
  • -print-libgcc-file-name :显示编译器配套库的名称。
  • -print-file-name=<lib> :显示库 <lib> 的完整路径。
  • -print-prog-name=<prog> :显示编译器组件 <prog> 的完整路径。
  • -print-multiarch :显示目标的规范化 GNU 三元组,用作库路径中的一个组件。
  • -print-multi-directory :显示 libgcc 版本的根目录。
  • -print-multi-lib :显示命令行选项和多个库搜索目录之间的映射。
  • -print-multi-os-directory :显示操作系统库的相对路径。
  • -print-sysroot :显示目标库目录。
  • -print-sysroot-headers-suffix :显示用于查找标题的 sysroot 后缀。
  • -Wa,<options> :将逗号分隔的 <options> 传递给汇编器(assembler)。
  • -Wp,<options> :将逗号分隔的 <options> 传递给预处理器(preprocessor)。
  • -Wl,<options> :将逗号分隔的 <options> 传递给链接器(linker)。
  • -Xassembler <arg> :将 <arg> 传递给汇编器(assembler)。
  • -Xpreprocessor <arg> :将 <arg> 传递给预处理器(preprocessor)。
  • -Xlinker <arg> :将 <arg> 传递给链接器(linker)。
  • -save-temps :不用删除中间文件。
  • -save-temps=<arg> :不用删除指定的中间文件。
  • -no-canonical-prefixes :在构建其他 gcc 组件的相对前缀时,不要规范化路径。
  • -pipe :使用管道而不是中间文件。
  • -time :为每个子流程的执行计时。
  • -specs=<file> :使用 <file> 的内容覆盖内置规范。
  • -std=<standard> :假设输入源为 <standard>
  • --sysroot=<directory> :使用 <directory> 作为头文件和库的根目录。
  • -B <directory> :将 <directory> 添加到编译器的搜索路径。
  • -v :显示编译器调用的程序。
  • -### :与 -v 类似,但引用的选项和命令不执行。
  • -E :仅执行预处理(不要编译、汇编或链接)。
  • -S :只编译(不汇编或链接)。
  • -c :编译和汇编,但不链接。
  • -o <file> :指定输出文件。
  • -pie :创建一个动态链接、位置无关的可执行文件。
  • -I :指定头文件的包含路径。
  • -L :指定链接库的包含路径。
  • -shared :创建共享库/动态库。
  • -static :使用静态链接。
  • --help :显示帮助信息。
  • --version :显示编译器版本信息。

示例

阶段编译

假设有文件 hello.c,内容如下:

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

编译 hello.c,默认输出 a.out

gcc hello.c

编译 hello.c 并指定输出文件为 hello

gcc hello.c -o hello

只执行预处理,输出 hello.i 源文件

gcc -E hello.c -o hello.i

只执行预处理和编译,输出 hello.s 汇编文件

gcc -S hello.c

也可以由 hello.i 文件生成 hello.s 汇编文件

gcc -S hello.i -o hello.s

只执行预处理、编译和汇编,输出 hello.o 目标文件

gcc -c hello.c

也可以由 hello.i 或 hello.s 生成目标文件 hello.o

gcc -c hello.i -o hello.o
gcc -c hello.s -o hello.o

由 hello.o 目标文件链接成可执行文件 hello

gcc hello.o -o hello

使用静态库

创建一个 foo.c 文件,内容如下:

#include <stdio.h>void foo(void)
{printf("Here is a static library\n");
}

将 foo.c 编译成静态库 libfoo.a

gcc -c foo.c             # 生成 foo.o 目标文件
ar rcs libfoo.a foo.o    # 生成 libfoo.a 静态库

查看文件描述

$ file *
foo.c:    C source, ASCII text
foo.o:    ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
libfoo.a: current ar archive

修改 hello.c 文件,调用 foo 函数

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

编译 hello.c 并链接静态库 libfoo.a(加上 -static 选项)

gcc hello.c -static libfoo.a -o hello

也可以使用 -L 指定库的搜索路径,并使用 -l 指定库名

gcc hello.c -static -L. -lfoo -o hello

运行结果

$ ./hello
Hello, GetIoT
Here is a static library

查看 hello 文件描述

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=b72236c2211dd8f0c3003bc02ad5e70bb2354e8c, for GNU/Linux 3.2.0, not stripped

使用共享库

修改 foo.c 文件,内容如下:

#include <stdio.h>void foo(void)
{printf("Here is a shared library\n");
}

将其编译为动态库/共享库(由于动态库可以被多个进程共享加载,所以需要使用 -fPIC 选项生成位置无关的代码

gcc foo.c -shared -fPIC -o libfoo.so

hello.c 代码无需修改,内容仍然如下:

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

编译 hello.c 并链接共享库 libfoo.so

gcc hello.c libfoo.so -o hello

也可以使用 -L-l 选项指定库的路径和名称

gcc hello.c -L. -lfoo -o hello

但是此时运行 hello 程序失败

$ ./hello
./hello: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

原因是找不到 libfoo.so 共享库

$ ldd hellolinux-vdso.so.1 (0x00007fff5276d000)libfoo.so => not foundlibc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcc90fa7000)/lib64/ld-linux-x86-64.so.2 (0x00007fcc911bd000)

这是因为 libfoo.so 并不在 Linux 系统的默认搜索目录中,解决办法是我们主动告诉系统,libfoo.so 共享库在哪里。

方式一:设置环境变量 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$(pwd)

将 libfoo.so 所在的当前目录添加到 LD_LIBRARY_PATH 变量,再次执行 hello

$ ./hello
Hello, GetIoT
Here is a shared library

方式二:使用 rpath 将共享库位置嵌入到程序

gcc hello.c -L. -lfoo -Wl,-rpath=`pwd` -o hello

rpath 即 run path,是种可以将共享库位置嵌入程序中的方法,从而不用依赖于默认位置和环境变量。这里在链接时使用 -Wl,-rpath=/path/to/yours 选项,-Wl 会发送以逗号分隔的选项到链接器,注意逗号分隔符后面没有空格哦。

这种方式要求共享库必须有一个固定的安装路径,欠缺灵活性,不过如果设置了 LD_LIBRARY_PATH,程序加载时也是会到相应路径寻找共享库的。

方式三:将 libfoo.so 共享库添加到系统路径

sudo cp libfoo.so /usr/lib/

执行程序

$ ./hello
Hello, GetIoT
Here is a shared library

如果 hello 程序仍然运行失败,请尝试执行 ldconfig 命令更新共享库的缓存列表。

此时,再次查看 hello 程序的共享库依赖

$ ldd hellolinux-vdso.so.1 (0x00007ffecfbb1000)libfoo.so => /lib/libfoo.so (0x00007f3f3f1ad000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3f3efbb000)/lib64/ld-linux-x86-64.so.2 (0x00007f3f3f1d6000)

可以看到 libfoo.so 已经被发现了,其中 /lib 是 /usr/lib 目录的软链接。

示例代码可以在 GitHub 找到。



http://chatgpt.dhexx.cn/article/cpJnL4YW.shtml

相关文章

使用GCC编译程序常用命令

一、编译器驱动程序 首先梳理一下源文件到可执行文件的整个过程&#xff0c;下面是两个源文件的组成main.c和sum.c // main.c int sum(int *a, int n); int array[2] { 1, 2 }; int main() {int val sum(array, 2);return val; }// sum.c int sum(int *a, int n) {int i, s…

matlab 反向二值化,MATLAB:图像二值化、互补图(反运算)(im2bw,imcomplement函数)...

图像二值化、反运算过程涉及到im2bw&#xff0c;imcomplement函数&#xff0c;反运算可以这么理解&#xff1a;原本黑的区域变为白的区域&#xff0c;白的区域变为黑的区域。 实现过程如下&#xff1a; close all;%关闭当前所有图形窗口&#xff0c;清空工作空间变量&#xff0…

图像处理Matlab阈值的设置imadjust(),graythresh(),im2bw()函数使用

1、imadjust()函数调节图像的对比度(若图像较暗&#xff0c;可用imadjust函数命令来调节图像的对比度) I1imadjust(I,stretchlim(I),[0;1]); % stretchlim(I2)自适应找到一个分割阈值向量来改变一幅图像的对比度 figure,imshow(I1); 2、matlab中DIP工具箱函数im2bw使用阈值&…

MATLAB--对于im2bw函数的优化

由于我在研究的是uint8图像&#xff0c;所以对于优化im2bw函数的形式为&#xff1a;im2bw(uint8[], T)&#xff0c;不过其它形式也可以由类似思想导出。 测试代码&#xff1a;遍历8个图像得出时间 for n1:8cchar(str(n));fimread(c);testtime3%要测试的代码 end 算法一 tic fR…

MATLAB中将图像转换为二值图像im2bw

在MATLAB中将图像转换为二值图像&#xff0c;主要运用im2bw函数&#xff0c;涉及到一个灰度门槛的数值。 对于灰度图像 bwim2bw(I,level); level空着的话&#xff0c;默认是0.5。level一般使用graythresh函数来计算&#xff0c;至于graythresh函数中运用到的Otsus method&am…

matlab函数im2bw_图像分割之阈值分割(matlab)(转载)

转载自&#xff1a;https://blog.csdn.net/weixin_39824223/article/details/112249214 matlab函数im2bw_图像分割之阈值分割&#xff08;matlab&#xff09; weixin_39824223 2021-01-02 06:21:09 373 收藏 2 文章标签&#xff1a; matlab函数im2bw 图像分割是一种重要的…

MATLAB中im2bw函数-将图像转换为二值图像

matlab中DIP工具箱函数im2bw使用阈值&#xff08;threshold&#xff09;变换法把灰度图像&#xff08;grayscale image&#xff09;转换成二值图像。所谓二值图像&#xff0c; 一般意义上是指只有纯黑&#xff08;0&#xff09;、纯白&#xff08;255&#xff09;两种颜色的图像…

4、im2bw 和 imbinarize 的区别与图像分割的综合应用

1. im2bw 和 imbinarize 的区别 将图片转换为二值图有两个函数&#xff0c;分别为&#xff1a; bw imbinarize(g); 与 bw im2bw(g);在 matlab2018 中建议用 imbinarize 来将图片转换为二值图&#xff0c;其参数必须为灰度图。 在 matlab2016 中&#xff0c;只有 im2bw 函…

理解Kalman滤波的使用

Kalman滤波简介 Kalman滤波是一种线性滤波与预测方法&#xff0c;原文为&#xff1a;A New Approach to Linear Filtering and Prediction Problems。文章推导很复杂&#xff0c;看了一半就看不下去了&#xff0c;既然不能透彻理解其原理&#xff0c;但总可以通过实验来理解其具…

卡尔曼滤波(Kalman Filtering)——(6)MATLAB仿真(保姆级)

MATLAB仿真 一、卡尔曼滤波的实际应用二、流程图三、执行过程四、程序代码五、仿真结果参考文献 一、卡尔曼滤波的实际应用 在这里依旧以前面提到的测量硬币为例进行MATLAB仿真。现有一枚硬币为了这枚硬币的直径&#xff0c;我们进行了多次测量&#xff0c;但是所使用的的尺子存…

Kalman Filter 遇到 Deep Learning : 卡尔曼滤波和深度学习有关的论文

突然心血来潮&#xff0c;想到卡尔曼滤波器是否能和深度学习结合。于是从谷歌学术上搜了一下&#xff0c;发现现在这方面的工作还没有太多结合。Top 期刊 TNNLS 2021 有一篇最新工作。ICLR 2020 出现一篇 Kalman Filter Is All You Need 的文章&#xff0c;但目前从开源的审稿意…

目标跟踪:卡尔曼滤波(Kalman Filter)到底是怎么工作的?

Kalman filter到底是怎么工作的&#xff1f; 本文主要参考的文章&#xff1a;https://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/&#xff0c;图片也基本来自上述博客 其实接触KF已经很久了&#xff0c;听过对应的课程&#xff0c;也对着公式进行过推导&#x…

卡尔曼滤波(kalman)

卡尔曼&#xff08;kalman&#xff09;滤波原理 kalman滤波器可以看做状态变量在由观测生成的线性空间上的射影。 如下状态空间模型描述的动态系统&#xff1a; (1) ​​​​​​​ ​​​​​​​ (2) 式中&#xff0c;k为离散时间&#xff…

卡尔曼滤波(Kalman filter)及预测

参考文章&#xff1a;https://blog.csdn.net/baidu_38172402/article/details/82289998; https://www.jianshu.com/p/2768642e3abf kalman滤波的作用&#xff1a;1.数据 滤波&#xff1b;2.数据预测 3.数据融合。其基本原理&#xff1a;是通过协方差 来进行加权。 1.什么是…

【Kalman】卡尔曼滤波Matlab简单实现

本节卡尔曼滤波Matlab实现是针对线性系统估计的&#xff0c;仅为简单仿真。 1.离散时间线性动态系统的状态方程 线性系统采用状态方程、观测方程及其初始条件来描述。线性离散时间系统的一般状态方程可描述为 其中&#xff0c;X(k) 是 k 时刻目标的状态向量&#xff0c;V(k)…

学习OpenCV——Kalman滤波

背景&#xff1a; 卡尔曼滤波是一种高效率的递归滤波器(自回归滤波器), 它能够从一系列的不完全及包含噪声的测量中&#xff0c;估计动态系统的状态。卡尔曼滤波的一个典型实例是从一组有限的&#xff0c;包含噪声的&#xff0c;对物体位置的观察序列&#xff08;可能有偏差&a…

卡尔曼滤波Kalman Filtering:介绍

本文是Quantitative Methods and Analysis: Pairs Trading此书的读书笔记。 控制理论(control theory&#xff09;是工程学的分支之一&#xff0c;主要应对工程系统控制的问题。比如控制汽车发动机的功率输出&#xff0c;稳定电动机的转速&#xff0c;控制“反应速率”&#x…

kalman 滤波 演示与opencv代码

在机器视觉中追踪时常会用到预测算法&#xff0c;kalman是你一定知道的。它可以用来预测各种状态&#xff0c;比如说位置&#xff0c;速度等。关于它的理论有很多很好的文献可以参考。opencv给出了kalman filter的一个实现&#xff0c;而且有范例&#xff0c;但估计不少人对它的…

Ensemble Kalman filter集合卡尔曼滤波

在气象预测领域&#xff0c;很多时候&#xff0c;模型具有 O ( 10 e 8 ) O(10e8) O(10e8)以上的量级&#xff0c;如果使用传统的卡尔曼滤波&#xff0c;协方差矩阵的更新将是一个~ 10 e 22 10e22 10e22量级的计算操作&#xff0c;因此传统的卡尔曼滤波并不适用。集合卡尔曼滤波…

Kalman滤波MATLAB实现实例——在温度测量中的应用

参考&#xff1a;《卡尔曼滤波原理及应用MATLAB仿真》 原理介绍 假设我们要研究的对象是一个房间的温度。根据经验判断,这个房间的温度大概在25℃左右,可能受空气流通、阳光等因素影响,房间内温度会小幅度地波动。我们以分钟为单位,定时测量房间温度,这里的1分钟,可以理解为采…