CMakelist. How to use and master CMakeList.txt

makefile文件依赖关系复杂,并且跨平台不优秀,因此,使用cmake这种自动工具,

自己看的参考版本是:cmake 实践。  http://file.ncnynl.com/ros/CMake%20Practice.pdf

1)跨平台的意思是: 可以在linux/unix平台生成makefile,又可以在苹果平台生成xcode.在windows平台则可以生成MSVC的工程文件。

2)cmake需要编写的是CMakeLists.txt,注意,需要每个目录一个,使用的是cmake 语言和语法。

3)如果没有实践,那么就在这停止学习吧,因为读的再多,几天后也会忘记。

4)cmake当然需要安装,只是在linux中,好多linux版本都已经安装好了cmake软件。

5)第一个t1测试,抄,自己也将ADD_EXECUTABLE(hello ${SRC_LIST)中${}给剩下了。

出错原因以及解决方法汇总:https://blog.csdn.net/felaim/article/details/71511909

总不能一直根据readme.txt安装依赖库,然后mkdir build, cd build, cmake .., make, make install

6)首先CMakeLists.txt必须注意,CM大写,L大写,list是复数。因为这个文件名确实是 大小写相关的。但是CMakeLists.txt文件内部,则没有明确的大小写要求。

并且还有一点,就是如果工程存在多个目录,那么需要确保每个要管理的目录都存在一个CMakeLists.txt文件。

7)开始解释hello涉及的语法指令,

7.1)PROJECT(projectname [cxx] [c] [Jave])该命令,1、可以省略后面的语言支持列表,因为默认支持所有语言。2,定义了,隐藏的定义,定义了两个cmake变量variables. _BINARY_DIR 和 _SOURCE_DIR,也就是说cmake中同样要遵守,定义了才可以使用,因此第一行PROJECT()指令就专门隐形生成了两个变量,在后面MESSAGE(STATUS “This is BINARYdir” ${HELLO_BINARY_DIR})

这种,但是自己并没有在生成makefile成功后见到这两个DIR的name.....这两个隐藏的定义变量有什么用??而这两个默认的变量与系统通用的两个变量一模一样,为了防止用户修改了用户名,后面对于CMakeLists.txt做好多涉及名字的修改,那么使用PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR变量即可。这两个变量是自动与会变化的projectname_BINARY_DIR 和projectname_SOURCE_DIR相互挂接的。

7.2)SET指令。SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

现阶段,我们只记住,这个SET用于显式地定义变量即可。例如:SET(SRC_LIST main.c t1.c t2.c)等,这种一串多个源文件的构成。

7.3)MASSAGE指令。

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

这个基本可以认为是:printf和sterr这种结合了,既能够按照设定级别报错也能够输出产生的信息。

其中[]并不是说敲命令要敲出来,而是说,方框中的是N选一而已。SEND_ERROR是产生错误,而错误会被跳过去。

STATUS是前缀加个- 表明输出信息内容。 自己打印出来貌似是两个横杠 - -

FATAL_ERROR这个表示立即停止所有的cmake过程。

中间的引号是文字,而后面的三个点是自己定义的变量啊之类的,

7.4) ADD_EXECUTABLE(hello ${SRC_LIST})

上述说明,首先前面的是生成的可执行文件名称就是最后./xxx这个执行的名字。然后后面是,生成这个名字需要用到的相关源文件列表。

7.5)cmake的基本语法:

变量引用方式:${}这种类型方式。而IF中控制语句使用的是直接放变量名字,因为判断的是这个变量名字,而不是变量内容,

指令(参数1 参数2  ...)这种

参数使用括弧括起来,参数之间使用空格或者分号分开。注意,是参数,不是变量。例如ADD_EXECUTABLE(hello main.c t1.c)变为:ADD_EXECUTABLE(hello main.c; t1.c)

上述,指令是大小写无关,但是推荐使用全部大写指令。而参数和变量是大小写相关的。

cmake很灵活的一个语法:SET(SRC_LIST main.c)以及SET(SRC_LIST "main.c")这种的是等效的。。但是加上双引号的好处是:可以将一个完整的带空格的文件名字括起来,然后当成一个文件即可。而且对于文件,自己还可以使用:无后缀的,那么cmake可以自动搜索所有相匹配的文件名字。

7.6)最简单的hello写法:不用使用SET()来定义SRC_LIST 因为只有一个main.c那么使用:

PROJECT(HELLO)

ADD_EXECUTABLE(hello  main.c)就行了。。。

 

8)清理工程:

跟经典的make 一样,make clean即可。

而不能删除make distclean,这个make distclean是为了能够删除中间文件,因为最后发布不需要给出中间文件的。那么注意,此时由于CMakeLists.txt是关于脚本生成的,没有办法追踪临时文件,所以没有可靠的make distclean方案。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx分割线xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1)上述是,内部构建,in-source_build,而cmake 推荐的是out-of-source build

因为,内部构建会导致:生成的临时文件,比自己的代码都多。。实在不想使用了,那么怎么办,使用外部构建即可。

2)构建hello的外部构建方法

2.1) 删除内部构建产生的所有中间文件,就保留自己的main.c 和CMakeLists.txt。其中最关键的是删除CMakeCache.txt文件。

关于删除方式,使用两种,一种是使用ls -a列出来文件夹下面所有的内容,然后,再使用 | grep -v "name1" "name2"

这样反向选择不删除的,打印出来发现全部是名称:ls -a | grep -v "name1" "name2" 这种,然后删除方法是:

rm -rf ` ls -a | grep -v "name1" "name2" `

这种就是必须使用反向的单引号来处理这个。

2.2)创建build目录,mkdir build ,

2.3) 进入build 目录,执行cmake,但是注意由于cmake虽然是自己找CMakeLists.txt文件,但是要指定正确的CMakeList.txt文件路径,所以此时的cmake后面是..指向父文件。 cmake ..

2.4)这样做了以后,出现的情况就是说: 所有的makefile以及中间文件都在build文件夹中,然后在build中执行make,就生成了目标文件。就是说,所有的东西自己将其框在一个文件中,与源代码完全隔离,不会很乱。

2.5)总结:通过外部构建,我们发现,仍然由PROJECT 默认生成了2个隐式变量,<>SOURCE_DIR,和 <>_BINARY_DIR,后者指代编译路径,是自己创建的build路径。而源代码路径与内部构建的时候,没有任何区别的。

总结:三个指令,然后PROJECT指令生成了2个隐式变量。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx分割线。外部构建out-of-source 工程构建过程。xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1)添加src目录放置完整的源代码内容。

2)添加doc目录,来放置工程的说明文档。

3)在工程目录中添加文本文件COPYRIGHT, README;

4)在工程目录中添加一个runhello.sh脚本,用来调用hello二进制。

5)将构建后的目标文件放入构建目录的bin子目录中,最终安装这些文件,将hello 二进制与runhello.sh安装到/usr/bin和将doc目录内容以及COPYRIGHT , README安装到/usr/share/doc/cmake/t2中。

语法声明:

1)ADD_SUBDIRECTORY(source_dir  [binary_dir]  [EXCLUDE_FROM_ALL])

这个函数厉害在于,不仅仅是指定存放源文件的子目录,而且是指定了中间二进制和目标二进制存放的位置。

当这个里面不再用binary_dir设置,那么默认产生的binary文件是在source_dir文件中的,即编译结果放在这里面。

2)不管ADD_SUBDIRECTORY怎么设置,其实我们都可以通过SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin )来重新设定保存路径,SET(LIBRARY_OUTPUT_PATH $(PROJECT_BINARY_DIR)/lib)这种,

3)如何安装,其实以前并没有学习过。

使用的是INSTALL指令。封装的是使用make的install命令,其中make的命令是:

DESTDIR= xxxxx

install:

mkdir -p $(DESTDIR) /usr/bin

install -m 755 hello $(DESTDIR) /usr/bin

上述首先,先生成usr/bin文件,然后install这个bin文件到指定的bin目录中,使用的install -m 表示的是,install是linux自有的命令,使用install --help我们可以看到:-m就是chmod的方式,来确定其可执行方式。

4)那么,helloworld怎么安装呢?需要引入一个新的cmake指令,INSTALL和一个非常有用的变量,CMAKE_INSTALL_PREFIX这个变量类似于configure脚本的-prefix,常见的使用方法看起来是这样的,

使用区别是,这个INSTALL()函数里面的参数,是:指定的,RUNTIME 类型 DESTINATION 是默认由PREFIX前缀以及后面的名字组成。

INSTALL(TARGETS targets... [[ARCHIVE|LIBRARY|RUNTIME] [DESTINATION

]  [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT ] [OPTIONAL] ] [...]) 参数中的 TARGETS 后面跟的就是我们通过 ADD_EXECUTABLE 和ADD_LIBRARY定义的目标文件。可以是二进制也可以是动态库,静态库。其中的选项,可以选择使用,例如PERMISSIONS 这个选项就不用了。而DESTINATION这个是可以放置最后的相对路径,此时注意不要以/开头,不然前面的变量CMAKE_INSTALL_PREFIX就无效了。

5)CMake中INSTALL能安装的类型有: 普通文件FILES,目录DIRECTORY,二进制TARGETS,静态库TARGETS,动态库TARGETS,非目标文件的可执行程序 PROGRAMS安装。其中既然发现二进制,静态库,动态库使用的是同一个名字,且是复数,那么就是说,其实区分在于后面的[ARCHIVE | LIBRARY | RUNTIME]

且安装的时候,对于DIRECTORY这种格式,使用的是名字后面有没有/区别很大,有/表示安装的是该目录下的文件,没有/表示的是安装的就是带这个文件夹一起安装过去了。

一般定义CMAKE_INSTALL_PREFIX的方法是: cmake -DCMAKE_INSTALL_PREFIX = /tmp/t2/usr ..

而这个上面的输入,就是平时自己用的cmake .. #既然是.. 表明了是,外部编译。只是此时在编译使用cmake命令的时候,给加上了宏定义!!!

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx分隔符号xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

静态库和动态库的构建,不再是cmake的变量CMAKE_INSTALL_PREFIX的定义了。

1)静态库和动态库的构建

注意,代码都一样,而生成可执行代码和文件库的区别是:

一个是ADD_EXECUTABLE(name  SRC_LIST)一个是ADD_LIBRARY (name  [SHARE | STATIC | MODULE]  SRC_LIST)

这才是决定不同的生成内容。但是如果同样的名字,生成STATIC时候,会失败,因为重复名字了。一个静态一个动态名字相同了。并且ADD_LIBRARY中,name不用写hello.so 或者hello.a因为后缀会根据SHARE,STATIC,MODULE自动生成的。

2)怎么得到同样名字的动态静态库??虽然上述,改下静态库的名字就可以了,但是明显不是编程设计者想要的结果。

3)我们需要在lib/CMakeLists.txt中添加一条:SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")这样,我们就可以同时得到libhello.so、libhello.a两个库了。

4)添加版本号的时候:

同样是SET_TARGET_PROPERTIES(name PROPERIES VERSION 1.2 S0VERSION 1)这个函数,

5)生成库文件以后,那么安装共享库和头文件的方法是:

INSTALL()指令,在CMAKE中不用函数说法,都是指令内容。,前面讲过,分别用的主体是TARGETS和FILES

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx安装完成以后xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1) 安装完成以后,怎么使用外部共享库和头文件,

我们需要给源代码src文件夹中的CMakeLists.txt添加内容,那么,内容是:INCLUDE_DIRECTORIES_BEFORE([] [] dir1 dir2 ...)

该指令是用于添加多个指定的搜索路径,头文件搜索路径,

头文件有了,那么共享库怎么添加呢??

2)TARGET_LINK_LIBRARIES(target library1 library2)注意前面的target是目标,而后面的才是要添加的库名字,所以TARGET_LINK_LIBRARIES(main hello)   TARGET_LINK_LIBRARIES(main hello.so)是一样的。想链接静态库也很简单:使用hello.a即可。

3)CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH这两种,不是cmake变量,而是环境变量,只是这两个环境变量用于指示cmake的地址的,头文件地址,可以使用export CMAKE_INCLUDE_PATH 这种命令来智能地选择。

4)

 

 

你可能感兴趣的:(Makefile)