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

 

 

cmake_minimum_required(VERSION 3.0.2) project(hand_igh_v2) ## Compile as C++11, supported in ROS Kinetic and newer add_compile_options(-std=c++11) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) ## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS roscpp rospy ) find_package(Xenomai REQUIRED) ## System dependencies are found with CMake's conventions # find_package(Boost REQUIRED COMPONENTS system) ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html # catkin_python_setup() ################################################ ## Declare ROS messages, services and actions ## ################################################ ## To declare and build messages, services or actions from within this ## package, follow these steps: ## * Let MSG_DEP_SET be the set of packages whose message types you use in ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). ## * In the file package.xml: ## * add a build_depend tag for "message_generation" ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in ## but can be declared for certainty nonetheless: ## * add a exec_depend tag for "message_runtime" ## * In this file (CMakeLists.txt): ## * add "message_generation" and every package in MSG_DEP_SET to ## find_package(catkin REQUIRED COMPONENTS ...) ## * add "message_runtime" and every package in MSG_DEP_SET to ## catkin_package(CATKIN_DEPENDS ...) ## * uncomment the add_*_files sections below as needed ## and list every .msg/.srv/.action file to be processed ## * uncomment the generate_messages entry below ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) ## Generate messages in the 'msg' folder # add_message_files( # FILES # Message1.msg # Message2.msg # ) ## Generate services in the 'srv' folder # add_service_files( # FILES # Service1.srv # Service2.srv # ) ## Generate actions in the 'action' folder # add_action_files( # FILES # Action1.action # Action2.action # ) ## Generate added messages and services with any dependencies listed here # generate_messages( # DEPENDENCIES # std_msgs # Or other packages containing msgs # ) ################################################ ## Declare ROS dynamic reconfigure parameters ## ################################################ ## To declare and build dynamic reconfigure parameters within this ## package, follow these steps: ## * In the file package.xml: ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" ## * In this file (CMakeLists.txt): ## * add "dynamic_reconfigure" to ## find_package(catkin REQUIRED COMPONENTS ...) ## * uncomment the "generate_dynamic_reconfigure_options" section below ## and list every .cfg file to be processed ## Generate dynamic reconfigure parameters in the 'cfg' folder # generate_dynamic_reconfigure_options( # cfg/DynReconf1.cfg # cfg/DynReconf2.cfg # ) ################################### ## catkin specific configuration ## ################################### ## The catkin_package macro generates cmake config files for your package ## Declare things to be passed to dependent projects ## INCLUDE_DIRS: uncomment this if your package contains header files ## LIBRARIES: libraries you create in this project that dependent projects also need ## CATKIN_DEPENDS: catkin_packages dependent projects also need ## DEPENDS: system dependencies of this project that dependent projects also need catkin_package( INCLUDE_DIRS include LIBRARIES hand_igh_v2 CATKIN_DEPENDS roscpp rospy DEPENDS system_lib ) ########### ## Build ## ########### ## Specify additional locations of header files ## Your package locations should be listed before other locations include_directories( # include ${catkin_INCLUDE_DIRS} ${Xenomai_ALCHEMY_INCLUDE_DIRS} /opt/etherlab/include ./include/ ../../devel/include ) ## Declare a C++ library # add_library(${PROJECT_NAME} # src/${PROJECT_NAME}/hand_igh_v2.cpp # ) ## Add cmake target dependencies of the library ## as an example, code may need to be generated before libraries ## either from message generation or dynamic reconfigure # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Declare a C++ executable ## With catkin_make all packages are built within a single CMake context ## The recommended prefix ensures that target names across packages don't collide add_executable(${PROJECT_NAME}_node src/main.cpp src/pdos.cpp src/callback.cpp src/nano17.cpp src/hit_ft_sensor.cpp) ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the ## target back to the shorter version for ease of user use ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" set_target_properties(${PROJECT_NAME}_node PROPERTIES COMPILE_FLAGS ${Xenomai_ALCHEMY_DEFINITIONS}) ## Add cmake target dependencies of the executable ## same as for the library above # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Specify libraries to link a library or executable target against target_link_libraries(${PROJECT_NAME}_node ${catkin_LIBRARIES} ${catkin_LIBRARIES} ${Xenomai_ALCHEMY_LIBRARIES} -L/opt/etherlab/lib -lethercat /opt/etherlab/lib/libethercat.so.1 ) ############# ## Install ## ############# # all install targets should use catkin DESTINATION variables # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html ## Mark executable scripts (Python etc.) for installation ## in contrast to setup.py, you can choose the destination # catkin_install_python(PROGRAMS # scripts/my_python_script # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark executables for installation ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html # install(TARGETS ${PROJECT_NAME}_node # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark libraries for installation ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html # install(TARGETS ${PROJECT_NAME} # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} # ) ## Mark cpp header files for installation # install(DIRECTORY include/${PROJECT_NAME}/ # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} # FILES_MATCHING PATTERN "*.h" # PATTERN ".svn" EXCLUDE # ) ## Mark other files for installation (e.g. launch and bag files, etc.) # install(FILES # # myfile1 # # myfile2 # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} # ) ############# ## Testing ## ############# ## Add gtest based cpp test target and link libraries # catkin_add_gtest(${PROJECT_NAME}-test test/test_hand_igh_v2.cpp) # if(TARGET ${PROJECT_NAME}-test) # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) # endif() ## Add folders to be run by python nosetests # catkin_add_nosetests(test)
最新发布
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值