【Linux 学习笔记】gcc初体验

大部分内容转自:

http://www.linuxidc.com/Linux/2014-08/105302.htm



用VMware装了个Ubuntu的虚拟机吗,前坑未填,又增新坑。


在这里学了一下,基本的目录结构:

http://www.linuxidc.com/Linux/2015-07/120815p4.htm


目录管理的生存向命令:

http://www.linuxidc.com/Linux/2015-07/120815p6.htm


Vim的基本操作:(。。。)



好了!开始填坑!


ctrl + alt + T 打开终端


pwd 显示当前目录


cd 切换目录

【Linux 学习笔记】gcc初体验_第1张图片


更多命令,如删除rmdir,   rm 等在链接中均有说明。


接下来主要说明gcc的用法:


1. 单个文件的编译


首先通过vim建立一个c文档 口令如下:

vi hello.c


假设程序为:

#include <stdio.h>
int main()
{
printf(“Hello World!\n”);
return 0;
}


:wq 保存并退出

hello.c文件保存在当前目录下


此时输入口令:

gcc hello.c

运行后,看上去并没有什么效果,此时键入:ls -al  (显示当前目录下所有的文件及文件夹,包括隐藏文件,以及它们的详细信息)

会发现当前目录中多出一个 a.out 的文件。

试着运行一下 a.out

./a.out

这时终端输出了“hello world”字样


如果不想每个生成的可执行文件都叫一个名字——a.out

则用如下口令:

gcc hello.c -o run

-o 代表 output

run 输出的文件的文件名

这时,输入:

./run

可以获得相同的效果


2.多个文件的编译


假设我一个项目里由多个c文件组成,main.c , add.c

这时如何编译

首先:

gcc -Wall -c main.c 

gcc -Wall -c add.c


这时,目录下会多出main.o , add.o 两个目标文件

-c 的作用是只编译不链接 不生成可执行文件

接下来就要将这些目标文件进行链接,生成可执行文件。

gcc -Wall main.o add.o -o result

此时,当前目录多处一个名为result的可执行文件

./result

运行后即可得到结果。


上述过程看起来十分繁琐,可以用一句话来概括

gcc -wall main.c add.c -o result


效果一样,但是前者更好的体现了gcc编译和链接的过程:

编译之后产生目标文件,将目标文件进行链接产生可执行文件。


3. 静态链接和动态链接

http://www.linuxidc.com/Linux/2014-08/105302p4.htm

此页说的很详细,我也就似懂非懂的复制粘贴一两句


“库说白了其实就是一个个目标文件的集合。linux上一共有两种库文件类型,一种是以.a格式的静态链接库,另一种是以.so格式的动态链接库。下面我们来讲讲静态链接库。”


ar的使用格式:

ar cr libName.a file1.o file2.o file3.o …...

注释:libName.a中前缀lib和后缀.a固定,Name是静态链接库的名称。    

ar cr libtest.a add.o、minus.o、divide.o、multiply.o                      
 // 将几个.o的目标文件整合到一个库中

执行命令后,我们查看当前目录下的文件,就多出了一个libtest.a文件。接着,我们就直接使用libtest.a来重新编译源程序:

gcc -Wall main.c libtest.a -o result2

程序结果和之前的一样。我们也可以使用下面这种方法:

gcc -Wall main.c -L. -ltest -o result2// 猜测原文这里的“.”加的位置可能有问题,经测试发现 -L后面接地址,"."表示当前目录,因此"."应当夹在-L后面

注意,上面的”-L.”不能缺少,因为,使用”-l“,编译器查找的是系统默认的库文件地址,而不是当前目录,故需要使用-L来说明库文件地址,由于我们的libtest.a在当前目录下,故直接使用“.”表示当前目录。以后,我们向别人提供第三方函数库时,如果不想让别人看到源代码,那么就可以只提供.a静态链接库和包含所有函数声明的头文件即可。

a.静态链接
在之前所有的教程里,我们都是把生成的目标文件、静态链接库以及头文件放在同一个文件夹下,这样不仅显得很杂乱,也不便管理源文件,一旦程序的文件数目庞大后,问题就愈加突出。下面我们就对程序文件整理一下,一般来说,头文件放在include 文件夹下,静态链接库lib文件夹下。下面先创建两个文件夹,并把相应的文件移动到对应文件夹下。

mkdir include
mkdir lib
mv libtest.a lib
mv math.h include

由于我们已经将四个目标文件(add.o、minus.o、divide.o、multiply.o)打包成静态链接哭libtest.a,那么就可以删除这四个文件:

rm add.o minus.o divide.o multiply.o

这是当前目录就只剩下main.c、add.c、minus.c、divide.c、multiply.c这五个源文件。



首先,我们用比较麻烦的方法一步步地来编译源文件,首先是生成目标文件,由于add.c、minus.c、divide.c、multiply.c这四个源代码的目标文件的已经生成并被打包到静态链接库中,故我们只需生成main.c的目标文件即可:

gcc -Wall -Iinclude -c main.c                          
   // 我在测试的时候 include 文件夹是放在 programming 文件夹中,因此可写为 -lprogramming/include ,注意“相对地址”概念

这里-Iinclude中-I后面接的是main.c中所引用头文件(math.h)的地址,这里使用的是相对地址,其实也可以使用绝对地址,当由于不同的linux系统,他们的文件位置可能有写差异,这就造成我们程序的移植性很差,所以还是建议大家使用相对地址。



接下就链接目标文件即可。

gcc -Wall main.o -Llib -ltest -o result3

这里-Llib是-L后面接的是静态链接库的地址,由于我们的libtest.a在lib中,故接lib。


可以看到,多个.c文件编译后生成的目标文件,.o文件,可以整合为一个库文件,即.a文件,存放到工程文件目录中,在链接时从目录中调用此库,即可达到多个.o文件同时作用的效果。

b.动态链接

动态链接的一个好处是,同一个库文件资源,可以供多个程序共享使用,可以省下许多内存空间。但是,在移植到另一个操作系统环境时,如果该系统没有相应的动态链接库或设置相应的路径,那么程序就无法运行,这在移植性方面,相对静态链接方式就差一些。下面开始进入主题:

动态链接库的后缀是.so(在linux上,windows上是.dll)。其命名方式为:libxxx.so,

创建方法:

gcc -c -fpic A.c B.c .............

gcc -shared A.o B.o .... -o libxxx.so

这里-fpic:由于共动态链接库不同,他们在运行时加载,因而地址是很随机的,加上-fpic选项,可以保证编译生成的东西是地址无关的。

我们这次创建一个libtest.so动态链接库。

gcc -c -fpic add.c minus.c divide.c multiply.c

gcc -shared add.o minus.o divide.o multiply.o -o libtest.so

现在,我们已经生成了一个libtest.so动态链接库。

编译链接:

gcc -Wall main.c -L. -ltest -o run

-L.表示库文件在当前目录下,-ltest就是libtest.so文件,注意,这里不是运行时,而是编译链接过程。。。

现在我们运行run执行文件,这时,会报错,说找不到libtest.so文件。

这是因为,程序运行时,查找动态链接库文件是到默认的系统目录下找的。解决办法有两个:

一、将libtest.so复制到/usr/lib目录下

二、修改路径:export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH,在路径下添加当前路径。

// 缺少权限未调试成功,不过概念大概就是这样


个人臆测动态与静态的区别:

静态库封装在软件目录中,与软件本体共生,使用静态库是为了管理软件本身。

动态库则需要随着软件的移植,在当前系统中的库中进行配置。在程序编译的时候,检索的是当前系统的库,是否有对应的动态库文件。因此,同一个库文件资源,可以供多个程序共享使用,可以省下许多内存空间。


本章内容,操作简单,偏向基础原理,主要是为了下一步学习makefile做准备。


你可能感兴趣的:(linux,gcc,ubuntu)