程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Linux网络应用开发--- 编译工具gcc用法和链接库

balukai 2025-01-10 11:34:04 文章精选 5 ℃

在Linux的系统中,主要是使用gcc/g++、Makefile和CMake这几种方式对C和C++代码进行编译的,本篇文章先简单介绍下gcc工具的使用场景和使用方法,以及静态库及动态库的使用生成和使用方法, Makefile和CMake用法比较复杂,打算在另一篇文章再单独详细介绍。

一、GCC/G++编译器:

1. 作用:

1)GCC主要功能是将高级程序代码翻译成目标机器代码,可以生成在不同系统平台上运行的可执行文件或动态、静态连接库。

2)GCC支持各种不同的目标体系结构,可以被广泛采用到多种架构的处理器平台的应用中。例如,它既支持基于宿主的开发(即在该平台上编译和运行),

也支持交叉编译(即在A平台上编译的程序在平台B使用)

3)GCC还提供了丰富的标准库和常用工具,如make、gdb、valgrind等,使得开发人员可以更方便地编写、调试和优化程序。


2. 编译步骤:

gcc编译程序过程如下:

预处理--->编译和优化 ---> 汇编 ---> 链接 --->可执行程序



1)预处理:将程序中引用的头文件包含进源代码中,并对宏进行替换。

gcc -E test.c -o test.i

预处理主要包括以下内容:

a. 在C/C++源文件中, 以“ #”开头的命令被称为预处理命令; 如,一些包含的头文件:#include<stdio.h> #include “header.h”

b. 宏定义展开. 如:#define定义的一些函数和常量;

c. 根据条件编译命令选择要使用的代码。如:#if, #ifdef , #ifndef等;

2)编译:将高级语言翻译成处理器可识别的汇编语言。

gcc -S test.i(test.c) -o test.s

说明:

a. C/C++代码(比如上述的“.i”文件)“ 翻译” 成汇编代码,所用到的工具为 cc1 ;

b. 检查语法错误;如果语法有误则报错,如果语法没错则编译成汇编语言;


3)汇编:转成二进制目标代码

gcc -c test.s(test.c) -o test.o

说明:

a. 将汇编语言解析成二进制文件(并非纯粹的二进制文件), 在Linux 系统上一般表现为 ELF 目标文件(OBJ 文件),用到的工具为 as;

b. 也可以进行反汇编:将机器代码转换为汇编代码,这在调试程序时常常用到;

反汇编: objdump -d test.o > test.s

4)链接:将所有的目标文件链接成可执行文件。

gcc test.o -o test 或者 gcc test1.o test2.o -o test

说明:

a. 链接就是将上步生成的 OBJ 文件和系统库的 OBJ 文件、 库文件链接起来,最终生成了可以在特定平台运行的可执行文件,用到的工具为 ld 或 collect2。

b. 格式: gcc -o 可执行文件 .c/.i/.s/.o文件都可以;


5)一次性编译多个.c文件

格式: gcc -o 可执行文件 .c文件 .c文件 ...(后面接多个.c文件都行)

说明: 只能有一个main函数;


总结:

1)C中的编译过程也称为将人类可理解代码(C程序)转换为机器可理解代码(二进制代码)的过程;

2)C语言的编译过程包括四个步骤:预处理、编译、汇编和链接;

3)预处理器执行删除注释、宏扩展、文件包含。这些命令在编译过程的第一步执行;

4)编译器可以提高程序的性能,并将中间文件转换为汇编文件;

5)汇编程序有助于将汇编文件转换为包含机器代码的对象文件;

6)链接器用于将库文件与对象文件链接。这是编译中生成可执行文件的最后一步.

7)程序运行:结合不同的处理器系统在内存中进行装载和执行;


3. gcc编译选项:

-c,仅编译生成目标文件.o,不进行链接;

-o outfile,指定生成的可执行文件为outfile,且这个名称不能和源文件同名;如果不指定文件名,默认可执行文件a.out;

-g,产生调试工具所需要的符号信息,如果需要对源代码进行调试,我必须加入这个选项;

-O,对程序进行优化编译、链接的选项,可以提高可执行文件的执行效率,编译和链接的速度就要慢一些;

有4个优化级别:

-O0: 不进行任何优化,在这种情况下,编译器尽量的缩短编译消耗(时间和空间);

-O1(或-Os):优化等级低;

-O2: 优化等级中;

-O3: 优化等级高,编译消耗时间和内存最多;

-I path: 指定编译时需要包括的头文件路径,#include 相关的文件;

-L path: 指定编译时需要链接的动态和静态库文件路径;-llib库所在的文件路径;

-E:只进行预处理,这个不生成目标文件;

-S: 生成汇编程序,不生成目标文件;

-c: 编译生成目标文件;

-o: 编译生成可执行文件,进行链接动作;

-static: 编译生成静态链接库的文件;

-shared:编译生成动态链接库的文件;

-W: 屏蔽所有警告信息;

-Wall:打开所有的警告,具体打开的选项见下面详细说明;

-Wno-:开头关闭特定的警告; 如:gcc -Wall -Wno-unused test.c -o test;

-Werror: 将所有警告当作错误;

-Werror= :指定特定的警告变成错误;

-Wfatal-erros: 编译遇到第一个错误就停止编译

-D: 指定宏定义;-Dname或 -Dname=value 这样的变量名称;

-U name:解除宏定义

-llibrary: 手动指定链接的动态(静态)库文件(注意库的命名格式有要求,如:libtest.so)

-ansi:对于C语言程序来说,其等价于-std=c90;对于C++程序来说,其等价于-std=c++98。

-std= : 指定c/c++版本,编程语言所遵循的标准,例如 c89、c90、c++98、c++11 等。


-Wall 选项详细说明:

相当于同时使用了下列所有的选项(有些选项对于调试程序非常实用的):

.unused-function:遇到仅声明过但尚未定义的静态函数时发出警告;

.unused-label: 遇到声明过但不使用的标号的警告;

.unused-parameter:从未用过的函数参数的警告;

.unused-variable:在本地声明但从未用过的变量的警告;

.unused-value: 仅计算但从未用过的值得警告;

.Format:检查对printf和scanf等函数的调用,确认各个参数类型和格式串中的一致;

.implicit-int:警告没有规定类型的声明;

.implicit-function-:在函数在未经声明就使用时给予警告;

.char-subscripts:警告把char类型作为数组下标。这是常见错误,程序员经常忘记在某些机器上char有符号;

.missing-braces:聚合初始化两边缺少大括号;

.Parentheses:在某些情况下如果忽略了括号,编译器就发出警告;

.return-type:如果函数定义的返回类型与实际不一致时会发出警告;

.sequence-point:出现可疑的代码元素时,发出报警;

.Switch:如果某条switch语句的参数属于枚举类型,但是没有对应的case语句使用枚举元素,编译器就发出警告;

超出枚举范围的case语句同样会导致这个警告。

.strict-aliasing:对变量别名进行最严格的检查。

.unknown-pragmas:使用了不允许的#pragma。

.Uninitialized:在初始化之前就使用自动变量。

----------------------------------------------------------------------


4. 例子说明用法:

##预编译展开的源文件;

gcc -E test.c -o test.i


##生成编译程序;

gcc -S test.i -o test.s


##生成没有链接的目标文件;

gcc -c test.s -o test.o


##链接生成可执行程序

gcc test.s -o test


##默认生成目标文件test.o,没有链接,不能运行;

gcc -c test.c


##同时编译多个.c文件,并链接生成test可执行文件;

gcc test1.c test2.c test3.c -o test

或者如下方法一步步进行:

gcc -c test1.c

gcc -c test2.c

gcc -c test3.c

gcc -o test test1.o test2.o test3.o


##想要使用-Wall来启用个选项,同时又要关闭unused警告

gcc -Wall -Wno-unused test.c -o test

##编译链接可执行文件,且指定包含的头文件路径;同时打开调试信息

gcc -g test.c -o test -I./include/ -D__DEBUG__


##编译链接可执行文件,且指定包含的链接库文件路径

(注意库文件的命名规则,以及-l的用法:libtest.so 调用时使用 -ltest);

gcc test.c -o test -L./lib/ -ldynic_test

##gcc 生成动态库的方法;

gcc test.c -shared -PIC -o libdynic_test.so


##gcc 生成静态库的方法;

gcc -c test1.c test2.c

ar crv libtest.a test1.o test2.o


二、静态库和动态库:

1、库命名规则:

1)静态库:lib + 名字 + .a, 例如: libtest.a

2)动态库:lib + 名字 + .so ,例如:libtest.so

2、制作步骤:

1)静态库:

##把当前目录下的所有.c文件编译成目标文件;

gcc -c *.c -I ../include

##把所有的目标文件打包成静态库

ar rcs libtest.a *.o

###解压当前的静态库文件到当前目录(可用于静态库模块的增删操作):

ar -x libtest.a


2)动态库:

##从源文件直接生成动态库

gcc -fPIC -shared func.c -o libfunc.so

##分步生成,从目标文件生成动态库;

(1) gcc -fPIC -c *.c -I ../include

(2) gcc -shared *.o -o libtest.so

参数说明:

-fPIC:作用于编译阶段,告诉编译器产生与位置无关代码;

-shared: 作用于链接阶段,告诉编译器生成动态库;


3. 调用方法:

1) 指定路径:

gcc test.c -o test -L./lib/ -ltest

运行时需要把库的路径加入到系统变量中:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/lib

./test


2)把libtest.so库放到/lib/或/usr/lib系统目录下;可直接运行;

3)使用ldconfig命令;

a.自定义一个mytest.conf文件放入到/etc/ld.so.conf.d/下,并修改这个mytest.conf,添加libtest.so的绝对路径;

b.再运行ldconfig 同步更新,即可直接运行;


(感谢关注,更新待续.....)

最近发表
标签列表