持续创作,加速成长!这是我参与「掘金日新计划·6月更文挑战」的第7天,点击查看活动详情
本文使用的项目是universe项目,宇宙的意思,提取码:mku9。请下载后放在Document目录,项目结构如下:
这个项目是这样的,zeus是宙斯的意思,他可以控制3个星球,太阳,月亮,月球旋转。
大部份C/C++开源项目,程序文件都有几百个,甚至几千几万个文件,并且不要被多文件吓到。gcc编译的时侯实际上都是单文件编译,之后链接阶段才是多文件,整个流程图如下:
本项目的编译命令如下:
gcc -c -o zeus.o zeus.c
gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c
复制代码
提示:以上命令可以加上-v或则-###显示更多的编译信息。
里面的命令,我是先编译zeus.c文件的,尽管这个zeus.c文件依赖sun.c,moon.c跟earth.c3个文件,并且编译阶段不须要晓得这3个C文件的存在,只须要在代码里include一下她们的头文件,晓得函数的定义即可。
编译阶段不须要晓得依赖函数的具体实现。
编译完成以后,执行以下命令开始链接:
gcc -o zeus zeus.o sun.o moon.o earth.o
复制代码
运行情况如下:
至此,一个多文件的C项目,就编译完成。
不过目前的示例过分简单,好多项目的C文件会嵌套使用函数,比如现今有个新需求,太阳转的时侯月亮要跟随转。所以我们在sun.c上面改动一下代码,加上以下代码:
由于sun.c调用了moon_rotate()函数,所以须要引入moon.h头文件,并且不要被引入头文件这个操作蒙蔽,在编译阶段,sun.c跟moon.c仍然是没有一丁点关系,仍然是独立编译。
在编译阶段,sun.c上面的moon_rotate()会被替换成call00000000,占下位置。
在链接阶段,链接器都会去扫描moon.o文件,找到moon_rotate()函数的真正地址,之后进行替换,由于moon_rotate()函数被调用了两次,第一次是在zeus.c上面调用,第二次是在sun.c上面调用,所以链接器须要替换两个地方的地址。
再执行之前的编译命令linux操作系统培训,运行疗效如下,月亮旋转了两次。
里面的事例还是偏简单,在实际项目中,你可能会碰到一些Makefile,gcc接受多个输入文件的情况,之前说过,gcc可以接受多个输入文件。
如今sun.c依赖moon.c的函数,我们试着把这两个文件一起编译,瞧瞧会如何?
gcc -c -o sun-moon.o sun.c moon.c
复制代码
从上图可以看见,这条命令立刻报错了,由于编译多文件的时侯,不能使用-c参数,-c参数是让gcc不要进行链接操作。
俺们把-c去除,再跑一次。
仍旧报错,这是由于虚拟主机 linux,假如gcc步入链接阶段才会去找main函数的具体地址,而main函数的地址在zeus.o上面,zeus.o没传递给gcc命令行参数,所以就报错了。
因而,无论是多庞大的C/C++项目,编译阶段,都是单个文件编译的,单个文件上面引用了外部的变量,函数。编译阶段只会把那些引用替换成一些占位符号,比如0000。
只有在链接阶段,gcc才可以接受多个文件作为输入。之后扫描这种输入文件,找到各个函数符号地址,之后进行替换。链接器一般会扫两次输入文件,第一次找到所有符号,第二次才开始替换占位符号。
一般小型C/C++项目编译问题,主要有以下几种:
1,找不到头文件,错误信息如下:
里面的报错,是由于我把moon.h头文件删了。
找不到头文件这些编译错误如何解决linux mk文件 编译,一般是头文件的搜索路径上面没有相关的moon.h。这时侯,须要查看gcc命令会从什么目录查找头文件。
只需加上-v参数即可,命令如下:
gcc -v -c -o sun.o sun.c
复制代码
扩充知识:Linux环境的大部份软件的用法,都在--help上面,学会看--help跟日志是极其重要的。而Windows的大部份软件linux mk文件 编译,也有--help,而且谷歌的文档更全面一些,英文版的文档谷歌更全面一些。
上图中韩志的意思是,会在当前目录跟/usr/include,/usr/local/include等等这种目录下搜索moon.h,因为这种目录都没有moon.h文件,所以编译器都会报错。
为此,假如你的项目编译的时侯编译器找不到头文件,而你确确实实有头文件,那就是头文件的目录不在编译器搜索路径上面,加起来即可,可以通过-I参数加上搜索路径。
gcc -v -c -o sun.o sun.c -I/home/ubuntu/
复制代码
里面的命令可以编译成功,由于我把moon.h放在了/home/ubuntu/目录下边。
#include引入头文件有两种写法。
#include "moon.h"
#include
复制代码
是只在系统目录下查找,不在当前目录查找,找不到头文件就报错。"moon.h"会在当前目录查找,也会在系统目录查找。
2,undefinedreference,错误信息如下:
前面这个错误是由于我把moon.o写漏了,加上即可。
3,C/C++小型项目还有好多编译静态库,动态库的常见问题,下一篇文章再做讲解。