| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> Linux网络编程第2章Linux编程环境 -> 正文阅读 |
|
[系统运维]Linux网络编程第2章Linux编程环境 |
前言: 在Linux上开发的时候,我们首先要了解Linux下的编译器熟知,知道GCC的编译、链接过程,知道怎么写Makefile文件,知道怎么使用GDB进行调试代码。 2.1 Linux环境下的编辑器2.1.1 Vim使用简介1.Vim安装
2.Vim编辑器的模式 2.1.2 使用Vim建立文件1.建立一个文件
2.进入插入模式
4.退出vim 发现当前目录下已经存在一个名为hello.c的文件。输入的wq是“保存后退出”的意思:q表示退出,w表示保存。当不想保存所作的修改时,输入“:”键后,再输入“q!”,Vim会直接退出,不保存所作修改。q!是强制退出的意思。 Vim有一个学习的帮助工具——vimtutor,它是很有帮助的一个工具,初学者可以使用它进行Vim的练习。输入“vimtutor”后,可以按照它的指示由浅入深地进行学习。 2.1.3 使用Vim编辑文本Vim的编辑命令有很多,本节选取几个经常使用的命令作为介绍。如何在Vim下移动光标,进行删除字符、复制、查找、跳转等操作。 1.移动光标h、j、k、l Vim在普通模式下移动光标是需要按特定的键,进行左、下、上、右光标移动的字符分别为h、j、k、l这四个字符。 当然还可以用方向键移动光标,但必须将手从字母键位置上移动到方向键上,这样会减慢输入速度。而且,有一些键盘是没有方向键的,或者需要特殊的操作才能使用方向键(例如必须按组合键)。所以,知道用h、j、k、l字符移动光标的用法是很有帮助的。 2.删除字符x、dd、u、CTRL+R 要删除一个字符可以使用x,在普通模式下,将光标移到需要删除的字符上面然后按x键。例如hello.c的第一行输入有一个错误: 将光标移动到I上,然后按x键,切换输入模式到插入模式,输入i,对include的修正完成了。 要删除一整行可以使用dd命令,删除一行后,它后面的一行内容会自动向上移动一行。使用这个命令的时候要注意输入d的个数,两个d才是一个命令,在实际使用过程中经常将d的输入个数弄混淆。 恢复删除可以使用u。当删除了不应该删除的东西后,u命令可以取消之前的删除。例如,用dd命令删除一行,再按u键,恢复被删除的该行字符。 Ctrl+r是一个特殊的命令,它为取消一个命令,可以使用它对u命令造成的后果进行弥补。例如使用u命令撤销了之前的输入,重新输入字符是很麻烦的,而使用Ctrl+r可以十分方便地将之前使用u命令撤销输入的字符重新找回。 3.复制粘贴p、y Vim的粘贴命令是p,它的作用是将内存中的字符复制到当前光标的后面。
光标位于此行的头部,当输入y2w时字符串#include就复制到内存中,按p键后,此行如下:
我们同样可以使用yy进行复制整行字符,然后按p进行粘贴。 4.查找字符串“/”
那么就代表的是在文本中搜索hello词。查找其他的匹配字符串可以输入字符“n”向下移到一个匹配的字符串上,输入字符“N”则会向上移到一个匹配的字符串上。 5.跳到某一行g
此刻光标便跳转到了第6行。
此刻便跳转到了第6行。注意其中的G为大写。 2.1.4 Vim的格式设置1.设置缩进
设定了这一选项之后,当输入一行语句后,Vim会自动在下一行进行缩进。
那么将tab键的宽度设置为了4个空格。 2.1.5 Vim配置文件.vimrc我们可以根据自己的习惯来更改自己的vimrc配置文件。这样每次在使用vim进行编辑的时候都可以自动加载配置文件了。
2.1.6 使用其他编辑器在使用其他编辑器编辑文件的时候,注意要保存成UNIX格式的。这主要是换行符导致的,在windows下的换行为“回车+换行”。而UNIX环境下的换行为单个的换行。在Linux下用Vim查看会发现每行的末尾有一个很奇怪的“~”。如果没有保存为UNIX的格式,在Linux下可以使用dos2UNIX转换。 dos2unix命令是用来将DOS格式的文本文件转换成UNIX格式的。
运行完之后,显示dos2unix: 正在转换文件 hello.c 为Unix格式… 2.2 Linux下的GCC编译器工具集2.2.1 GCC简介GCC是Linux下的编译工具集,是GNU Compiler Collection的缩写,包含gcc、g++等编译器。这个工具集不仅包含编译器,还包含其他工具集,例如ar、nm等。 2.2.2 编译程序的基本知识GCC编译器对程序的编译如图2.1所示,分为4个阶段:预编译、编译和优化、汇编和链接。GCC的编译器可以将这4个步骤合并成一个。 预编译过程将程序中引用的头文件包含进源代码中,并对一些宏进行替换。 编译过程将用户可识别的语言翻译成一组处理器可识别的操作码,生成目标文件,通常翻译成汇编语言,而汇编语言通常和机器操作码之间是一种一对一的关系。GNU中有C/C++编译器GCC和汇编器as。 所有的目标文件必须用某种方式组合起来才能运行,这就是链接的作用。目标文件中通常仅解析了文件内部的变量和函数,对于引用的函数和变量还没有解析,这需要将其他已经编写好的目标文件引用进来,将没有解析的变量和函数进行解析,通常引用的目标是库。链接完成后会生成可执行文件。 2.2.3 单个文件编译成执行文件使用GCC编译器编译单个文件很简单,使用gcc命令再加上源文件就可以了。不指定生成文件名的话,自动生成a.out的可执行文件。自动编译的过程包括头文件扩展、目标文件编译,以及链接默认的系统库生成可执行文件,最后生成系统默认的可执行程序a.out。
GCC将采取默认步骤,先将C文件编译成目标文件,然后将目标文件链接成可执行文件,最后删除目标文件。上述命令没有指定生成执行文件的名称,GCC将生成默认的文件名a.out。运行结果如下:
如果希望生成指定的可执行文件名,选项-o可以使编译程序生成指定文件名,例如将上述程序编译输出一个名称为test的执行程序:
2.2.4 编译生成目标文件目标文件是指经过编译器的编译生成的CPU可识别的二进制代码,因为其中一些函数过程没有相关的指示和说明,目标文件不能执行。 在2.2.3节中介绍了直接生成可执行文件的编译方法,在这种编译方法中,中间文件作为临时文件存在,在可执行文件生成后,会删除中间文件。在很多情况下需要生成中间的目标文件,用于不同的编译目标。 GCC的-c选项用于生成目标文件,这一选项将源文件生成目标文件,而不是生成可执行文件。默认情况下生成的目标文件的文件名和源文件的名称一样,只是扩展名为.o。例如,下面的命令会生成一个名字为hello.o的目标文件:
如果需要生成指定的文件名,可以使用-o选项。下面的命令将源文件hello.c编译成目标文件,文件名为test.o:
可以用一条命令编译多个源文件,生成目标文件,这通常用于编写库文件或者一个项目中包含多个源文件。例如一个项目包含file1.c、file2.c和file3.c,下面的命令可以将源文件生成3个目标文件:file1.o、file2.o和file3.o:
2.2.5 多文件编译GCC可以自动编译链接多个文件,不管是目标文件还是源文件,都可以使用同一个命令编译到一个可执行文件中。
执行编译出来的可执行文件test,程序的运行结果如下:
当然可以先将源文件编成目标文件,然后进行链接。例如,下面的过程先将string.c和main.c源文件编译成目标文件string.o和main.o,然后将string.o和main.o链接生成test:
2.2.6 预处理在C语言程序中,通常需要包含头文件并会定义一些宏。预处理过程将源文件中的头文件包含进源文件中,并且将文件中定义的宏进行扩展。 一句话就是对#的进行扩展处理,将头文件和宏定义进行扩展填充。 编译程序时选项-E告诉编译器进行预编译操作。例如如下命令将文件string.c的预处理结果显示在计算机屏幕上:
如果需要指定源文件预编译后生成的中间结果文件名,需要使用选项-o。例如,下面的代码将文件string.c进行预编译,生成文件string.i。string.i内容如下: 预处理之后是.i文件。 2.2.7 编译成汇编语言编译过程将用户可识别的语言翻译成一组处理器可识别的操作码,通常翻译成汇编语言。汇编语言通常和机器操作码之间是一对一的关系。 生成汇编语言的GCC选项是-S,默认情况下生成的文件名和源文件一致,扩展名为.s。例如,下面的命令将C语言源文件string.c编译成汇编语言,文件名为string.s。
下面是编译后的汇编语言文件string.s的内容。其中,第1行内容是C语言的文件名,第3行和第4行是文件中的函数描述,标签StrLen之后的代码用于实现字符串长度的计算。 2.2.8 生成和使用静态链接库静态库是obj文件的一个集合,通常静态库以“.a”为后缀。静态库由程序ar生成,现在静态库已经不像之前那么普遍了,这主要是由于程序都在使用动态库。 静态库的优点是可以在不用重新编译程序库代码的情况下,进行程序的重新链接,这种方法节省了编译过程的时间(在编译大型程序的时候,需要花费很长时间)。但是由于现在系统的强大,编译的时间已经不是问题。静态库的另一个优势是开发者可以提供库文件给使用的人员,不用开放源代码,这是库函数提供者经常采用的手段。当然这也是程序模块化开发的一种手段,使每个软件开发人员的精力集中在自己的部分。在理论上,静态库的执行速度比共享库和动态库要快(1%~5%)。 总结一下用静态链接库的好处:后缀通常是.a,由ar生成。不用重新编译链接静态库,静态库的执行速度要更快一些。
也可以使用命令“-l库名”进行,库名是不包含函数库和扩展名的字符串。例如编译main.c链接静态库libstr.a的命令可以修改为:
上面的命令将在系统默认的路径下查找str函数库,并把它链接到要生成的目标程序上。可能系统会提示无法找到库文件str,这是由于str库函数没有在系统默认的查找路径下,需要显示指定库函数的路径,例如库文件和当前编译文件在同一目录下:
注意:在使用-l选项时,-o选项的目的名称要在-l链接的库名称之前,否则gcc会认为-l是生成的目标而出错。 2.2.9 生成动态链接库动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。 动态链接库的名称有别名(soname)、真名(realname)和链接名(linker name)。别名由一个前缀lib,然后是库的名字,再加上一个后缀“.so”构成。真名是动态链接库的真实名称,一般总是在别名的基础上加上一个小版本号、发布版本等构成。除此之外,还有一个链接名,即程序链接时使用的库的名字。在动态链接库安装的时候,总是复制库文件到某个目录下,然后用一个软链接生成别名,在库文件进行更新的时候,仅仅更新软链接即可。
其中,选项“-soname,libstr.so”表示生成动态库时的别名是libstr.so;“-o libstr.so.1”选项则表示是生成名字为libstr.so.1的实际动态链接库文件;-shared告诉编译器生成一个动态链接库。
Ubuntu的配置文件将目录/etc/ld.so.conf.d中的配置文件包含进来,对这个目录下的文件进行查看:
如果想知道系统中有哪些动态链接库,可以使用ldconfig的-p选项来列出缓存文件中的动态链接库列表。下面的命令中表明在系统缓存中共有682个动态链接库。
使用ldconfig命令,默认情况下并不将扫描的结果输出。使用-v选项会将ldconfig在运行过程中扫描到的目录和共享库信息输出到终端,用户可以看到运行的结果和中间的信息。在执行ldconfig后,将刷新缓存文件/etc/ld.so.cache。
当用户的目录并不在系统动态链接库配置文件/etc/ld.so.conf中指定的时候,可以使用ldconfig命令显示指定要扫描的目录,将用户指定目录中的动态链接库放入系统中进行共享。命令格式的形式为:
这个命令将ldconfig指定的目录名中的动态链接库放入系统的缓存/etc/ld.so.cache中,从而可以被系统共享使用。下面的代码将扫描当前用户的lib目录,将其中的动态链接库加入系统:
如果在运行上述命令后,再次运行ldconfig而没有加参数,系统会将/lib、/usr/lib及/etc/ld.so.conf中指定目录中的动态库加入缓存,这时候上述代码中的动态链接库可能不被系统共享了。
-L指定链接动态链接库的路径,-lstr链接库函数str。但是运行test一般会出现如下问题:
将存放库文件libstr.so的路径/example/ex02加入到搜索路径中,再运行程序就没有之前的警告了。
加载test程序的命令为:
注意:如果系统的搜索路径下同时存在静态链接库和动态链接库,默认情况下会链接动态链接库。如果需要强制链接静态链接库,需要加上“-static”选项,即上述的编译方法改为如下的方式:
2.2.10 动态加载库动态加载库和一般的动态链接库所不同的是,一般动态链接库在程序启动的时候就要寻找动态库,找到库函数;而动态加载库可以用程序的方法来控制什么时候加载。动态加载库主要有函数dlopen()、dlerror()、dlsym()和dlclose()。
例如,下面的代码使用dlopen打开当前目录下的动态库libstr.so。
其中参数handle为dlopen()打开动态库后返回的句柄,参数symbol为函数的名称,返回值为函数指针。
执行文件testdl的结果为:
使用动态加载库和动态链接库的结果是一致的。 2.2.11 GCC常用选项除了之前介绍的基本功能外,GCC的选项配置是编译时很重要的选择,例如头文件路径、加载库路径、警告信息及调试等。本节将对常用的选项进行介绍。
2.2.12 编译环境的搭建目前最新的GCC编译器的版本为gcc-4.8.0。在安装Ubuntu的时候,默认情况下会安装GCC。读者可以使用which命令来查看系统中是否已经安装了GCC:
如果不存在,使用apt进行升级,获得gcc包并且安装:
如果读者对C++感兴趣可以安装g++。在编译器安装完毕后,可以使用GCC进行程序的编译。 2.3 Makefile文件简介当源文件变多的时候,使用GCC编译太麻烦了,所以使用了一种管理工程的功能,可以方便地进行程序的编译,对更新的文件进行重新编译。 2.3.1 一个多文件的工程例子有一个工程中的文件列表如图2.2所示。工程中共有5个文件,在add目录中有add_int.c和add_float.c,两个文件分别计算整型和浮点型的相加;在sub目录下有文件sub_int.c和sub_float.c,分别计算整型和浮点型的相减;顶层目录有main.c文件负责整个程序。
2.3.2 多文件工程的编译
默认情况下会执行Makefile中的第一个规则,即cacu相关的规则,而cacu规则依赖于多个目标文件add_int.o、add_float.o、sub_int.o、sub_float.o、main.o。编译器会先生成上述目标文件后执行下述命令:
上述命令将多个目标文件编译成可执行文件cacu,即: 2.2.3 Makefile的规则Makefile的框架是由规则构成的。make命令执行时先在Makefile文件中查找各种规则,对各种规则进行解析后运行规则。规则的基本格式为:
在执行的过程中,比如当要实现第一条规则的时候,发现所依赖的目标文件不存在,那么就执行产生目标文件的规则。规则之间事可以嵌套的。 执行的规则是从第一个规则开始分析的,从上往下依次嵌套执行完毕。当把规则clean放在第一个的时候,再执行make命令就不是生成目标文件了,而是清理文件。如果要生成文件的话需要使用如下命令:
有一种简便的方法可以实现与上面相同的功能
这种方法的规则main.o中依赖项中的“%o:%c”的作用是将TARGET域的.o的扩展名替换为.c,即将main.o替换为main.c。而命令行的 < 表 示 依 赖 项 的 结 果 , 即 m a i n . c ; <表示依赖项的结果,即main.c; <表示依赖项的结果,即main.c;@表示TARGET域的名称,即main.o。 2.3.4 Makefile使用变量我们在上面一节中通过对每个规则进行添加删除文件,很容易漏掉一些,也很麻烦。所以就使用变量对文件进行总结和替代。我们对文件进行处理的时候直接对变量操作即可。
另外还有CFLAGS等默认值是调用编译器时的选项默认配置,例如修改后的Makefile生成main.o时,没有指定编译选项,make程序自动调用了文件中定义的CFLAGS选项-Iadd-Isub-O2来增加头文件的搜索路径,在所有的目标文件中都采用了此设置。经过简化后,之前的Makefile可以采用如下形式:
2.3.5 搜索路径在系统中加入搜索路径
使用:进行分割开,make的搜索路径包含path1和path2目录。 2.3.6 自动推导规则没啥可讲的 2.3.7 递归make2.4 GDB调试 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 15:26:08- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |