CMakeList静态库多层嵌套问题 undefined reference to

9 篇文章 0 订阅
4 篇文章 0 订阅

前言

被一个问题缠绕了很长时间,这两天花精力好好研究了一下,总算解决了,翻过来看,就是自己不注意造的很多小问题。我的想法是把一些代码封装起来,但是有些部分要求能让现场工作同事有一定的改动空间,比如接口部分、协议部分、都是可以改动的,但是有些地方怕他们改错,所以需要封装起来。

问题描述

我的工程是ROS工程,用CmakeLists.txt,基于上述想法,把一部分类封装成库,另外一部分暴露出来,在封装库的时候涉及到了静态库的多层嵌套问题。我的CmakeLists.txt架构是这样的:

CmakeLists.txt架构

		

find_package(Boost REQUIRED COMPONENTS system) #需要的第三方库find_package,这里只是用boost示意一下
#可以放到 THIRD_PARTY_LIBS
set( THIRD_PARTY_LIBS
        ${catkin_LIBRARIES}
        ${Boost_LIBRARIES}
        ${PCL_LIBRARIES} 
        )
link_directories(${PROJECT_SOURCE_DIR}/lib  #自己封装的库的位置

               ) 
#------------------------------本工程生成的库----------------------------------------               
#封装库filter ,会生成 libfiter.a
add_library(filter STATIC ${PROJECT_SOURCE_DIR}/src/filter.cpp)

target_link_libraries(filter
                                     ${PCL_LIBRARIES}
                                     ${THIRD_PARTY_LIBS})

#封装库segment ,会生成 libsegment.a
add_library( segment STATIC ${PROJECT_SOURCE_DIR}/src/segment.cpp)
target_link_libraries(segment
                                     ${PCL_LIBRARIES}
                                     ${THIRD_PARTY_LIBS})

#-----------------------------------调用的库-----------------------------------


#***注意*** 这里的object依赖自己生成的其他静态库:libbuild.a ,libtracking.a,就是这里出现的问题
add_library( object STATIC ${PROJECT_SOURCE_DIR}/src/object.cpp)
target_link_libraries(object 
																	build
																	tracking																	
                                 
                                     ${THIRD_PARTY_LIBS})


#--------------------------------------最后生成的库libprocess.a--------------------------------

#利用本工程生成的libfiter.a 、 libsegment.a 以及自己封装的libobject.a 还有第三方库生成的libprocess.a

add_library(process STATIC ${PROJECT_SOURCE_DIR}/src/process.cpp)

target_link_libraries(process 
                                        filter  #   本工程生成的                          		  
                                        segment # 本工程生成的                             
                                        object  #之前封装的,主要要把.h文件添加到本工程
                                        ${THIRD_PARTY_LIBS})# 需要的第三方库

#--------------------------------------生成可执行程序--------------------------------
add_executable(${PROJECT_NAME}_node src/${PROJECT_NAME}_node.cpp src/${PROJECT_NAME}.cpp)
## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}_node			
				 				  ${catkin_LIBRARIES}

                                  process 
                                 #
                                 # filter
                                 # segment
                                  
                                 # object                                
                                                                    
                                  ${THIRD_PARTY_LIBS}                                 
                                )


问题

step 1

	按照上面的CmakeLists.txt 是可以编译过的,这里编译一下。

step 2

	但是因为我想把object部分也封装成库,所以要把下面这部分屏蔽,把生成的库object 都放在目录${PROJECT_SOURCE_DIR}/lib下。
#-----------------------------------调用的库-----------------------------------
#***注意*** 这里的object依赖自己生成的其他静态库:libbuild.a ,libtracking.a,就是这里出现的问题
add_library( object STATIC ${PROJECT_SOURCE_DIR}/src/object.cpp)
target_link_libraries(object 
									build
									tracking
							        ${THIRD_PARTY_LIBS})
							       
**这部分全部屏蔽掉**

step 3

	然后再编译,可以通过。

step 4

	删掉build和devel,不更改CmakeLists.txt ,再次编译,报错 `undefined reference to` 此类问题。

step 5

	然后,去找论坛,发现可能是有些依赖库没有加进来,所以我在最后 可执行程序这里添加了所有的库。
#--------------------------------------生成可执行删掉build和devel,不更改CmakeLists.txt ,再次编译,报错程序--------------------------------
add_executable(${PROJECT_NAME}_node src/${PROJECT_NAME}_node.cpp src/${PROJECT_NAME}.cpp)
 ## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}_node			
				 				  ${catkin_LIBRARIES}

                                  process 
                                 # 下面之前是屏蔽的.....
                                  filter
                                  segment
                                                                    
                                  object                   
                                                                    
                                  ${THIRD_PARTY_LIBS}                                 
                                )
		

step 6

	再次编译,还是出错,检查过链接次序,依赖库等,都没有问题。
	奇怪的是我把step 2部分注释去掉,编译通过,再屏蔽该部分,编译通过,然后删掉build和devel,不更改CmakeLists.txt ,再次编译,报错。
	就是这个问题,虐我千百遍,虐我好几年。

解决办法

库的依赖关系

	这里要特别感谢这篇文章:[“undefined reference to“ 问题汇总及解决方法 ------非常非常好的一篇文章](https://blog.csdn.net/stpeace/article/details/73302833)
	这篇文章说了“undefined reference to“的三个问题:
	1.依赖的库没有 找到/添加,这里就是没有设置存放你自己封装库的位置,或者没有添加依赖,通常要在CmakeLists.txt中添加:	
link_directories(${PROJECT_SOURCE_DIR}/lib  #自己封装的库的位置

               ) 
target_link_libraries(object 
									build
									tracking
							        ${THIRD_PARTY_LIBS})							        
	2.依赖顺序有问题,库的依赖是有次序的,这个次序是从头开始,提纲切领。可以见上面的文章。
	3.定义与实现不一致。这个就需要检测代码。

静态库的理解

	undefined reference to 的几个问题都处理了,但是还是出问题。就去研究静态库,这里参照了多个静态库生成一个静态库。[CMake应用:合并静态库的最佳实践](https://zhuanlan.zhihu.com/p/389448385) 。在这篇文章中发现了静态库其实就是 .o文件的集合,可以用ar -x *.a来查看,但是发现,只是当前cpp文件的,o,依赖的静态库并没有被一并打包到这个库里面。
	一度怀疑上面的问题是以为.o文件没有被生成,就按照合并静态库的做法好一顿捣鼓,最后没啥效果。忽然想到既然.a是有的对应的输出文件.o的,那么就不是因为需要编译生成.o文件,那为什么不屏蔽object是可以的,屏蔽了就不行?另外先放开编译,再屏蔽编译确实能通过?
	为什么?
	1.不屏蔽CmakeLists.txt的object生成过程是可以的,屏蔽了就不行  
	2.先不屏蔽,编译,再屏蔽编译确实能通过
	??????????????????
	把这两个操作的build文件拿出来,去对比了半天也没定位到。

解决

	想一下,库既然都存在,那么素材是都有的。并且先不屏蔽,编译,再屏蔽编译确实能通过,说明是,依赖也是没有问题的。因为CmakeLists.txt 要转成cmake,cmake比较麻烦,所以这个中间过程是不可见的。

想一下自己的架构,包含下面几种库:

	1.本工程生成的库,无嵌套
	2.调用的库,嵌套了其他调用库,2层嵌套
	3.用1 2 以及本地cpp生成的库,3层嵌套
	4.调用3生成的库,生成可执行程序。

库都可以生成

	库生成没有问题,并且编译有通过的情况,那么这个路就是可以走通的。那是不是链接关系的问题呢?并且发现是2这个库在报错误。
	通过对静态库的理解,发现上层的静态库并没有把下层静态库打包到一块,所以在最终的可执行程序,必须要列出所有可以依赖的库。最终:
   add_executable(${PROJECT_NAME}_node src/${PROJECT_NAME}_node.cpp src/${PROJECT_NAME}.cpp)
 ## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}_node			
				 				  ${catkin_LIBRARIES}

                                  process 
                                 # 下面之前是屏蔽的.....
                                  filter
                                  segment
                                  
                                  object
                                  build  #添加了最底层的静态库
                                  tracking #添加了最底层的静态库                          
                                                                    
                                  ${THIRD_PARTY_LIBS}  #添加了需要的第三方库                                 
                                )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值