CMakeLists.txt学习
---------------- 3-26
编译过程:源文件.c/.h --> 预编译(处理#开头的预编译指令,如#inclide、#define等) --> 编译(语法、语义分析并优化) --> 汇编(将上一步整理的代码转为机器码) --> 链接(将编译出来的目标文件和代码里用到的库文件打包成最终的可执行文件)
静态库和动态库区别:
静态库在链接这一步的时候把自己直接加载到程序中;程序(可执行文件)运行时就不再需要该静态库,意味着如果库文件更新了,需要重新编译可执行文件;最终生成的可执行文件大
动态库在链接这一步的时候只是给了个接口;程序(可执行文件)运行时通过接口加载,所以程序(可执行文件)运行时还需要动态库存在,意味着库文件更新了,此可执行文件也就更新了;最终生成的可执行文件小
生成静态库和动态库:
注:无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件(就是汇编成机器码那一步)
Linux生成静态库:
gcc -c hello.c // 生成目标文件hello.o, 或者 gcc hello.c -c
ar crv libhello.a hello.o // 将目标文件hello.o 打包成静态库文件libhello.a
Linux联合编译静态库(假如静态库文件是libhello.a ,main.c要使用它):
gcc main.c -L . -lhello // -L 后面是静态库文件所在的目录,h-l加上库名,这个库名是去掉lib和后面的.a。或者 gcc main.c libhello.a -o main
Linux生成动态库:
gcc -fPIC -shared -o libhello.so hello.c // -fPIC 是为了能够在多个应用程序间共享,-shared指定生成动态库。
Linux联合编译动态库:
gcc mian.c -o mian -L ./ -lhello // -L后面是库文件的路径,h-l加上库名,这个库名是去掉lib和后面的.so。或者 gcc main.c libhello.so -o main
补充:当使用gcc联合编译源文件和库时,只需要源文件(或源文件加载的头文件)里有库里的实现函数的声明即可。因为联合声明时你只要定义了再使用,它会去联合了的库里面或者其它源文件里自动找这个实现函数。linux动态、静态库&win动态、静态库:so、a & dll、lib。
编译源文件生成可执行文件:gcc ts.c -o ts || gcc main.c main.h ts.c -o main || gcc main.c libhello.so -o main // 可以将其它的源文件、头文件、库文件一起联合编译
------------------ 3-27
前言:
1.使用gcc联合编译,如果修改了其中的一个源文件,所有文件都会被重新编译一次。为此就出现了makefile文件,makefile就是规则、规则、还是TMD规则~,比如执行makefile时发现依赖比目标要新,那么就不会再编译依赖,而要执行makefile文件就需要命令make。但有些人觉得写makefile规则很麻烦,于是就搞了一个cmake工具,该工具使用cmake命令根据CMakeLists.txt自动生成makefile,而这个生成的makefile可以监听CMakeLists.txt的改变,所以后续如果不是新增编译规则直接make编译即可
2.常见的预处理指令 :#ifndef F(如果没有定义F就执行下面的内容)、#ifdef F(如果定义了F就执行下面的内容)、#define F(定义一个标识符F,特点是它定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了)、#else 、#endif;我们很多时候在头文件里会看到:
#ifndef __hello_h__ #define __hello_h__ // 内容 #endif //意思是在预编译的时候如果没有__hello_h__ 就执行下面的内容,下面呢就通过#define生成了__hello_h__,这个生成的__hello_h__在预编译完之前是不会消失的。 //假设在预编译完之前又有其它的地方需要这个头文件,想再编译它的时候__hello_h__已经存在了,所以不会再次编译。也就是防止多次编译。那为什么标识符要起的这么复杂,因为怕和其他define的内容搞重了
基本使用:
首先 cmake . (. 表示CMakeLists.txt所在的目录,cmake就是通过CMakeLists.txt来生成makefile的。或指定编译器生成makefile:cmake . -G "Unix Makefiles") --> make(根据makefile里的规则开始编译,所以要和makefile在同目录) --> 生成CMakeLists.txt里定义的项目名称的可执行文件,最后执行一下就好了。
注意:cmake会在当前目录生成makefile等其它文件和源文件混在一起就很乱了,一般是建一个build文件夹在里面执行cmake .. ;
------------------ 3-28
add_executable(hi main.c)
1. 普通使用生成可执行文件
add_executable(hi WIN32 EXCLUDE_FROM_ALL main.c hi.c) hi:生成的可执行文件名字 WIN32:有这个参数的话WIN32_EXECUTABLE属性会自动变成true,表示在windows环境下创建可执行文件,C程序入口函数(main)会被WinMain函数代替,生成的可执行文件为GUI应用程序而不是控制台应用程序。同理有MACOSX_BUNDLE参数的话MACOSX_BUNDLE属性会被置为true,此时如果在macOS或者iOS上构建可执行文件目标的话,目标会成为一个从Finder启动的GUI可执行程序 EXCLUDE_FROM_ALL:有此参数时,表示不会生成这个可执行文件,需要自己在后面手动编译生成(make hi) main.c hi.c:生成可执行文件所需要的源文件。如果可执行文件和库文件已经生成了,后面想给它再加源文件进去编译,使用target_sources(hi xx.c)即可 2. 导入可执行目标文件add_executable (IMPORTED [GLOBAL])