【cmake实战十二:cmake问题集锦】LNK1104: 无法打开文件“xxxxxxxxx.lib”
- 一、问题1:==编译时报错==,LNK1104: 无法打开文件“xxxxxxxxx.lib”
- 1、问题分析
- 2、解决方案
- 2.1、方案一:link_directories
- 2.2、方案二:target_link_libraries
- 3、link_directories和target_link_libraries的区别
- 4、其他方案
- 二、问题2:关于 include_directories
- 1、情况描述
- 2、问题:porjectB引用的porjectC的头文件都是红色
- 3、问题解决
- 4、总结
- 三、问题3:==cmake时报错==,get_target_property() called with non-existent target
- 1、描述
- 2、问题描述==cmake时报错==:get_target_property() called with non-existent target “xxxx”.
- 3、问题原因
- 4、解决方案
- 四、问题4:==编译和安装时报错==setlocal
- 1、原因1:对生成目录没有写入权限
- 2、原因2:对生成的进程程序没有权限
- 3、原因3:要install的文件不存在、or路径不正确
- 4、原因4:要install文件被其他进程占用。
- 5、总结:setlocal解决方案汇总如下:
- 五、问题5:==编译时报错==无法解析的外部符号
- 1、情况描述
- 2、问题:无法解析的外部符号struck google:protobuf:
- 3、原因分析
- 4、解决方案
- 后记:
一、问题1:编译时报错,LNK1104: 无法打开文件“xxxxxxxxx.lib”
- 本周五新写了一个网络客户端的项目(cmake),编译时报错如下
LNK1104: 无法打开文件“libboost_data_time-vc141-mt-gd-x64-1_73.lib”
1、问题分析
由于公司产品框架依赖较多,应该是我引用的某个项目用到了boost库,编译链接时找不到对应的lib,所以报错“LNK1104: 无法打开文件“libboost_data_time-vc141-mt-gd-x64-1_73.lib”
2、解决方案
公司项目是不可以放出来的,用我自己之前写的一个小demo,具体说明下如何解决。
2.1、方案一:link_directories
- 把boost库的lib路径,链接到当前项目。(也就是把上面报错的“xxxxxxxxx.lib”路径,链接到当前项目路径。
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)PROJECT(NEWHELLO)# link directories
link_directories("${BOOST_LIBRARY_PATH}") #BOOST_LIBRARY_PATH代表你设置的boost库lib的路径,否则会报错找不到lib# 将指定目录添加到编译器的头文件搜索路径之下
include_directories("${BOOST_INCLUDE_PATH}") #${BOOST_INCLUDE_PATH}代表要用到的boost库头文件的路径ADD_EXECUTABLE(hello main.cpp)
2.2、方案二:target_link_libraries
- 链接报错的“xxxxxxxxx.lib”库
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)PROJECT(NEWHELLO)include_directories("${BOOST_INCLUDE_PATH}")ADD_EXECUTABLE(hello main.cpp)# link librarytarget_link_libraries(hello "${BOOST_LIBRARY_PATH}/xxxxxxxxx.lib")
3、link_directories和target_link_libraries的区别
- link_directories:应该放到生成二进制文件前。
放到ADD_EXECUTABLE前,本代码生成的是可执行进程。
- target_link_libraries:因为要放到生成二进制文件后。
放到ADD_EXECUTABLE后,如果是动态库类似
4、其他方案
- 因为我们项目使用的CMakeLists.txt管理项目的,所以我这里讲解的是cmake的方式,当然link_directories和target_link_libraries也都可以在visual studio中配置,我就不在这里讲解了,大家可以自行查找下在visual studio中配置对应的解决方案。
二、问题2:关于 include_directories
在写代码的过程种,还遇到了一个和include_directories相关的问题。
1、情况描述
- 我写的是项目A,porjectA
- 项目A用到了项目B,projectB
- 而项目B又用到了项目C,projectC
2、问题:porjectB引用的porjectC的头文件都是红色
- 从porjectA进入porjectB时,发现porjectB引用的porjectC的头文件都是红色的,也就是说,porjectB没有把porjectC头文件包进来。
- 我们查看项目B的CMakeLists.txt,发现porjectB已经把porjectC的头文件包进来了,porjectB使用了include_directories(“${projectC_INCLUDE_PATH}”)
3、问题解决
- porjectA的CMakeLists.txt中也使用include_directories(“${projectC_INCLUDE_PATH}”),然后就好了。
4、总结
- 在《1、情况描述》中说的这样的情况下,porjectA的CMakeLists.txt,需要包括porjectB的CMakeLists.txt中的include_directories。
- 这样是否合理呢?个人认为不太合理,但是目前验证的就是这样一个情况,后续有新的理解,再更新
三、问题3:cmake时报错,get_target_property() called with non-existent target
1、描述
- 我写的是项目A,porjectA
- 项目A用到了项目B,projectB
2、问题描述cmake时报错:get_target_property() called with non-existent target “xxxx”.
get_target_property() called with non-existent target “xxxx”.Call Stack (most recent call first):
xxxx代表我们生成的某个项目,比如本项目projectB
3、问题原因
- 在添加porjectA、projectB的CMakeLists.txt中,我们书写如下
add_subdirectory(projectB)
add_subdirectory(porjectA)
4、解决方案
因为porjectA依赖了projectB,所以应该先生成projectB
add_subdirectory(porjectA)
add_subdirectory(projectB)
四、问题4:编译和安装时报错setlocal
setLocal问题大致可以分为两类,一是没有权限,二是文件不存在。细分有以下四种情况。(具体原因可以从输出那查看)
1、原因1:对生成目录没有写入权限
- 解决方案:给visual studio赋给写入目录的权限,比如项目建立在了c盘,就需要使用管理员启动visual studio
2、原因2:对生成的进程程序没有权限
- 比如,我们要生成的进程A正在运行(或者被其他进程占用),这时我们是没有权限操作的,
- 解决方案:把正在运行的程序A关闭。(也就是我们要生成的进程A)
3、原因3:要install的文件不存在、or路径不正确
- 解决方案:把要install的文件放到我们CMakeLists.txt中写的路径下。
4、原因4:要install文件被其他进程占用。
我们知道同一个进程共享文件io和权限,但是不同进程就不行了。
- 解决方案1:把占用安装文件的进程关闭
- 解决方案2:重启电脑
5、总结:setlocal解决方案汇总如下:
- 重启电脑(or关闭相关进程)
- 检查install的文件是否存在
- 检查install的路径是否错误
五、问题5:编译时报错无法解析的外部符号
- 一般来说,这种的问题是由于没有链接的问题,或者链接的库找不到。但是此处并非是这样的。
1、情况描述
- 我写的是项目A,porjectA
- 项目A用到了项目B,projectB,(projectB中定义了很多导出的PB结构)
其中projectB的代码中如下
// projectB 代码
# ifdef PB_DLL_FLAG
# define API __declspec(dllexport)
# else
# define API __declspec(dllimport)
# endif
其中projectB的CMakeLists.txt中如下
# projectB CMakeLists.txt
add_definitions(-DPB_DLL_FLAG )
其中projectA的CMakeLists.txt中如下
# projectA CMakeLists.txt
add_definitions(-DPB_DLL_FLAG )
2、问题:无法解析的外部符号struck google:protobuf:
编译是报错“无法解析的外部符号struck google:protobuf::EmptyDefaultTypeIernal google:protobuf::Empty_default_instance”
3、原因分析
- projectB的CMakeLists.txt中,添加add_definitions(-DPB_DLL_FLAG ),这样在编译时,代码中就可以使用PB_DLL_FLAG 了
- 而根据代码中的逻辑,如果定义了PB_DLL_FLAG ,API 就是导出的接口__declspec(dllexport)
// projectB 代码
# ifdef PB_DLL_FLAG
# define API __declspec(dllexport)
# else
# define API __declspec(dllimport)
# endif
- 而我们在projectA的CMakeLists.txt中如下,就也把API也当作导出了,
# projectA CMakeLists.txt
add_definitions(-DPB_DLL_FLAG )
- 其实我前面也说了,其实我的projectA是要使用projectB导出的PB类型,这就出问题了。所以projectA不应该定义add_definitions(-DPB_DLL_FLAG ),这样API 就是导入了,也就是__declspec(dllimport)
4、解决方案
把而我们在projectA的CMakeLists.txt中的“add_definitions(-DPB_DLL_FLAG )”删除,这样就是导入了。
后记:
前面讲解过__declspec(dllexport)、__declspec(dllimport)、add_definitions,但是并没有综合的使用过,且对__declspec(dllexport)、__declspec(dllimport)理解的都不深入,所以才会犯这样的错误。所以后面还会找一篇文章,深入细致的讲解下操作系统的dllexport、dllimport。