【cmake实战十二:cmake问题集锦】LNK1104: 无法打开文件“xxxxxxxxx.lib”

一、问题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 library

target_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。

猜你喜欢

转载自blog.csdn.net/junxuezheng/article/details/129780080