gcc编译

这篇具有很好参考价值的文章主要介绍了gcc编译。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、GCC简介

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):生成 .i 的文件[预处理器cpp]
  • 编译(Compiling):  将预处理后的文件转换成汇编语言, 生成文件 .s [编译器egcs]
  • 汇编(Assembling):  由汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as]
  • 链接生成可执行文件(Linking) [链接器ld]
gcc编译

 

安装:
# 安装c编译器(linux需安装python-devel, gcc)
centos: yum install python-devel  gcc
ubuntu: apt-get install build-essential

二、GCC使用

nist@zq-node2:~/test$ gcc --help
Usage: gcc [options] file...
Options:
  -pass-exit-codes         从一个阶段以最高错误代码退出.
  --help                   Display this information.
  --target-help            显示特定于目标的命令行选项.
  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...].
                           显示特定类型的命令行选项.
  (使用 '-v --help' 显示子进程的命令行选项).
  --version                显示编译器版本信息.

  -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 显示用于查找headers的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>    使用<standard>作为headers和libraries的根目录.
  -B <directory>           将 <directory> 添加到编译器的搜索路径.

  -v                       显示编译器调用的程序.
  -###                     与 -v 类似,但引用的选项和命令不执行.
  -E                       仅执行预处理(不要编译、汇编或链接).
  -S                       只编译(不汇编或链接).
  -c                       编译和汇编,但不链接.
  -o <file>                指定输出文件. gcc 编译出来的文件默认是 a.out
  -pie                     创建一个动态链接、位置无关的可执行文件
  -shared                  创建共享库/动态库.
  -g:                     生成调试信息
  -w:                       不生成任何警告
  -Wall:                    编译时 显示Warning警告,但只会显示编译器认为会出现错误的警告
  -x <language>         指定以下输入文件的语言。允许的语言包括:c c++汇编程序none“none”表示恢复到的默认行为根据文件的扩展名猜测语言。
Options starting with -g, -f, -m, -O, -W, or --param are automatically
 passed on to the various sub-processes invoked by gcc.  In order to pass
 other options on to these processes the -W<letter> options must be used.
For bug reporting instructions, please see:
<file:///usr/share/doc/gcc-9/README.Bugs>.


-shared:
编译动态库时要用到
-pthread:
在Linux中要用到多线程时,需要链接pthread库
-fPIC:
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
-fwrapv:
它定义了溢出时候编译器的行为——采用二补码的方式进行操作
-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的
-O2:
会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。
-O3: 在O2的基础上进行更多的优化
-Wall:
编译时 显示Warning警告,但只会显示编译器认为会出现错误的警告
-fno-strict-aliasing:
“-fstrict-aliasing”表示启用严格别名规则,“-fno-strict-aliasing”表示禁用严格别名规则,当gcc的编译优化参数为“-O2”、“-O3”和“-Os”时,默认会打开“-fstrict-aliasing”。
-I (大写的i):
是用来指定头文件目录
-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include
-l:
-l(小写的 L)参数就是用来指定程序要链接的库,-l参数紧接着就是库名,把库文件名的头lib和尾.so去掉就是库名了,例如我们要用libtest.so库库,编译时加上-ltest参数就能用上了

2.1、gcc编译的四个步骤 

(10条消息) Linux下gcc命令详解_linux gcc_ENSHADOWER的博客-CSDN博客
预处理:            gcc -E Test.c -o Test.i    # -E选项,可以让编译器在预处理后停止,并输出预处理结果
编译:              gcc -S Test.i -o Test.s    # -S选项,表示在程序编译期间,将我们的代码编译成汇编语言。
汇编:              gcc -c Test.s -o Test.o    # -c选项,表示由汇编器负责将刚才的.s文件编译为目标文件,即计算机所能识别的序列。
链接生成可执行文件: gcc Test.o -o Test         # 将刚才的Test.o文件与C标准输入输出库进行连接,最终生成程序Test可执行文件

2.2、多源文件的编译方法

[假设有两个源文件为test.c和testfun.c]
1. 多个文件一起编译
用法:
gcc testfun.c test.c -o test

作用:将testfun.c和test.c分别编译后链接成test可执行文件。文章来源地址https://www.toymoban.com/news/detail-464155.html

2. 分别编译各个源文件,之后对编译后输出的目标文件链接
用法:
gcc -c testfun.c -o testfun.o    # 将testfun.c编译成testfun.o
gcc -c test.c -o test.o           # 将test.c编译成test.o
gcc -o testfun.o test.o -o test    # 将testfun.o和test.o链接成test
以上两种方法相比较,第一中方法编译时需要所有文件重新编译,而第二种方法可以只重新编译修改的文件,未修改的文件不用重新编译
   

2.3、库文件连接

开发软件是需要依赖第三方函数库。
函数库实际上就是一些头文件(.h)和库文件(so、或lib、dll)的集合
虽然Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下;Windows所使用的库文件主要放在Visual Stido的目录下的include和lib,以及系统文件夹下。但也有的时候,我们要用的库不再这些目录下,所以GCC在编译时必须用自己的办法来查找所需要的头文件和库文件。
例如我们的程序test.c是在linux上使用c连接mysql,这个时候我们需要去mysql官网下载MySQL Connectors的C库,下载下来解压之后,有一个include文件夹,里面包含mysql connectors的头文件,还有一个lib文件夹,里面包含二进制so文件libmysqlclient.so
其中inclulde文件夹的路径是/usr/dev/mysql/include,lib文件夹是/usr/dev/mysql/lib
gcc编译
静态库链接时搜索路径顺序:
  1. ld会去找GCC命令中的参数-L
  2. 再找gcc的环境变量LIBRARY_PATH
  3. 再找内定目录 /lib、  /usr/lib、   /usr/local/lib 这是当初compile gcc时写在程序内的
动态链接时、执行时搜索路径顺序:
  1. 编译目标代码时指定的动态库搜索路径
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
  4. 默认的动态库搜索路径/lib
  5. 默认的动态库搜索路径/usr/lib
有关环境变量:
  • LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
  • LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

三、示例

3.1、阶段编译

假设有文件 hello.c,内容如下
#include <stdio.h>

int main(void)
{
    printf("Hello, GetIoT\n");
    return 0;
}
1、编译 hello.c,默认输出 a.out
gcc hello.c
编译 hello.c 并指定输出可执行文件为 hello
gcc hello.c -o hello
gcc编译
2、只执行预处理,输出 hello.i 源文件
gcc -E hello.c -o hello.i
3、只执行预处理和编译,输出 hello.s 汇编文件
gcc -S hello.c -o hello.s
也可以由 hello.i 文件生成 hello.s 汇编文件
gcc -S hello.i -o hello.s
4、只执行预处理、编译和汇编,输出 hello.o 目标文件
gcc -c hello.c -o hello.o
也可以由 hello.i 或 hello.s 生成目标文件 hello.o:
gcc -c hello.i -o hello.o
gcc -c hello.s -o hello.o
5、由 hello.o 目标文件链接成可执行文件 hello
gcc hello.o -o hello

3.2、使用静态库

创建一个 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 静态库
gcc编译
查看文件描述
$ file *
gcc编译
修改 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
gcc编译
运行结果:
$ ./hello
gcc编译
查看 hello 文件描述
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=f20be3e93d3c316877bbe4292f5ee7e06cf77f27, for GNU/Linux 3.2.0, not stripped

3.3、使用共享库

修改 foo.c 文件,内容如下
#include <stdio.h>

void foo(void)
{
    printf("Here is a shared library\n");
}
将其编译为动态库/共享库(由于动态库可以被多个进程共享加载,所以需要使用 -fPIC 选项生成位置无关的代码
gcc foo.c -shared -fPIC -o libfoo.so
gcc编译
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 hello
linux-vdso.so.1 (0x00007fff5276d000)
libfoo.so => not found
libc.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 hello
linux-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  找到。

到了这里,关于gcc编译的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ARM交叉编译工具链 gcc-arm-none-eabi

    1,交叉编译工具链简介 (1)命令规则 交叉编译工具链的命名规则为:arch [-vendor] [-os] [-(gnu)eabi] arch – 体系架构ÿ

    2024年03月25日
    浏览(45)
  • Linux工具【1】(编辑器vim、编译器gcc与g++)

    vim(vi improved)编辑器是从 vi 发展出来的一个文本编辑器。 代码补全、编译及错误跳转、语法高亮等方便编程的功能特别丰富,在程序员中被广泛使用。 vim 可以说是程序开发者的一项很好用的工具,它更是一个程序开发工具而不只是文字处理软件。 在vim中编辑代码可以使程

    2024年02月15日
    浏览(34)
  • 在Lniux中编译代码的工具 —— vim和gcc/g++的使用

    目录 🌈前言 📁1. 什么是vim 📁2. vim的使用 vim的基本操作: 📁3. 命令模式下的命令集 📁4. 底行模式下的命令集 📁5. vim的个性设置  📁6. gcc/g++的使用 📁 扩展:程序从编译到运行的翻译过程 预处理(进行宏替换): 编译(生成汇编): 汇编(生成机器可识别代码):

    2024年02月20日
    浏览(21)
  • 交叉编译工具 aarch64-linux-gnu-gcc 的介绍与安装

    AArch64 是随 ARMv8 ISA 一起引入的 64 位架构,用于执行 A64 指令的计算机。而且在 AArch64 状态下执行的代码只能使用 A64 指令集。,而不能执行 A32 或 T32 指令。但是,与 AArch32 中不同,在64位状态下,指令可以访问 64 位和 32 位寄存器。 aarch64-linux-gnu-gcc 是一个交叉编译工具链,可

    2024年04月14日
    浏览(37)
  • 1762_gcc编译c语言makefile自动生成工具的Perl实现

    全部学习汇总: GreyZhang/g_makefile: Learn makefile from all kinds of tutorials on the web. Happy hacking and let\\\'s find an common way so we may don\\\'t need to touch makefile code any more! (github.com)          前阵子实现了一个CodeWarrior嵌入式开发环境的自动编译环境,用的基本上是Python。说起来,我觉得那个环

    2024年02月12日
    浏览(65)
  • 下载较老版本或最新版本的ARM Linux gcc 交叉编译工具链

    如果开发的 ARM 平台比较的多,需要多个版本的 arm gcc 交叉编译工具链,那么如何获取较新版本的 arm gcc 交叉编译工具链呢? 速度较快的,也比较新的,就到 ARM 官方网站下载 下载地址: https://developer.arm.com/downloads/-/gnu-a GNU-A Downloads 最新的下载地址: https://developer.arm.com/do

    2024年02月14日
    浏览(39)
  • 【探索Linux】—— 强大的命令行工具 P.4(编译器 gcc/g++ 使用)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim ,也相信大家都掌握的不错,今天博主带大家了解一下Linux编译器 gcc/g++ 使用, 下面话不多说坐稳扶好咱们要开车了!!

    2024年02月12日
    浏览(44)
  • linux下使用gcc编译工具出现“命令未找到”或“没有那个文件或目录”等提示

    在linux系统中使用gcc编译工具对C程序进行编译时,报错显示“gcc命令未找到”或“没有那个文件或目录”,而此时你确定已经安装了gcc编译工具,这大概率是因为系统未能找到gcc命令的安装位置所导致的,需要将gcc的安装路径添加到PATH环境变量中,解决方法如下:        

    2024年02月08日
    浏览(39)
  • 编译工具链 之四 ARM-MDK、IAR、GCC 的 .MAP 文件、.LST 文件

       .map 文件和 .lst 文件是嵌入式开发中最有用的俩调试辅助文件。现在主要从事 RISC-V 架构,主要与 GCC 打交道,今天就重点学习一下 GCC 的 .map 文件、 .lst 文件,并辅助以 ARMCC 和 IAR 作为对比。   本文中的 DEMO 主要是使用 https://gitee.com/itexp/STM32_BareMetal 这个代码,其中配

    2024年01月19日
    浏览(70)
  • 【Linux】Linux编译器-gcc/g++ && Linux项目自动化构建工具-make/Makefile

    目录 Linux编译器-gcc/g++使用 1.背景知识  Linux中头文件的目录在 Linux 库 条件编译的典型应用 2.gcc如何完成 动态库 vs 静态库 debug release Linux项目自动化构建工具-make/Makefile 背景 用法 特殊符号  预处理(去注释,头文件展开,条件编译,宏替换) 编译(生成汇编) 汇编(生成

    2024年02月20日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包