VC中LINK 2001 和 LINK 2009 的错误的解决方法

 更新时间:2020年10月5日 17:30  点击:2276

最近将两个开源C++项目编译成windows版本的时候遇到很多问题,关键是两个项目经过同事的修改之后,一个项目引用了另一个项目,两个项目的头文件中都有一些跨平台的关于数据类型,以及一些通用函数的定义,所以导致有冲突,编译的时候总是报错,报的最多的是“无法解析的外部符号”,经过近3天的折腾总算都通过了,这里是一些总结。

首先,关于VC中的lib,与linux下的静态库是不同的,在VC中编译动态库的时候会生成一个lib和一个对应的dll,使用者在使用的时候需要包含头文件以及连接到该lib,在发布最终程序的时候则需要将对应的dll拷贝到发布目录。当然也可以使用LoadLibrary的方式在程序中动态加载dll而不需要使用这个动态库生成的lib了。

如果是静态库,编译之后只会生成一个lib文件,该lib文件非常大,可能有几十M的大小,(而编译动态库的时候生成的lib可能只有几十KB或者几百KB)在使用这个静态库的lib的时候,也需要指定头文件,与对应的lib库文件,编译成功之后就可以直接运行,不需要拷贝额外的文件了。

另外如果A是静态库,B是静态库,并且B使用了A的接口,这个时候在编译B的时候只需要指定A的头文件就可以了,不需要指定A的库文件。如果有一个项目C编译成可执行文件,C使用了B中的接口,这个时候在编译C的时候,需要同时指定B的头文件(如果该头文件中又引用了A的头文件那可能也要同时指定A的头文件),与B的lib库文件,以及A的lib库文件。 也就是说编译C的时候要指定之前所有依赖的lib文件。

在windows中编译动态库的时候,如果动态库中的函数需要给别人使用,那么这些函数或者类则需要被导出,具体如下,假设库的头文件为A.h:

#  if defined LIB_A  //这个宏为这个A特有的宏
  #    define DLLEXP __declspec(dllexport)
  #  else
  #    define DLLEXP __declspec(dllimport)
  #  endif
  
  class DLLEXP ExportClass{
  //......
  };

如果在项目B中使用A库,那么项目B在引用A.h的时候,由于项目B没有定义LIB_A这个宏,所以实际上使用的是#define DLLEXP __declspec(dllimport)这个定义,也就是说在B项目中,这个ExportClass类的声明变成导入了,表示该类是从外部库导入的类。 而在项目A中由于定义了LIB_A这个项目特有的宏,所以使用的是#define DLLEXP __declspec(dllexport)这个定义,说明需要编译成导出给别人用的类。

如果是C语言的库给C++使用或者C++的库封装给C使用则除了要添加__declspec(dllexport)导出声明之外,还需要添加 external "C" 的声明,该声明主要告诉编译器,编译的时候生成的函数的符号表按照C的规则来生成。 因为C编译器与C++编译器生成符号表的时候规则是不一样的。

那么编译的时候报告LINK错误,无法解析的外部符号,一般是下面几种原因造成的:

1. 最常见的情况是要么没有指定引用库的路径,或者没有指定所以依赖的库文件名字。
2. 如果正确指定了lib库路径,以及lib库名,那检查一下该lib中是否有该符号的实现,也就是说头文件中声明了该符号,但是该库文件中却没有具体的实现。
3. 如果库文件中确实实现了符号的定义,那么检查一下lib库的版本是否与正确(32位或者64位)。还有如果报告的是某一个函数无法解析,则要对比一下该函数在库中的实现与在头文件中的声明是否一致(特别是函数的参数个数与参数类型是否完全一致)。
4. 有一种情况就是在编译lib的时候,该lib是动态库,但是没有添加导出声明,导致该库中的函数并不对外导出(静态库不需要导出声明,加了反而会有问题),那么使用者在链接的时候也会报无法解析的符号。
5. 还有一种非常隐蔽的情况,这也是我遇到的情况,在项目A中将一些基本的数据类型做了typedef,例如类似下面的定义:

typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;

然后A项目的导出函数 FUNC(uint8_t); 使用了该uint8_t,但是在B项目中对上述的 uint8_t 又做了另外一套定义 (如果A和B是两个开源项目则很有可能出现这种冲突),如下:

typedef unsigned __int8 uint8_t;

那么在B中使用A的时候,使用的uint8_t是B的定义,实际上函数的声明变成了 FUNC(unsigned __int8) 但是在A的lib库文件的实现里面使用的是FUNC(unsigned char)也就是说该函数FUNC的声明与定义并不匹配,那么当然也会报告找不到符号了,这种情况一般是在两个开源项目混合使用的时候就会出现冲突。

6. 编译静态库的时候,如果静态库B引用了静态库A中的内容,此时在B的项目里面都不需要指定A的库路径,只需要指定A的相关头文件,就可以编译通过,如果里面有什么问题,那么会在最终使用B的项目的时候,链接的时候报出来。例如C项目使用了B,那么在编译C的时候需要同时添加A和B两个库,如果之前B使用A的过程中有问题的话,那么在编译C的时候就会报告LINK错误,而不是在编译B的时候报告(除非是语法错误)。

7. 如果项目C使用了B库与A库,但是B与A是有依赖关系的,那么在C的工程设置中,也要指定B和A的先后关系,否则也可能会报错。

8. 如果在连接项目的时候报告下面的错误:

无法找到外部符号 _CrtDbgReportW 或者是
error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0” (有可能是值"0"不匹配"2")

这种错误一般是在Release版本的项目中使用了Debug的库,但是有时候明明看到我们编译的库都是Release版本的,使用那个库的时候却还是报告这个问题,这个现象可能是,编译那个库的时候,虽然选择的是Release方式编译,但是在项目的宏定义中却定义了_DEBUG宏,导致该还是会被认为是Debug的版本。

VC中常见LINK错误及解决方案

. Windows子系统设置错误, 提示:
libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Windows项目要使用Windows子系统, 而不是Console, 可以这样设置:

[Project] --> [Settings] --> 选择"Link"属性页,
在Project Options中将/subsystem:console改成/subsystem:windows

2. Console子系统设置错误, 提示:
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16

控制台项目要使用Console子系统, 而不是Windows, 设置:

[Project] --> [Settings] --> 选择"Link"属性页,
在Project Options中将/subsystem:windows改成/subsystem:console

3. 程序入口设置错误, 提示:
msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16

通常, MFC项目的程序入口函数是WinMain, 如果编译项目的Unicode版本, 程序入口必须改为wWinMainCRTStartup, 所以需要重新设置程序入口:

[Project] --> [Settings] --> 选择"Link"属性页,
在Category中选择Output,
再在Entry-point symbol中填入wWinMainCRTStartup, 即可

4. 线程运行时库设置错误, 提示:
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex

这是因为MFC要使用多线程时库, 需要更改设置:

[Project] --> [Settings] --> 选择"C/C++"属性页,
在Category中选择Code Generation,
再在Use run-time library中选择Debug Multithreaded或者multithreaded
咸鱼游侠(75374355) 12:11:11

其中,
Single-Threaded 单线程静态链接库(release版本)
Multithreaded 多线程静态链接库(release版本)
multithreaded DLL 多线程动态链接库(release版本)
Debug Single-Threaded 单线程静态链接库(debug版本)
Debug Multithreaded 多线程静态链接库(debug版本)
Debug Multithreaded DLL 多线程动态链接库(debug版本)

单线程: 不需要多线程调用时, 多用在DOS环境下
多线程: 可以并发运行
静态库: 直接将库与程序Link, 可以脱离MFC库运行
动态库: 需要相应的DLL动态库, 程序才能运行
release版本: 正式发布时使用
debug版本: 调试阶段使用

初学者在学习VC++的过程中,遇到的LNK2001错误的错误消息主要为:

  unresolved external symbol “symbol”(不确定的外部“符号”)。

  如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。

  以下是可能产生LNK2001错误的原因:

  一.由于编码错误导致的LNK2001

  1.不相匹配的程序代码或模块定义(.DEF)文件能导致LNK2001。例如, 如果在C++源文件内声明了一变量“var1”,却试图在另一文件内以变量“VAR1”访问该变量,将发生该错误。

  2.如果使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将导致LNK2001错误。

  3.调用函数时如果所用的参数类型同函数声明时的类型不符将会产生LNK2001。

  4.试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001。

  5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。静态函数和静态变量具有相同的使用范围限制。当试图从文件外部访问任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001。

  函数内声明的变量(局部变量) 只能在该函数的范围内使用。

C++ 的全局常量只有静态连接性能。这不同于C,如果试图在C++的多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是需要时在头文件中加入该常量的初始化代码,并在.CPP文件中包含该头文件;另一种方法是使用时给该变量赋以常数。

  二.由于编译和链接的设置而造成的LNK2001

  1.如果编译时使用的是/NOD(/NODEFAULTLIB)选项,程序所需要的运行库和MFC库在连接时由编译器写入目标文件模块, 但除非在文件中明确包含这些库名,否则这些库不会被链接进工程文件。在这种情况下使用/NOD将导致错误LNK2001。

  2.如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将得到“unresolved external on _WinMain@16”的LNK2001错误信息。

  3.使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对“func”的引用,在目标文件里即对“__imp__func” 的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行连接,将在__imp__func上发生LNK2001;如果不使用/MD选项编
  译,在使用MSVCxx.LIB连接时也会发生LNK2001。

  4.使用/ML选项编译时,如用LIBCMT.LIB链接会在_errno上发生LNK2001。

  5.当编译调试版的应用程序时,如果采用发行版模态库进行连接也会产生LNK2001;同样,使用调试版模态库连接发行版应用程序时也会产生相同的问题。

  6.不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。

  编程时打开了函数内联(/Ob1或/Ob2),但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字),这时将得到该错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志内联函数。

  8.不正确的/SUBSYSTEM或/ENTRY设置也能导致LNK2001

到此这篇关于VC中LINK 2001 和 LINK 2009 的错误的解决方法的文章就介绍到这了,更多相关VC中常见LINK错误及解决方案内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?

    这篇文章主要介绍了C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?,这也小编做.NET项目时经常思考和让人混乱的一个问题,这篇文章写的挺好,一下清晰了许多,需要的朋友可以参考下...2020-06-25
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16
  • SpringMvc自动装箱及GET请求参数原理解析

    这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • SpringMvc获取请求头请求体消息过程解析

    这篇文章主要介绍了SpringMvc获取请求头请求体消息过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-17
  • Springmvc ResponseBody响应json数据实现过程

    这篇文章主要介绍了Springmvc ResponseBody响应json数据实现过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-10-26
  • vc提示unexpected end of file found的原因分析

    这篇文章主要介绍了vc提示unexpected end of file found的原因分析,给出了几点常见错误原因的分析,需要的朋友可以参考下...2020-04-25
  • 基于C#后台调用跨域MVC服务及带Cookie验证的实现

    本篇文章介绍了,基于C#后台调用跨域MVC服务及带Cookie验证的实现。需要的朋友参考下...2020-06-25
  • 理解javascript中的MVC模式

    这篇文章主要为大家介绍了javascript中的MVC模式,MVC是一种软件架构模式,一般把软件模式分为三部分,本文就针对MVC模式的三部分进行讲解,感兴趣的小伙伴们可以参考一下...2016-02-01
  • Spring MVC 处理一个请求的流程

    Spring MVC是Spring系列框架中使用频率最高的部分。不管是Spring Boot还是传统的Spring项目,只要是Web项目都会使用到Spring MVC部分。因此程序员一定要熟练掌握MVC部分。本篇博客简要分析Spring MVC处理一个请求的流程。...2021-02-06
  • 仅30行代码实现Javascript中的MVC

    这篇文章主要介绍了仅30行代码实现Javascript中的MVC的方法,MVC的基础是观察者模式,这是实现model和view同步的关键,想要深入了解的朋友可以参考本文...2016-02-18
  • 使用jQuery.form.js/springmvc框架实现文件上传功能

    这篇文章主要介绍了使用jQuery.form.jsspringmvc框架实现文件上传功能,非常具有参考借鉴价值,感兴趣的朋友一起学习吧...2016-05-14
  • SpringMVC和rabbitmq集成的使用案例

    这篇文章主要介绍了SpringMVC和rabbitmq集成的使用案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-20
  • 详解CocosCreator MVC架构

    这篇文章主要介绍了CocosCreator MVC架构,同学们在制作游戏过程中,尽量使用一些架构,会避免很多问题...2021-04-16
  • 华为将携HiLink智能家居生态成果重磅亮相2017AWE

    3月9日-11日,以“智慧生活尽在AWE”为主题的2017年中国家电及消费电子博览会(AWE)将在上海新国际博览中心(SNIEC) 举行。届时,华为将携HiLink智能家居生态成果亮相。华为消费者业务首席战略官邵洋还将在AWE开幕式上发表主题演讲,并与方太集团、海尔集团、京东集团、博西家电四家企业的相关负责人共同出席“中国家电发展高峰论坛”,就如何打造“智慧生活”以及“人工智能在智能家居中的应用”进行探讨交流。...2017-07-06
  • AngularJS教程之MVC体系结构详解

    本文主要讲解AngularJS MVC体系结构,这里提供详细的教程供大家学习参考,有需要的小伙伴可以参考下...2016-08-24
  • web面试MVC与MVVM区别及Vue为什么不完全遵守MVVM解答

    这篇文章主要介绍了web面试中常问问题,MVC与MVVM区别以及Vue为什么不完全遵守MVVM的难点解答,有需要的朋友可以借鉴参考下,希望能够有所帮助...2021-09-24
  • ASP.NET MVC API 接口验证的示例代码

    本篇文章主要介绍了ASP.NET MVC API 接口验证的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
  • SpringMVC中的handlerMappings对象用法

    这篇文章主要介绍了SpringMVC中的handlerMappings对象用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-26
  • ASP.NET Core MVC如何实现运行时动态定义Controller类型

    这篇文章主要介绍了ASP.NET Core MVC如何实现运行时动态定义Controller类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22