开发工具
集成开发工具(Integrated Development Environment,IDE)
IDE开发程序非常方便,因为它们提供了程序的编译、运行、调试、项目管理一条龙的服务,
使用IDE的唯一缺陷就是这些IDE安装文件往往很大,编译创建工程时候生成的临时文件很多。略显笨重和臃肿,
大量的封装确实容易上手和使用,方便用户编程,但是也掩盖了底层编译、调试的过程,不利于新手学习。
代码编辑工具:Vim、gedit
在Linux环境下,使用Vim之前首先要安装,
虽然现在大多数UNIX、GNU/Linux操作系统默认安装Vim,但是也有一些操作系统,如Ubuntu,系统自带的默认文本编辑工具是Vi,Vi是 visual interface
的简写,
以前系统编辑文本都使用行编辑器ex命令,后来才有了Vi工具,作为ex的可视化操作接口,可以直接可视化编辑文本,比使用纯命令行处理文本方便了很多,
Vi有很多不完善的地方,比如只能单步撤销、不能使用方向键等,所以就出现了Vi的加强版——Vi Improved,即Vim。
Vim针对Vi做了很多的改进,比如增加了多级撤销、多窗口操作、关键字自动补全等功能,甚至可以通过插件来扩展和配置更多的功能。
Vim安装命令:
# apt-get install vim //Ubuntu操作系统的安装命令,#开头表示当前命令是以root权限运行的
$ sudo apt-get install vim //Ubuntu操作系统的安装命令,$开头表示当前命令是以普通用户权限运行的
# yum install vim //Fedora操作系统的安装命令
# brew install vim //macOS操作系统的安装命令
使用vim -v
查看是否安装成功!
程序编译工具:GCC、make
注意:GCC并不是真正的C编译器,它是GNU C编译器工具中的一个二进制工具,
在编译程序时候,GCC会首先运行,然后由GCC分别调用预处理器
、编译器
、汇编器
、连接器
等工具来完成整个GCC编译过程。
GCC的编译器参数(控制编译过程):
- -E :只对C源程序进行预处理,不编译。即宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
- -S :只编译到汇编文件。即检查语法,将预处理后文件编译生成汇编文件
- -c :只编译生成目标文件,不进行链接。即将汇编文件生成目标文件(二进制文件)
- -o :指定输出的可执行文件。因为C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去,最终生成一个可执行目标文件(或者简称为可执行文件),可以被加载到内存中,由系统执行。
- -g :生成带有调试信息的debug文件
- -O2 :代码编译优化等级,一般选择2
- -W :在编译中开启警告(warming)信息
- -I :大写的I,在编译时候指定头文件的路径
- -l : 小写的L,指定程序使用的函数库
- -L :大写的L,指定函数库的路径
GCC编译程序非常方便,但是也有弊端:
例如,在一个多文件的项目中,如果C源文件过多,如编译Linux内核源码,大概有30 000 多个源文件,使用GCC命令编译,则是这样的
# gcc -o vmlinux main.c usb.c device.c hub.c ...
后面得跟上30 000多个源文件名,这显然是不合理的
所以,针对多文件的编译,可以使用make命令
make其实也是一个编译工具,只不过make在编译程序的时候,需要依赖一个Makefile的文件:生成一个可执行文件所依赖的所有C源文件都在这个Makefile文件中指定。
在Makefile中,通过定义一个个规则,来描述各个要生成的目标文件所依赖的源文件及编译命令,最后链接器将这些目标文件组装在一起,生成可执行文件。
make具体的原理流程:
当使用make编译一个工程时,make首先会解析Makefile,根据Makefile文件中定义的规则和依赖关系,分析出生成可执行文件和各个目标文件所依赖的源文件,并根据这些依赖关系构建出一个依赖关系树。然后根据这个依赖关系和Makefile定义的规则一步一步依次生成这些目标文件,最后将这些目标文件链接在一起,生成最终的可执行文件。
举一个例子:
假设一个项目有两个源文件:main.c和sum.c
//main.c
#include<stdio.h>
int add(int a, int b);
int main(void)
{
int sum = 0;
sum = add(3,4);
printf("sum:%d\n",sum);
return 0;
}
//sum.c
int add(int a,int b)
{
return a+b;
}
如果使用GCC编译的话,命令如下所示:
# gcc -0 hello main.c sum.c
如果使用make工具来编译,那么首先我们需要编写一个Makefile文件:
一个Makefile通常是由一个个规则构成的,规则是构成Makefile的基本单元。一个规则通常由目标、目标依赖和命令3部分组成
目标:目标依赖
命令
- 目标:一般是我们要生成的可执行文件或各个源文件对应的目标文件
- 目标依赖:生成目标所需要依赖的源文件
- 命令:可以编译命令、链接命令或Shell命令,命令必须以Tab键开头
具体的书写:
.PHONY: all clean
all:hello
hello:main.o sum.o
gcc -o hello main.o sum.o
main.o:main.c
gcc -c main.c
sum.o:sum.c
gcc -c sum.c
clean:
rm -f main.o sum.o hello
解释:
Makefile 文件中使用 .PHONY 声明的目标是一个伪目标,伪目标并不是一个真正的文件名,可以看作一个标签。伪目标比较特殊,一般无依赖,主要用来无条件执执行一些命令,如清理编译结果和中间零时文件。
一个规则可以像伪目标那样无目标依赖,无条件地执行一些命令操作,也可以没有命令,只表示单纯的依赖关系,如上面Makefile文件中的all伪目标。
执行的时候,需要将Makefile与main.c和sum.c放置同一目录下,然后再命令环境下输入make命令直接编译项目
# make
gcc -c main.c
gcc -c sum.c
gcc -o hello main.o sum.o
也可以使用 make clean 命令清理程序的编译结果和生成的零时中间文件
make clean
rm -f hello main.o sum.o
Makefile 文件名的第一个字母一般大写,小写也不会出错,因为make在编译程序的时候,会首先查找当前目录下的Makefile文件,找不到再去找makefile或GNUmakefile文件,当这三个都找不到的时候,make就会报错!
项目管理工具:Git
版本控制系统一般分为集中式版本控制系统和分布式版本控制系统
-
集中式版本控制系统
- 软件的各个版本的代码快照只保存在服务器;
用户想要查看某个版本的代码,需要从版本库中拉取到本地计算机上,查看和修改后,再保存到服务器上。 - 缺点:
因为存储在服务器上,使用时需要联网;
一般收费;
可能被员工删库跑路。 - 典型代表:
小乌龟 TortoiseSVN
- 软件的各个版本的代码快照只保存在服务器;
-
分布式版本控制系统
- 不再将整个版本库保存在一个服务器上,而是保存在每个员工的计算机上。
- 优点:
免费;
老板不怕被删库跑路。 - 典型代表:
Git
早期使用TortoiseSVN的比较多,自从Linux内核作者Linus开发出Git这款免费的版本控制工具后,Git变得越来越流行。
参考:
[1]嵌入式C语言自我修养:从芯片、编译器到操作系统/王利涛编著.——北京:电子工业出版社,2021.4