Linux GCC编译器使用

gcc编译器

gcc的工作流程

gcc编译器将c源文件到生成一个可执行程序,中间一共经历了四个步骤:在这里插入图片描述
四个步骤并不是gcc独立完成的,而是在内部调用了其他工具,从而完成了整个工作流程, 其中编译最耗时, 因为要逐行检查语法.
在这里插入图片描述
下面以test.c为例介绍gcc的四个步骤:

## 预处理
gcc -E test.c -o test.i
## 编  译
gcc -S test.i -o test.s
## 汇  编
gcc -c test.s -o test.o
# 链  接
gcc test.o -o test

一步生成最终的可执行程序:

gcc test.c -o test

gcc常用参数

  • -v 查看gcc版本号, --version也可以
  • -E 生成预处理文件
  • -S 生成汇编文件
  • -c 只编译, 生成.o文件, 通常称为目标文件
  • -I 指定头文件所在的路径
  • -L 指定库文件所在的路径
  • -l 指定库的名字
  • -o 指定生成的目标文件的名字
  • -g 包含调试信息, 使用gdb调试需要添加-g参数
  • -On n=0∼3 编译优化,n越大优化得越多

例如:下面代码片段

int a = 10;
int b = a;
int c = b;
printf("%d", c);

上面的代码可能会被编译器优化成:

int c = 10;
printf("%d", 10);

-Wall提示更多警告信息

int a;
int b;
int c = 10;
printf([%d]\n”, c);

编译如下:

gcc -o test -Wall test.c
warning: unused variable ‘b’ [-Wunused-variable]
warning: unused variable ‘a’ [-Wunused-variable]

-D编译时定义宏
test.c文件中的代码片段: printf("MAX==[%d]\n", MAX);
编译:

gcc -o test test.c -D MAX=10
gcc -o test test.c -DMAX=10

Linux静态库和共享(动态)库

库的介绍

库是二进制文件, 是源代码文件的另一种表现形式, 是加了密的源代码; 是一些功能相近或者是相似的函数的集合体.

使用库有什么好处

  • 提高代码的可重用性, 而且还可以提高程序的健壮性;
  • 可以减少开发者的代码开发量, 缩短开发周期.

库制作完成后, 如何给用户使用

  • 头文件—包含了库函数的声明
  • 库文件—包含了库函数的代码实现

注意:

库不能单独使用, 只能作为其他执行程序的一部分完成某些功能, 也就是说只能被其他程序调用才能使用.

库可分静态库(static library)和共享库(shared library)

静态库(static library)

静态库可以认为是一些目标代码的集合, 是在可执行程序运行前就已经加入到执行码中, 成为执行程序的一部分. 按照习惯, 一般以.a做为文件后缀名.

静态库的命名一般分为三个部分

  • 前缀:lib
  • 库名称:自定义即可, 如test
  • 后缀:.a

所以最终的静态库的名字应该为:libtest.a

静态库的制作

下面以fun1.c , fun2.chead.h三个文件为例讲述静态库的制作和使用, 其中head.h文件中有函数的声明, fun1.cfun2.c中有函数的实现.

  • 步骤1:将c源文件生成对应的.o文件 gcc -c fun1.c fun2.c 或者分别生成.o文件:

head.h

void fun1();
void fun2();

fun1.c

#include <stdio.h>
void fun1()
{
    printf("this is fun1\n");	
}

fun2.c

#include <stdio.h>
void fun2()
{
    printf("this is fun2\n");	
}
gcc -c fun1.c -o fun1.o
gcc -c fun2.c -o fun2.o
  • 步骤2:使用打包工具ar将准备好的.o文件打包为.a文件
    • 在使用ar工具是时候需要添加参数rcs, r更新、c创建、s建立索引
  • 命令:ar rcs 静态库名 .o文件 , ar rcs libtest1.a fun1.o fun2.o
    在这里插入图片描述

静态库的使用

静态库制作完成之后, 需要将.a文件和头文件一定发布给用户.
假设测试文件为main.c, 静态库文件为libtest1.a, 头文件为head.h
用到的参数:

  • -L:指定要连接的库的所在目录
  • -l:指定链接时需要的静态库, 去掉前缀和后缀
  • -I: 指定main.c文件用到的头文件head.h所在的路径;gcc -o main1 main.c -L./ -ltest1 -I./

main.c

#include <stdio.h>
#include <stdlib.h>
#include "head.h"

int main(int argc, char *argv[])
{
	printf("this is main!\n");

	fun1();
	fun2();

	return 0;
}

静态库的优缺点

优点:

  • 函数库最终被打包到应用程序中,实现是函数本地化,寻址方便、速度快。(库函数调用效率==自定义函数使用效率)
  • 程序在运行时与函数库再无瓜葛,移植方便。

缺点:

  • 消耗系统资源较大, 每个进程使用静态库都要复制一份, 无端浪费内存。

在这里插入图片描述

  • 静态库会给程序的更新、部署和发布带来麻烦。如果静态库libxxx.a更新了,所有使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载)。

共享库(shared library)/动态库

共享库在程序编译时并不会被连接到目标代码中, 而是在程序运行是才被载入. 不同的应用程序如果调用相同的库, 那么在内存里只需要有一份该共享库的拷贝, 规避了空间浪费问题.
动态库在程序运行时才被载入, 也解决了静态库对程序的更新、部署和发布会带来麻烦. 用户只需要更新动态库即可, 增量更新. 为什么需要动态库, 其实也是静态库的特点导致.
按照习惯, 一般以.so做为文件后缀名. 共享库的命名一般分为三个部分:

  • 前缀:lib
  • 库名称:自己定义即可, 如test
  • 后缀:.so

所以最终的静态库的名字应该为:libtest.so

在这里插入图片描述

共享库的制作

  1. 生成目标文件.o, 此时要加编译选项:-fPIC(fpic);
    gcc -fpic -c fun1.c fun2.c
    参数:-fpic创建与地址无关的编译程序(pic, position independent code), 目的就是为了能够在多个应用程序间共享.
  2. 生成共享库, 此时要加链接器选项: -shared(指定生成动态链接库)
    gcc -shared fun1.o fun2.o -o libtest2.so

查看共享库中内容

nm libtest2.so

在这里插入图片描述

共享库的使用

引用动态库编译成可执行文件(跟静态库方式一样):
用到的参数:

  • -L:指定要连接的库的所在目录
  • -l:指定链接时需要的动态库, 去掉前缀和后缀
  • -I: 指定main.c文件用到的头文件head.h所在的路径
    gcc main.c -I./ -L./ -ltest2 -o main2
    然后运行:./main2,发现竟然报错了.
    在这里插入图片描述
分析为什么在执行的时候找不到libtest2.so
  • 当系统加载可执行代码时候, 能够知道其所依赖的库的名字, 但是还需要知道所依赖的库的绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。

ldd命令可以查看可执行文件依赖的库文件, 执行ldd main2, 可以发现libtest2.so找不到.
在这里插入图片描述

  • 对于elf格式的可执行程序,是由ld-linux.so*来完成的, 它先后搜索elf文件的 DT_RPATH段(不能修改) — 环境变量LD_LIBRARY_PATH — /etc/ld.so.cache文件列表 — /lib/, /usr/lib目录找到库文件后将其载入内存。

使用file命令可以查看文件的类型: file main2,显示为可执行类型
在这里插入图片描述

如何让系统找到共享库

  • 拷贝自己制作的共享库到/lib或者/usr/lib
  • 临时设置LD_LIBRARY_PATH: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径
  • 永久设置(推荐使用此方式,只对当前用户生效), 把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径, 设置到∼/.bashrc文件中, 然后再执行下列三种办法之一:
    • 执行. ~/.bashrc使配置文件生效(第一个.后面有一个空格)
    • 执行source ~/.bashrc配置文件生效
    • 退出当前终端, 然后再次登陆也可以使配置文件生效
  • 永久设置,把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径,设置到/etc/profile文件中
  • 将其添加到 /etc/ld.so.cache文件中
    • 编辑/etc/ld.so.conf文件, 加入库文件所在目录的路径
    • 运行sudo ldconfig -v, 该命令会重建/etc/ld.so.cache文件
      解决了库的路径问题之后, 再次ldd命令可以查看可执行文件依赖的库文件,ldd main2:

etc目录下为系统级别的配置文件,修改后会影响所有用户,不建议修改

在这里插入图片描述
总结

  • 动态库文件在编译的时候, 连接器需要使用参数-L找到库文件所在的路径;

  • 在执行的时候, 是加载器ldd根据动态库的路径进行加载的, 与编译的时候用的-L指定的路径无关.

  • 最常用的解决办法:将LD_LIBRARY_PATH环境变量加到用户级别的配置文件~/.bashrc中, 然后生效(. ~/.bashrc 或 source ~/.bashrc 退出终端然后再登录)

共享库的特点

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单。
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux 中的 GCC 编译器使用方法如下: 1. 安装 GCC 编译器: 使用终端输入 `sudo apt-get install gcc` 命令进行安装。 2. 编写源代码: 使用文本编辑器编写 C/C++ 源代码。 3. 编译源代码: 使用终端输入 `gcc -o 程序名 源代码名` 命令进行编译。 4. 运行程序: 使用终端输入 `./程序名` 命令运行程序。 例如: ``` $ gcc -o hello hello.c $ ./hello ``` 其中 -o 参数是指定生成的可执行文件的名称,如果不加-o参数默认生成 a.out 文件 有关 GCC 编译器的更多使用方法,请输入 `gcc --help` 命令查看。 ### 回答2: gcc是GNU Compiler Collection (GNU编译器系列)的缩写,它是一个自由软件的编译器,支持多种编程语言,包括C、C++、Objective-C、Fortran、Ada、以及Java。它是Linux系统中常用的编译器之一。 在Linux系统中使用gcc编译器可以通过命令行完成。首先需要在终端中打开一个文本编辑器,创建并保存源代码文件,文件名以“.c”为扩展名。接着进入终端,使用cd命令进入到源代码文件所在的目录,然后使用gcc命令进行编译。 例如: gcc hello.c -o hello 其中,hello.c是源代码文件名,-o表示输出文件名,后面的hello则是输出文件的名称。 在编译过程中,还可以在命令后添加一些选项,以对编译参数进行设置。例如,使用-Wall选项可以开启编译器的所有警告提示,使用-g选项可以生成调试信息,方便调试程序。 例如: gcc -Wall -g hello.c -o hello 除了以上的基本命令之外,还可以通过man gcc命令查看手册,了解更多的编译命令行参数和选项的用法。当然,对于大型项目的编译,一些高级的IDEs也可以辅助完成编译工作。 ### 回答3: GCC(Gnu C Compiler)是Linux系统下的一个著名的编译器,它是GNU编译器套件(GNU Compiler Collection)的一部分,支持多种语言的编译,如C、C++、Objective-C、Fortran、Ada等。 GCC安装 通常,GCC已经预装在大多数Linux发行版中,如果没有安装,可以使用以下命令进行安装: - Ubuntu/Debian:sudo apt-get install gcc - Fedora/CentOS:sudo yum install gcc - Arch:sudo pacman -S gcc GCC编译 使用GCC编译源代码时,首先需要将源代码保存在一个文件中。以C语言为例,假设有一个main.c文件,可以使用以下命令进行编译: gcc main.c -o main 其中,-o选项指定编译后的可执行文件名为main。如果编译成功,将生成一个名为main的可执行文件。 GCC编译时还可以使用其他选项,如-Wall选项可以开启所有警告信息,-g选项可以为代码添加调试信息。 GCC链接库 在Linux系统中,经常需要使用外部库,例如数学库、字符串处理库、网络库等,GCC支持链接这些库以方便在程序中使用。以链接数学库为例: gcc main.c -o main -lm 其中,-lm指定链接数学库。 GCC优化选项 GCC提供了多种编译优化选项,可以使编译后的代码更快、更小。以下是一些常用的优化选项: - -O0:关闭所有优化。 - -O1:启用基本优化,但不会增加代码大小。 - -O2:启用更多优化,可能会增加代码大小。 - -Os:优化代码大小,启用尽可能多的优化选项。 使用GCC时,需要根据具体情况来选择适合的优化选项。 总的来说,GCCLinux系统中一个非常重要的编译器,学会使用GCC可以更好地编写和调试程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值