大部分内容转自:
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 切换目录
接下来主要说明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做准备。