CMAKE 备忘。

来源:互联网 发布:淘宝怎么设置起拍数量 编辑:程序博客网 时间:2024/05/29 18:36

简单实用cmake,文件:《CMAKE Practice》

一、语法

1、project

project(projectName [CXX | C | JAVA])
定义工程名称,并可以指定工程支持的语言。(支持的语言列表其实可以忽略,默认支持所有语言)

隐式定义了两个cmake变量
< projectName>_BINARY_DIR
< projectName>_SOURCE_DIR

但cmake其实帮我们预定义了
PROJECT_ BINARY_DIR
PROJECT_ SOURCE_DIR

2、SET

SET(VAR VALUE)
例如:
SET(SRC_LIST main.c t1.c t2.c)

3、ADD_EXECUTABLE

ADD_EXECUTABLE(object ${ SRC_LIST})
定义工程会生成一个文件名叫object的可执行文件,相关源文件是SRC_LIST中定义的源文件列表

二、目录结构

1、内部构建与外部构建

内部构建:源文件与生成的临时文件 混在一起
外部构建:源文件与生成的临时文件 分开

举例:
目录/home/xxx/t1 : main.c CMakeLists.txt

内部构建:
在/home/xxx/t1下,直接
cmake .
make
于是在/home/xxx/t1目录生成了一些临时文件和源文件混在一块

外部构建:
选择一个其他的目录,就是选择一个除了/home/xxx/t1以外的目录。
一般在/home/xxx/t1目录下建立build目录。
即在/home/xxx/t1下:
mkdir build
cd build
cmake .. (cmake后跟CMakeLists.txt所在目录)
make
于是源文件依然在/home/xxx/t1目录下,而生成的文件在/home/xxx/t1/build下,显得井然有序。

而且!在外部构建下:

变量名 指代路径 例子中的路径 < projectName>BINARY_DIR或PROJECT BINARY_DIR 指代编译路径 /home/xxx/t1/build < projectName>SOURCE_DIR或PROJECT SOURCE_DIR 指代工程路径 /home/xxx/t1

三、更为标准的工程格式?

希望更健全的格式请看《CMAKE PRACTICE》
我认为工程格式够用的格式是:
1、工程拥有子目录src
2、构建后的目标文件放在子目录bin上。

就俩点。。。

举例:

这里写图片描述

目录结构如上,其中2个CMakeLists.txt内容也给出了。
我们会看到,在构建目录t1下的cmakelists.txt其实并不编译,在src目录下才真正编译可执行文件hello。

那么t1目录下的CMakeLists.txt是充当什么角色呢?
其中有个句子:

ADD_SUBDIRECTORY(src bin)

这句是告诉cmake程序,它还添加了一个子目录src,并指定了中间二进制和目标二进制存放的位置。

这里穿插一个语法ADD_SUBDIRECTORY。

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,比如,工程的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建。

那么指不指定第二个参数(即中间二进制和目标二进制存放的位置)有什么影响呢?
①加bin,外部编译(外部目录为build)。
build目录下有bin目录,存放了中间二进制和目标二进制。但没有src目录
②加bin,内部编译
构建目录下有bin目录,src目录内文件不变。
③不加bin,外部编译(外部目录为build)。
build目录下为src目录,但其中只是存放中间二进制和目标二进制,并没有main.c文件(并不含源文件)
④不加bin,内部编译
构建目录下src目录加入了一些中间二进制和目标二进制文件。混在一起。。

由此,我们可以知道ADD_SUBDIRECTORY(src bin)的意思是:
工程要添加的子目录是src,我们告诉cmake要去src那里也看看,并把编译输出放在bin文件,如果没指定bin就默认放在src,其中该src并不一定是构建目录下的src,而是编译路径下的src,当内部编译时候,两者是同一个目录。

换个地方保存目标二进制

我们都可以通过 SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

我们提到了< projectname>_BINARY_DIR 和 PROJECT_BINARY_DIR 变量,他们指的编译发生的当前目录,如果是内部编译,就相当于 PROJECT_SOURCE_DIR 也就是工程代码所在目录,如果是外部编译,指的是外部编译所在目录。

问题是,我应该把这两条指令写在工程的 CMakeLists.txt 还是 src 目录下的CMakeLists.txt,把握一个简单的原则,在哪里 ADD_EXECUTABLE 或 ADD_LIBRARY,如果需要改变目标存放路径,就在哪里加入上述的定义。

四、静态库和动态库

ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 … sourceN)
你不需要写全 libhello.so,只需要填写 hello 即可,cmake 系统会自动为你生成
libhello.X
类型有三种:
SHARED,动态库
STATIC,静态库
MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。

静态库动态库同名问题:
举例:

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

然后再在 build 目录进行外部编译,我们会发现,静态库根本没有被构建,仍然只生成了一个动态库。因为 hello 作为一个 target 是不能重名的,所以,静态库构建指令无效。

怎么办??

SET_TARGET_PROPERTIES,其基本语法是:
SET_TARGET_PROPERTIES(target1 target2 …
PROPERTIES prop1 value1
prop2 value2 …)

在本例中,我们需要作的是向 CMakeLists.txt 中添加一条:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME “hello”)

五、使用外部共享库和头文件

5.1使用外部头文件

INCLUDE_DIRECTORIES(头文件搜索路径)

5.2添加共享库

需要两个指令

1、LINK_DIRECTORIES(directory1 directory2 ……)
添加非标准的共享库搜索路径

2、TARGET_LINK_LIBRARIES(target library1 library2 ……)
为target添加需要链接的共享库

举例:
TARGET_LINK_LIBRARIES(main hello)
也可以写成
TARGET_LINK_LIBRARIES(main libhello.so)

基本上上述是我觉得可以搞定平时的练习和项目的了……不够可以再去翻翻或者去看官网。

六、后续 cmake使用过程中出现的错误。

6.1 参数区分大小写?

add_subdirectory( src bin EXCLUDE_FROM_ALL)

其中add_subdirectory大小写都无所谓,但括号中第三个参数,即EXCLUDE_FROM_ALL,必须大写。。

6.2 使用文件名后缀

应该很少人犯这个错误。
PROJECT(projectName )会帮我们自动选择是C还是C++还是java

举个错误的例子:
我写了一个c++的文件,但后缀名却用了xxx.c的格式,然后cmake以为是C文件,于是发生了错误。。

解决方法:改掉后缀即可。。。

原创粉丝点击