您的位置:首页 > 编程语言 > C语言/C++

C++编译库文件

2016-04-12 20:05 337 查看
本人小白程序猿,之前写过C++ ACM,但一直没有关注过编译,都是直接IDE,一直不了解原理。最近老板给了个任务,要用一个类似Maven的工具来编译C++,因为项目是用C++,Java还有一些脚本混合编程的。编译Java倒好办,直接用Maven就行了,编译C++,大概也知道用g++或者gcc,但一直没有实际用过大项目,今天就研究了一发,真是博大精深。

编译

首先编译,在操作系统的课程中有介绍过,就是把高级语言(c++,java这些)翻译成汇编,这个过程就是编译,然后汇编再和一些库链接,然后生成可执行文件(windows上是exe,Linux上是elf)。

动态链接和静态链接

其次就是涉及到动态链接和静态链接。这个概率在c++虚函数的老师也提及过,虚函数其实就算是一种动态链接,在运行的时候才匹配,其他的那些函数属于动态链接,在编译的时候就匹配……虚函数的水太深了,虽然之前看过几次,但还是有点忘了,这里就不讨论了。

跟虚函数很类似,或者说就是同一个东东,库的加载也分动态加载和静态加载。静态加载就是在编译之后,就加载静态库函数,然后整合进可执行文件中;动态加载是在程序运行的时候才加载库函数。

可认为静态加载就是把库函数全部打包进可执行文件,就好像吃饭的时候,你把你需要吃的菜全部都放进你的碗里(菜就是库函数,碗就是你的可执行文件),动态加载就是你需要吃菜的时候才去夹菜。

所以就会有两个情况,如果你的库函数太大,生成可执行文件的速度就会慢,而可执行文件比较大,因为全部都在可执行文件里面了,但是在运行的时候就会很快,因为不需要从外界获取库函数了。但是如果是动态加载,生成可执行文件的速度会很快,而且所需要的空间不大,但是运行过程中可能会比较慢。

但是总体来说,当项目很大的时候,有很多库函数是公用的,如果都用静态加载,那么会是的好几个可执行文件里面都有静态的库函数,这样就浪费空间了。所以一般会比较常使用动态链接库(linux 是so文件,windows是dll文件)。

如何生成静态链接库和动态链接库呢

/content/3614369.html 这篇博客介绍得很清晰了,而且还介绍了什么是动态库什么是静态库。

这里就不重复了,不要重复造轮子

Make和Makefile

上面的博客主要是用g++来介绍生成编译的库,但是如果遇到项目文件比较大的时候,这个时候用g++或者gcc效率会比较低。当然你也可以写一个shell脚本进行批量编译,这的确是可行,但是有一个对于大项目致命的缺点:当项目文件很多的时候,但我只更新其中几个文件的时候,如果用shell进行编译或把之前没有改动的文件一起编译,造成资源浪费,所以可以通过Linux上面一个很厉害的命令,make。

Make是Linux上一个命令,这个命令就是给大项目提供批量编译的,主要的原理是通过一个叫makefile(文件名就是makefile,可以认为是类似于maven中的pom之类的配置文件)的文件,里面记录每个文件的依赖,通过哪些文件生成哪些文件,当然这个东西是不能自动帮你下载东西的,然后主要是用gcc的命令。具体格式如下图所示,奇数行是依赖关系,偶数行是命令,这个命令前面要加tab的,不能用空格代替,命令是gcc的命令,所以在编译c++的时候会有所不同,下面会提到。



所以自己就可以把上面的博客改写成用makefile的形式,然后用make命令就可以搞定了,如下图(相比上面的博客稍有改动)

这里注意一点,还有一个参数是-lstdc++,这里因为用的是gcc的命令,gcc主要是给C编译的,所以不会自动去找C++中std的库,所以要自己手动加个参数,如果是g++就不用,因为g++本身就是给C++编译的。这里具体参数的意思可以参照上面那篇博客(人家已经讲得很好了,就不重复造轮子了)



C++头文件(.h)和源文件(.cpp)

说完了编译,但是可能很多人对C++的头文件和源文件没有清楚的概念,其实我之前也是,也是为了做这个项目,才了解了一下,之前一直用C++做ACM,也没有意识到有什么区别。

如果有做过Java或Android的人应该知道package这个概念,其实可以把C++的头文件和源文件看做是一个package,参考来自于下面的博客。至于package也可以认为是库,有时候一个项目会反复用到很多代码,这个时候只要有一个库函数,定义了这些程序,这时候只要把这些库包含进来就行了,例如c++的include,Java的import,php的require,c#的using都是类似的效果。

/article/5062202.html

回到C++来,可以认为头文件里是定义的接口,这里稍微解释一下接口这东西,因为自己曾经也是这么无知,接口就是类似于一个窗口,例如像遥控器上面的按钮,我只需要知道按哪个有什么效果,至于里面怎么实现的可以不用管,像java,c#里面都有类似的概念。

例如你在头文件里面定义了int add(int a,int b)的函数,这个函数的作用就是实现a+b,这就可以认为定义了一个借口,至于怎么实现,就去源文件里面实现。然后使用这个函数的时候,你就直接包含头文件就可以了,大概就是这样一个逻辑。

一般在头文件中需有一个#ifndef的宏定义,这是为了防止在引用的时候被反复编译,这样只要这个库函数被编译一次就可以了,如下图所示,至于那个名字,随便取什么都可以,就是个变量名而已,不过一般建议和这个头文件的名字保持一致比较规范。如下图所示global.h



在头文件里面定义好接口之后,就在源文件里面定义实现,如下图所示(part.cpp)



然后在main.cpp里面这样写就可以了



当然有人可能会问难道引用库函数一定要使用头文件么,其实可以不用,可以直接写在源文件中,例如一个写函数在一个cpp中,然后另一个cpp调用这个函数,如这篇博客所说

http://www.crazyant.net/414.html

这样也是可以的,不过这相当于把两个cpp合在一起,在链接的整合的时候会写入同一个可执行文件中,这和静态库差不多,只是把合起来的工作放在了编译的时候,而静态库加载是放在写代码的时候,原理差不太多

因为前人,才能更高

1.讲解动态、静态库,在Linux,Windows下生成动态静态链接库

/content/3614369.html

2. 比较详细的讲了一下c++头文件和源文件(可参照我给的代码理解一下)

/article/5062202.html

3. 另一种不用头文件的库引用 http://www.crazyant.net/414.html

以及很多其他博客,由于大部分博客个人感觉说得太笼统,或者太冗余,就不列出了,不过还是感激各位前人的资料
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: