GNU编译工具-GCC

1.GCC

GCC全称:**GNU编译器套件(GNU Compiler Collection)**包括C、C++、Objective-C、Fortran、Java、Ada和Go语言的前端,也包括了这些语言的库(如libstdc++、libgcj等等)。

2.编译四个阶段

编译目的是将源程序(文本)生成可执行的目标文件(二进制),其一般包括四个阶段:预处理—— >编译—— >汇编—— >链接。
在这里插入图片描述
hello.c

#include <stdio.h>
int main()
{
	printf("hello\n");
	return 0;
}
2.1预处理阶段

将头文件编译进来,还有完成宏的替换。可以通过指定gcc的-E选项来查看。
命令:unix : gcc -E hello.c -o hello.i
作用:将hello.c预处理并输出为hello.i

2.2编译阶段

这个阶段编译器主要做词法分析、语法分析、语义分析等,在检查无错误后后,把代码翻译成汇编语言。可通过gcc的-S选项来查看,生成汇编代码。
命令: gcc -S hello.i -o hello.s
作用:将hello.i汇编成hello.s

2.3汇编阶段

这个阶段将汇编文件翻译成机器语言,生成二进制目标文件。可以使用-c选项,这个.o文件无法使用文本查看器来查看,因为它是二进制文件。
命令:gcc -c hello.s -o hello.o
作用:将hello.s转成hello.o

2.4链接阶段

此阶段会链接hello.c中用到的库函数,比如用到了printf库函数,就会去/usr/lib文件夹下查找libc库(下面会详细解释),找到后将printf.o链接进来,最终生成了可执行文件。
命令:gcc hello.o -o hello
作用:将hello.o与printf.o链接,并生成可执行文件helllo

3.g++与gcc

简单理解
gcc是GCC中的GUN C Compiler(C 编译器)
g++是GCC中的GUN C++ Compiler(C++编译器)
但本质上gcc和g++并不是编译器,只是一种驱动器,在执行时根据文件类型调用不同编译器。
g++与gcc的主要区别是:

  • 对于 .c和.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)
  • 对于 .c和.cpp文件,g++则统一当做cpp文件编译
  • 使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL
  • gcc在编译C文件时,可使用的预定义宏是比较少的
  • gcc在编译cpp文件时/g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器),会加入一些额外的宏
  • 在用gcc编译c++文件时,为了能够使用STL,需要加参数 –lstdc++ ,但这并不代表 gcc –lstdc++ 和 g++等价,它们的区别不仅仅是这个

4.gcc使用

4.1基本使用

gcc和g++的基本使用上类似,下面只介绍gcc的使用。
gcc使用一般格式: gcc [选项] 要编译的文件 [选项] [目标文件] ,其中,目标文件可缺省,gcc默认生成的可执行文件名为:a.out。可以编译一个文件,也可以同时编译多个文件。gcc的主要几个选项如下:

  • g - turn on debugging (so GDB gives morefriendly output)
  • -Wall - turns on most warnings
  • -O or -O2 - turn on optimizations
  • -o - name of the output file
  • -c - output an object file (.o)
  • -I - specify an includedirectory
  • -L - specify a libdirectory
  • -l - link with librarylib.a

比如:
gcc hello.c 生成可执行文件a.out。
gcc -c hello.c 生成目标文件hello.o
gcc -o hello hello.c 生成可执行文件hello。
gcc -o hello helloa.c hellob.c main.c生成可执行文件hello(假设main中用到了helloa和hellob中定义的函数)。
g++ -std=c++11 hello.cpp 打开支持c++11标准生成可执行文件a.out。

4.2头文件和库文件的查找

头文件的查找规则如下:

  • 系统头文件根据gcc -I参数指定的路径查找
  • 用户自定义头文件在当前目录查找
  • 根据环境变量设置查找:
    – C_INCLUDE_PATH:c语言头文件路径
    – CPLUS_INCLUDE_PATH:c++头文件路径
  • 去系统默认路径下查找:
    – /usr/include
    – /usr/local/include

库文件类似:

  • 根据gcc -L参数查找
  • 根据环境变量查找
    – LIBRARY_PATH
  • 去系统默认路径查找
    –/usr/lib
    –/usr/local/lib
4.3静态库 .a

静态库就是当目标文件和库文件链接时,目标文件中所使用的所有库的机器码将被拷贝到最终生成的可执行文件中,缺点是占用磁盘和内存空间。

1.编译静态库

gcc -c -static hello.c -o hello.o
指定-static选项生成目标文件。
ar -rc libhello.a hello.o
使用ar命令将创建libhello.a并将hello.o放入其中,可以同时插入多个目标文件。
库的名字必须以lib开头,否则链接库时找不到。

2.使用静态库
  • 库的使用需要在gcc选项中指定,例如:(假设libhello.a在当前目录)
    gcc main.c -o main -lhello -L .
  • 需要指定 -l参数后面跟库名(除去lib剩余的部分),任何包含某函数定义的库文件必须位于调用该函数的目标文件之后
  • 还要用 -L参数指出库所在的路径,也可以不在gcc命令中显式指定,而直接设置环境变量LIBRARY_PATH
  • 除了c标准库libc,其余的库都需要指定 -l
  • gcc连接 c++程序需要指定 -lstdc++,g++则不需要指定。
4.4共享库 .so
1.编译共享库

编译共享库分两步,首先编译成位置独立的目标文件(选项-fpic),然后再编译成共享库(选项-shared)
gcc -c -fpic hello.c
gcc -shared hello.o -o libhello.so
等同于:
gcc -fpic -shared -c hello.c -o libhello.so

2.使用共享库

使用动态库方法有两种,一种是直接编译(gcc优先使用动态库,如果指定使用静态库,需要加-static选项),另一种是动态加载,需要用到下面四个函数:

#include<dlfcn.h>
void *dlopen(const char *filename,int flag);
char *dlerror(void);
void *dlsym(void *handle,const char *symbol);
int dlclose(void *handle);

dlopen 打开共享库,返回指向该共享库的指针,flag参数有两个:
RTLD_LAZY:符号查找时加载。
RTLD_NOW:马上加载。
dlsym使用共享库中的某个函数,handle设置为dlopen返回的指针,symbol是要调用的函数名字,返回指向该函数的指针。

编译时使用共享库与使用静态库一样。

linux环境下的动态库一般名为libxxx.so,用ldd命令分析某个可执行程序,可以看到该程序依赖哪些动态库,以及路径。 如 ldd ./test
linux-vdso.so.1 => (0x00007fffaab52000)
libc.so.6 => /lib64/libc.so.6 (0x0000003c4c800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003c4c000000)

如果有依赖库找不到,程序会无法正常运行。

3.加载共享库

在所有基于GNUglibc的系统中,在启动一个ELF二进制执行程序时,一个特殊的程序“程序装载器”会被自动装载并运行。在linux中,这个程序装载器就是/lib/ldlinux.so.X(X是版本号)。它会查找并装载应用程序所依赖的所有共享库。被搜索的目录保存在 /etc/ld.so.conf文件中。当然,如果程序的每次启动,都要去搜索一番,势必效率不堪忍受。Linux系统已经考虑这一点,对共享库采用了缓存管理。ldconfig就是实现这一功能的工具,其缺省读取/etc/ld.so.conf文件,对所有共享库按照一定规范建立符号连接,然后将信息写入/etc/ld.so.cache。/etc/ld.so.cache的存在大大加快了程序的启动速度。

  • 1.修改/etc/ld.so.conf,添加自己的共享库路径
  • 2.更新共享库缓存:sudo ldconfig -v

参考:
https://blog.csdn.net/benpaobagzb/article/details/51277960

glibc、libc、libstdc++等等的关系,见:
https://blog.csdn.net/haibosdu/article/details/77094833

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值