目录
16 vim
16.1 vi简介
16.1.1 命令行模式
16.1.2 文本输入模式
16.1.3 末行模式
16.2 vim基础操作
16.3 vim分屏操作
16.4 vim打造IDE
16.4.1 简洁版IDE
17 gcc
18 toolchain
19 静态库和共享库
19.1 静态库
19.2 共享库
19.2.1 基础班使
19.2.2 就业班使用
19.4 项目实战
20 gdb调试工具
20.1 gdb调试模式
21 Makefile项目管理
21.1 用途
21.2 基本规则
21.2.1 三要素
21.3 Makefile 工作原理
21.4 Makefile 变量
21.5 Makefile 函数
21.6 clean
21.7 知识图谱
16 vim
16.1 vi简介
vi是“Visual interface”的简称,它在Linux上的地位就仿佛Edit程序在DOS上一样。它可以执行输出、删除、查找、替换、块操作等众多文本操作,而且用户可以根据自己的需要对其进行定制。Vi不是一个排版程序,它不象Word或WPS那样可以对字体、格式、段落等其他属性进行编排,它是一个文本编辑程序。 vi没有菜单,只有命令,且命令繁多。
Vi有三种基本工作模式:
+ 命令模式
+ 文本输入模式
+ 末行模式。
16.1.1 命令行模式
任何时候,不管用户处于何种模式,只要按一下ESC键,即可使Vi进入命令模式;我们在shell环境(提示符为$)下输入启动Vi命令,进入编辑器时,也是处于该模式下。在该模式下,用户可以输入各种合法的Vi命令,用于管理自己的文档。此时从键盘上输入的任何字符都被当做编辑命令来解释,若输入的字符是合法的Vi命令,则Vi在接受用户命令之后完成相应的动作。但需注意的是,所输入的命令并不在屏幕上显示出来。若输入的字符不是Vi的合法命令,Vi会响铃报警。
16.1.2 文本输入模式
在命令模式下输入插入命令i、附加命令a 、打开命令o、修改命令c、取代命令r或替换命令s都可以进入文本输入模式。在该模式下,用户输入的任何字符都被Vi当做文件内容保存起来,并将其显示在屏幕上。在文本输入过程中,若想回到命令模式下,按键ESC即可。
16.1.3 末行模式
末行模式也称ex转义模式。在命令模式下,用户按“:”键即可进入末行模式下,此时Vi会在显示窗口的最后一行(通常也是屏幕的最后一行)显示一个“:”作为末行模式的提示符,等待用户输入命令。多数文件管理命令都是在此模式下执行的(如把编辑缓冲区的内容写到文件中等)。末行命令执行完后,Vi自动回到命令模式。例如:
:sp newfile
则分出一个窗口编辑newfile文件。如果要从命令模式转换到编辑模式,可以键入命令a或者i;如果需要从文本模式返回,则按Esc键即可。在命令模式下输入“:”即可切换到末行模式,然后输入命令。
16.2 vim基础操作
进入插入模式
i: 插入光标前一个字符
I: 插入行首
a: 插入光标后一个字符
A: 插入行未
o: 向下新开一行,插入行首
O: 向上新开一行,插入行首
进入命令模式:
ESC:从插入模式或末行模式进入命令模式
移动光标:
h: 左移
j: 下移
k: 上移
l: 右移
M: 光标移动到中间行
L: 光标移动到屏幕最后一行行首
G: 移动到指定行,行号 -G
w: 向后一次移动一个字
b: 向前一次移动一个字
{: 按段移动,上移
}: 按段移动,下移
Ctr-d: 向下翻半屏
Ctr-u: 向上翻半屏
Ctr-f: 向下翻一屏
Ctr-b: 向上翻一屏
gg: 光标移动文件开头
G: 光标移动到文件末尾
删除命令:
x: 删除光标后一个字符,相当于 Del
X: 删除光标前一个字符,相当于 Backspace
dd: 删除光标所在行,n dd 删除指定的行数 D: 删除光标后本行所有内容,包含光标所在字符
d0: 删除光标前本行所有内容,不包含光标所在字符
dw: 删除光标开始位置的字,包含光标所在字符
撤销命令:
u: 一步一步撤销
Ctr-r: 反撤销
重复命令:
文本行移动:
>>: 文本行右移
<<: 文本行左移
复制粘贴:
yy: 复制当前行,n yy 复制 n 行
p: 在光标所在位置向下新开辟一行,粘贴
可视模式:
v: 按字符移动,选中文本
V: 按行移动,选中文本可视模式可以配合 d, y, >>, << 实现对文本块的删除,复制,左右移动
替换操作:
r: 替换当前字符
R: 替换当前行光标后的字符
查找命令:
/: str查找
n: 下一个
N:上一个
替换命令:
把abc全部替换成123
末行模式下,将光标所在行的abc替换成123
:%s/abc/123/g
末行模式下,将第一行至第10行之间的abc替换成123
:1, 10s/abc/123/g
同上,但要用户一个个确认是否替换
:%s/abc/123/gc
查看 Man Page:
光标移动到函数上,Shift-k 光标移动到函数上,3Shift-k,查看第三章的 ManPage
查看宏定义:
[-d: 可以查看宏定义,必须先包含此宏所在的头文件
代码排版:
gg=G: 代码自动缩进排版
vim里执行 shell 下命令:
末行模式里输入!,后面跟命令
16.3 vim分屏操作
分屏操作:
sp: 上下分屏,后可跟文件名
vsp: 左右分屏,后可跟文件名
Ctr+w+w: 在多个窗口切换
启动分屏:
1.使用大写O参数进行垂直分屏
$ vim -On file1 file2 ...
2.使用小写o参数进行水平分屏
$ vim -on file1 file2 ...
注: n是数字,表示分屏的数量,n要大于等于文件个数
关闭分屏
1.关闭当前窗口
ctrl+w c
2.关闭当前窗口,如果只剩最后一个,则退出vim
ctrl+w q
编辑中分屏
1.上下分割当前打开的文件
ctrl+w s
2.上下分割,并打开一个新的文件
:sp filename
3.左右分割当前打开的文件
ctrl+w v
4.左右分割,并打开一个新的文件
:vsp filename
分屏编辑中光标的移动
vi中的光标键是h,j,k,l,要在各个屏之间切换,只需要先按一下ctrl+w
1.把光标移动到上边的屏
ctrl+w k
2.把光标移动到下边的屏
ctrl+w j
3.把光标移动到右边的屏
ctrl+w l
4.把光标移动到左边的屏
ctrl+w h
5.把光标移动到下一个的屏
ctrl+w w
移动分屏
1.向上移动
ctrl+w K
2.向下移动
ctrl+w J
3.向右移动
ctrl+w L
4.向左移动
ctrl+w H
屏幕尺寸
1.增加高度
ctrl+w +
2.减少高度
ctrl+w -
3.让所有屏的高度一致
ctrl+w =
4.左加宽度
ctrl+w >
5.右加宽度
ctrl+w <
6.右增加n宽 (如:n=30)
ctrl+w n <
16.4 vim打造IDE
16.4.1 简洁版IDE
C+p: 生成tags
C+]: 跳转到函数定义
C+t:从函数定义返回
C+o:在左侧打开文件列表
F4: 在右侧打开函数列表
C+n:补齐函数,向下翻
vimrc是vim的配置文件,可以修改两个位置
1. /etc/vim/vimrc
2.~/.vimrc
~/.vimrc优先级高
17 gcc
-v / –v / –version 查看gcc版本号
-I目录 指定头文件目录,注意-I和目录之间没有空格
-c 只编译,生成.o文件,不进行链接
-g 包含调试信息
-On n=0
∼
3 编译优化,n越大优化得越多
-Wall 提示更多警告信息
-D<DEF> 编译时定义宏,注意-D和<DEF>之间没有空格
-E 生成预处理文件
-M 生成.c文件与头文件依赖关系以用于Makefile,包括系统库的头文件
-MM 生成.c文件与头文件依赖关系以用于Makefile,不包括系统库的头文件
binutils 一组用于编译、链接、汇编和其它调试目的的程序,包括ar、as、ld、nm、objcopy、objdump、ranlib、readelf、size、strings、strip
等
* gcc 编译器
* glibc 该库实现Linux系统函数,例如open、read等,也实现标准C语言库,如printf
等。几乎所有应用程序都需要与glibc链接
本节主要介绍binutils中的几种主要工具的作用。
* ar 打包生成静态库
* as 汇编器
* ld 链接器。本节前面介绍用gcc完成链接步骤,其实是gcc调用链接器ld,将用户编译
生成的目标文件连同系统的libc启动代码链接在一起形成最终的可执行文件
* nm 查看目标文件中的符号(全局变量、全局函数等)
* objcopy 将原目标文件中的内容复制到新的目标文件中,可以通过不同的命令选项调
整目标文件的格式,比如去除某些ELF文件头
* objdump 用于生成反汇编文件,主要依赖objcopy实现,a.out编译时需要-g,
objdump -dSsx a.out > file
* ranlib 为静态库文件创建索引,相当于ar命令的s选项
* readelf 解读ELF文件头
19 静态库和共享库
*本节就如何创建和使用程序库进行论述。所谓“程序库”,简单说,就是包含了数据和执行码的文件。其不能单独执行,可以作为其它执行程序的一部分来完成某些功能。库的存在,可以使得程序模块化,可以加快程序的再编译,可以实现代码重用,可以使得程序便于升级。程序库可分静态库(static library)和共享库(shared object)。
19.1 静态库
是在可执行程序运行前就已经加入到执行码中,成为执行程序的一部分;共享库,是在执行程序启动时加载到执行程序中,可以被多个执行程序共享使用。建议库开发人员创建共享库,比较明显的优势在于库是独立的,便于维护和更新;而静态库的更新比较麻烦,一般不做推荐。然而,它们又各有优点,后面会讲到。本节所讲述的执行程序和库都采用ELF(Executable and Linking Format)格式,尽管GNU,GCC工具可以处理其它格式,但不在本节的讨论范围。 静态库可以认为是一些目标代码的集合。按照习惯,一般以“.a”做为文件后缀名。使用ar(archiver)命令可以创建静态库。因为共享库有着更大的优势,静态库已经不经常使用。但静态库使用简单,仍有使用的余地,并会一直存在。有些Unix系统,如Solaris 10,已经基本废弃了静态库。
静态库在应用程序生成时,可以不必再编译,节省再编译时间。但在编译器越来越快的。今天,这一点似乎已不重要。如果其他开发人员要使用你的程序,而你又不想给其源码,提供静态库是一种选择。从理论上讲,应用程序使用了静态库,要比使用动态加载库速度快1-5%,但实际上可能并非如此。由此看来,除了使用方便外,静态库可能并非一种好的选择。要创建一个静态库,或要将目标代码加入到已经存在的静态库中,可以使用以下命令:
ar rcs libmylib.a file1.o
file2.o以上表示要把目标码file1.o和file2.o加入到静态库libmylib.a中(ar的参数r)。若libmylib.a不存在,会自动创建(ar的参数c)。然后更新.a文件的索引,使之包含新加入的.o文件的内容(ar的参数s)。
静态库创建成功后,需要链接到应用程序中使用。使用gcc的-l选项来指定静态库,使用-L参数来指定库文件的搜索路径。比如上述例子应指定-lmylib,所有库文件名都以lib开头,开头的lib在指定参数时应省略。-l和-L之后都直接带参数而不跟空格。
在使用gcc时,要注意其参数的顺序。-l是链接器选项,一定要放在被编译的文件名称之后;若放在文件名称之前则会连接失败,并会出现莫名其妙的错误。这一点切记。
19.2 共享库
共享库的创建比较简单,基本有两步。首先使用-fPIC或-fpic创建目标文件,PIC或pic表示位置无关代码,然后就可以使用以下格式创建共享库了: gcc -share -Wl,-soname,your_soname -o library_name file_list library_list 下面是使用a.c和b.c创建库的示例:
19.2.1 基础班使
gcc -fPIC -c a.c
gcc -fPIC -c b.c
gcc -shared -Wl -o libmyab.so a.o b.o
加载共享库方法:
1.拷贝自己制作的共享库到/lib或者/usr/lib
2.临时设置LD_LIBRARY_PATH, export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径
3.永久设置,把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径 设置到
∼
/.bashrc
或者/etc/profile
4.设置/etc/ld.so.conf, 把库所在路径追加到此配置文件里。
19.2.2 就业班使用
gcc -shared -Wl,-soname libmyab.so.1 -o libmyab.so.1.0.1 a.o b.o 按照共享库的命名惯例,每个共享库有三个文件名:real name、soname和linker name。真正的库文件(而不是符号链接)的名字是real name,包含完整的共享库版本号。soname是一个符号链接的名字,只包含共享库的主版本号,主版本号一致即可保证库函数的接口一致,因此应用程序的.dynamic段只记录共享库的soname,只要soname一致,这个共享库就可以用。如libmyab.so.1和libmyab.so.2是两个主版本号不同的libmyab,有些应 用程序依赖于libmyab.so.1,有些应用程序依赖于libmyab.so.2,但对于依赖libmyab.so.1 的应用程序来说,真正的库文件不管是libmyab.so.1.10还是libmyab.so.1.11都可以用,所以使用共享库可以很方便地升级库文件而不需要重新编译应用程序,这是静态库所没有的优点。注意libc的版本编号有一点特殊,libc-2.8.90.so的主版本号是6而不是2或2.8。linker name仅在编译链接时使用,gcc的-L选项应该指定linker name所在的目录。有的linker name是库文件的一个符号链接,有的linker name是一段链接脚本。例如上面的libc.so就是一个linker name,它是一段链接脚本:
在所有基于 GNUglibc的系统中,在启动一个 ELF二进制执行程序时,一个特殊的程序“程序装载器”会被自动装载并运行。在linux中,这个程序装载器就是/lib/ld linux.so.X(X是版本号)。它会查找并装载应用程序所依赖的所有共享库。被搜索的目录保存在/etc/ld.so.conf文件中。当然,如果程序的每次启动,都要去搜索一番,势必效率不堪忍受。Linux系统已经考虑这一点,对共享库采用了缓存管理。ldconfig就是实现这一功能的工具,其缺省读取/etc/ld.so.conf文件,对所有共享库按照一定规范建立符号连接,然后将信息写入/etc/ld.so.cache。 /etc/ld.so.cache的存在大大加快了程序的启动速度。
1. 修改/etc/ld.so.conf
sudo vi /etc/ld.so.conf
添加你的共享库路径
2. 更新查找共享库的路径
sudo ldconfig -v
3.测试你的程序可否找到共享库
ldd a.out
19.4 项目实战
1.创建一个目录,mycal
mkdir mycal
2.创建4个c文件和1个.h,分别实现加减乘除
add.c
int add(int a, int b)
{
return a+b;
}
sub.c
int sub(int a, int b)
{
return a-b;
}
mul.c
int mul(int a, int b)
{
return a*b;
}
dive.c
int dive(int a, int b)
{
return a/b;
}
common.h
#ifndef COMMON_H_
#define COMMON_H_
int add(int a, int b);
int sub(int a, int b);
int dive(int a, int b);
int mul(int a, int b);
#endif
3.制作静态库
gcc -c add.c sub.c mul.c dive.c
ar rcs libmycal.a add.o sub.o mul.o dive.o
4.制作共享库
gcc -c -fPIC add.c sub.c mul.c dive.c
gcc -shared -Wl,-soname,libmycal.so.1 -o libmycal.so.1.10 add.o sub.o mul.o dive.o
5.设置共享库加载路径
打开共享库路径配置文件
sudo vi /etc/ld.so.conf
最后一行添加mycal路径
/home/itcast/mycal
更新共享库加载路径
sudo ldconfig -v
此时可以看到自动创建出来了,so name libmycal.so.1 手动添加link name
ln -s libmycal.so.1.10 libmycal.so
6.编写测试文件main.c,分别去链接静态库和共享库,进行测试
main.c
#include <stdio.h>
#include "common.h"
int main(void)
{
printf("%d\n", add(5, 3));
return 0;
}
20 gdb调试工具
程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪。到目前为止我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码中适当的位置插入printf,执行程序并分析打印结果,如果结果和预期的一样,就基本上证明了自己假设错误原因,就可以动手修正Bug了,如果结果和预期的不一样,就根据结果做进一步的假设和分析。本章我们介绍一种非常强大的调试工具gdb,可以完全操控程序的运行,使得程序就像你手里的玩具一样,叫它走就走,叫它停就停,并且随时可以查看程序中所有的内部状态,比如各变量的值、传给函数的参数、当前执行的语句位置等。掌握了gdb的用法以后,调试的手段就更加丰富了。但要注意,即使调试的手段非常丰富了,其基本思想仍然是“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环,根据现象如何假设错误原因,以及如何设计新的现象去验证假设,这都需要非常严密的分析和思考,如果因为手里有了强大的工具就滥用,而忽视了严谨的思维,往往会治标不治本地修正Bug,导致一个错误现象消失了但Bug仍然存在,甚至是把程序越改越错。本章通过几个初学者易犯的错误实例来讲解如何使用gdb调试程序,在每个实例后面总结一部分常用的gdb命令。
gcc -g main.c -o main
常用命令
20.1 gdb调试模式
* run 全速运行
* start 单步调试
* set follow-fork-mode child
21 Makefile项目管理
21.1 用途
+ 项目代码编译管理
+ 节省编译项目时间
+ 一次编写终身受益
+ 操作示例文件:add.c sub.c mul.c dive.c main.c
21.2 基本规则
Makefile由一组规则组成,规则如下:
目标:依赖
(tab)命令
如:add.o:add.c
(一个tab缩进)gcc –Wall –g –c add.c –o add.o
目标:要生成的目标文件
依赖:目标文件由哪些文件生成
命令:通过执行该命令由依赖文件生成目标
21.2.1 三要素
* 目标
* 条件
* 命令
21.3 Makefile 工作原理
基本原则:
1.若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来生成该依赖文件。
2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新
* 分析各个目标和依赖之间的关系
* 根据依赖关系自底向上执行命令
* 根据修改时间比目标新,确定更新
* 如果目标不依赖任何条件,则执行对应命令,以示更新
21.4 Makefile 变量
在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单变量定义及使用:
定义了两个变量:foo、bar,其中bar的值是foo变量值的引用。
1、变量定义直接用'='
2、使用变量值用$(变量名)
通常我们在Makefile中会定义一些变量,方便Makefile的修改维护 。
src = main.c func1.c func2.c
CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项 如:-I
CFLAGS:C编译器的选项 –Wall –g -c
LDFLAGS :链接器选项 –L -l
自动变量:
$@:表示规则中的目标
$<:表示规则中的第一个条件
$^:表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。
模式规则:
至少在规则的目标定义中要包含’%‘,’%‘表示一个或多个,在依赖条件中同样可以使用’%‘,依赖条件中的’%’的取值,取决于其目标:模式规则示例:
注意:只有写成模式规则的时候,$<才表示了所有依赖条件的依次取值,否则只是取依赖条件中的第一个。
21.5 Makefile 函数
src = $(wildcard *.c)
找到当前目录下所有后缀为.c的文件,赋值给src
obj = $(patsubst %.c,%.o, $(src))
把src变量里所有后缀为.c的文件替换成.o
21.6 clean
* 用途:清除编译生成的中间.o文件和最终目标文件
* make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令
* 伪目标声明:.PHONY:clean
* clean命令中的特殊符号
–
“-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
–
“@”不显示命令本身,只显示结果。如:“@echo”clean done“”
* 其它
–
make 默认执行第一个出现的目标,可通过make dest指定要执行的目标
–
distclean目标
–
install目标
–
make -C 指定目录 进入指定目录,调用里面的Makefile
–
make -n:只打印要执行的命令,不会真正执行命令
–
make -p:显示隐含规则数据库中的信息
–
make -C:切换到另一个目录中执行该目录下的Makefile
–
make -f:-f执行一个makefile文件名称,使用make执行指定的makefile
21.7 知识图谱