【Linux】Linux下GCC的介绍与使用

8 篇文章 0 订阅
什么是GCC

GCC原名为 GNU C语言编译器(GNU C Compiler)

GCC(GNU Compiler Collection,GNU编译套件)是由GNU开发的编程语言编译器。

安装命令
sudo apt-get insatll gcc g++

注意安装版本要大于4.8.5因为4.8.5以后的版本才支持c++11标准

查看版本

gcc -v
gcc --version
g++ -v
g++ --version
gcc和g++的区别

gcc和g++ 都是GNU (组织)的一个编译器。

1、误区一: gcc只能编译c代码,g++只能编译c++代码。两者都可以,请注意:

  • 后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序

  • 后缀为.cpp 的,两者都会认为是C++程序,C++的语法规则更加严谨一些

  • 编译阶段,g++会调用gcc, 对于C++代码,两者是等价的,但是因为gcc命令不能自动和C++程序使用的库联接,所以通常用g++来完成链接,为了统一起见,干脆编译/链接统统用g++了 ,这就给人一种错觉,好像cpp程序只能用g++似的.

2、误区二: gcc不会定义_cplusplus 宏,而g++会

  • 实际上,这个宏只是标志着编译器将会把代码按C还是C++语法来解释
  • 如上所述,如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则,就是已定义

3、误区三:编译只能用gcc,链接只能用g++

  • 严格来说,这句话不算错误,但是它混淆了概念,应该这样说:编译可以用gcc/g++,而链接可以用g++ 或者gcc -lstdc++。
  • gcc命令不能自动和C++程序使用的库联接,所以通常使用g++来完成联接,但在编译阶段,g++会自动调用gcc, 二者等价
gcc编译过程

在这里插入图片描述

gcc常用参数
选项名作用
-o产生目标(.i、.s、.o、可执行文件等)
-E只运行C预编译器
-S告诉编译器产生汇编程序文件后停止编译,产生的汇编语言文件拓展名为.s
-c通知gcc取消连接步骤,即编译源码,并在最后生成目标文件
-w不产生任何警告信息
-Wall使gcc对源文件的代码有问题的地方发出警告
-Idir指定 include 包含文件的搜索目录
-Ldir指定编译的时候,搜索的库的路径
-lLib在程序编译的时候,指定使用的库
-g在目标文件中嵌入调试信息,以便gdb之类的调试程序调试
-D允许从编译程序命令行进行宏定义符号
gcc的使用示例:
gcc -E hello.c -o hello.i   #对hello.c文件进行预处理,生成了hello.i 文件
gcc -S hello.i -o hello.s   #对预处理文件进行编译,生成了汇编文件
gcc -c hello.s -o hello.o   #对汇编文件进行编译,生成了目标文件
gcc hello.o -o hello 		#对目标文件进行链接,生成可执行文件
gcc hello.c -o hello 		#直接编译链接成可执行目标文件
gcc -c hello.c 或 gcc -c hello.c -o hello.o #编译生成可重定位目标文件

-D 参数演示

测试代码如下:

#include<stdio.h>

int main()
{
#ifdef DEBUG
	printf("DEBUG:\n");
#else
	printf("Normal:\n");
#endif
	for(int i=0;i<3;i++)
		printf("work\n");
	return 0;
}

测试命令

gcc -o Debug Debug.c
./Debug
Normal:
work
work
work
gcc -o Debug Debug.c -DDEBUG
./Debug
DEBUG:
work
work
work
库的介绍

什么是库?

库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。

库文件有两种,静态库和动态库(共享库)

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。静态库比较占用磁盘空间,而且程序不可以共享静态库。运行时也是比较占内存的,因为每个程序都包含了一份静态库。

  • 动态库(.so或.sa):程序在运行的时候才去链接共享库的代码,多个程序共享使用库的代码,这样就减少了程序的体积。

库的好处:

1.代码保密

2.方便部署和分发

生成静态库

静态库命名规则:

◆ Linux : libxxx.a

lib : 前缀(固定)

xxx : 库的名字,自己起 .

a : 后缀(固定)

◆ Windows : libxxx.lib

首先准备几个文件和文件夹

$ tree
.
├── calc
│   ├── add.c
│   ├── div.c
│   ├── head.h
│   ├── main.c
│   ├── mult.c
│   └── sub.c
└── library
    ├── include
    ├── lib
    └── src

add.c

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

int add(int a,int b)
{
	return a+b;
}

div.c

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

double divide(int a,int b)
{
	if(b==0)
		return (double)a/b;
	else
		return 0;
}

mult.c

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

int multiply(int a,int b)
{
	return a*b;
}

sub.c

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

int subtract(int a,int b)
{
	return a-b;
}

head.h

#ifndef _HEAD_H_
#define _HEAD_H_

int add(int a,int b);
double divide(int a,int b);
int multiply(int a,int b);
int subtract(int a,int b);
#endif

为了生成.a文件,我们需要先生成.o文件。

$ cd calc/
$ gcc -c add.c div.c mult.c sub.c

打包生成静态库

$ ar rcs libcalc.a add.o sub.o mult.o div.o

ar是gun归档工具,rcs表示replace and create,如果libhello之前存在,将创建新的libhello.a并将其替换。

r - 将文件插入备存文件中

c - 建立备存文件

s - 索引

将库放到指定位置

$ cp libcalc.a ../library/lib/
$ cp head.h ../library/include/
$ cp add.c div.c mult.c sub.c ../library/src/

库目录结构如下(这个库目录就是发给被人用的)

$ tree
.
├── include
│   └── head.h
├── lib
│   └── libcalc.a
└── src
    ├── add.c
    ├── div.c
    ├── mult.c
    └── sub.c
使用静态库

编辑main.c文件

#include<stdio.h>
#include"head.h"
int main()
{
	int a = 20;
	int b = 12;
	printf("a = %d,b = %d\n",a,b);

    printf("a + b = %d\n",add(a,b));
    printf("a - b = %d\n",subtract(a,b));
    printf("a * b = %d\n",multiply(a,b));
    printf("a / b = %d\n",divide(a,b));
    return 0;

}

然后就可以这样来使用静态库libcalc.a

$ gcc main.c -o app -I ./include/ -lcalc -L./lib
$ ./app
a = 20,b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 12

其中:
-I directory 指定include包含文件的搜索目录
-l 在程序编译的时候,指定使用的库
-L directory 指定编译的时候,搜索的库的路径

生成动态库(共享库)

◆ 动态库命名规则:

Linux : libxxx.so

lib : 前缀(固定)

xxx : 库的名字,自己起 .

so : 后缀(固定)

在Linux下是一个可执行文件

◆ Windows : libxxx.dll

使用静态库的测试代码,库目录结构还是一样

$ tree
.
├── calc
│   ├── add.c
│   ├── div.c
│   ├── head.h
│   ├── main.c
│   ├── mult.c
│   └── sub.c
└── library
    ├── include
    ├── lib
    └── src

为了生成.so文件,我们需要先生成.o文件得到和位置无关的代码。

$ gcc -c -fpic add.c div.c mult.c sub.c

打包生成动态库

$ gcc -shared add.o sub.o mult.o div.o -o libcalc.so

将库放到指定位置

$ cp libcalc.so ../library/lib/
$ cp head.h ../library/include/
$ cp add.c div.c mult.c sub.c ../library/src/

库目录结构如下(这个库目录就是发给被人用的)

$ tree
.
├── include
│   └── head.h
├── lib
│   └── libcalc.so
└── src
    ├── add.c
    ├── div.c
    ├── mult.c
    └── sub.c
使用动态库
$ gcc main.c -o app -I include/ -L lib/ -l calc
$ ldd app
        linux-vdso.so.1 =>  (0x00007ffc75cb0000)
        libcalc.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f3605ddb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f36061a9000)

通过ldd命令查看程序动态库依赖关系

ldd是list dynamic dependencies的缩写, 意思是, 列出动态库依赖关系。

结果发现libcalc.so => not found找不到了

那么如何让程序找到依赖库呢?这里提供四种方法

方法一(不推荐)
#拷贝.so文件到系统共享库路径下,一般指/usr/lib或者/lib/目录
$ sudo cp ./lib/libcalc.so /usr/lib/
方法二(临时环境变量)
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/deroy/library/lib
$ echo $LD_LIBRARY_PATH
:/root/deroy/library/lib
$ ldd app
        linux-vdso.so.1 =>  (0x00007fffe1570000)
        libcalc.so => /root/deroy/library/lib/libcalc.so (0x00007f007020f000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f006fe41000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0070411000)
$ ./app
a = 20,b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 12

运行成功

缺陷:只在当前终端有效,关闭中端后就没用了

方法三(配置用户环境变量)

将环境变量写入到~/.bashrc即可,即将下面内容添加到末尾

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/deroy/library/lib

[root@library]# cd ~
[root@~]# vim .bashrc
[root@~]# . .bashrc			#相当于source .bashrc
[root@~]# source .bashrc
[root@~]# cd deroy/library/
[root@library]# ldd app
        linux-vdso.so.1 =>  (0x00007ffe0d2db000)
        libcalc.so => /root/deroy/library/lib/libcalc.so (0x00007f937669c000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f93762ce000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f937689e000)
[root@library]# ./app
a = 20,b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 12
方法四(配置系统环境变量)

将环境变量写入到~/etc/profile即可,即将下面内容添加到末尾,需要root权限

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/deroy/library/lib

[root@library]# vim /etc/profile
[root@library]# source /etc/profile
[root@library]# ldd app
        linux-vdso.so.1 =>  (0x00007ffe08dc3000)
        libcalc.so => /root/deroy/library/lib/libcalc.so (0x00007f0eada81000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f0ead6b3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0eadc83000)
[root@library]# ./app
a = 20,b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 12
总结
静态库的优缺点

◼ 优点:

◆ 静态库被打包到应用程序中加载速度快

◆ 发布程序无需提供静态库,移植方便

◼ 缺点:

◆ 消耗系统资源,浪费内存 ◆ 更新、部署、发布麻烦

动态库的优缺点

◼优点:

◆ 可以实现进程间资源共享(共享库)

◆ 更新、部署、发布简单 ◆ 可以控制何时加载动态库

◼缺点:

◆ 加载速度比静态库慢

◆ 发布程序时需要提供依赖的动态库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cappuccino-jay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值