cmake:解决error LNK2005: void * __cdecl operator new(unsigned __int64) already defined in LIBCMTD.lib

本文详细解析了在使用/MT选项编译MFC项目时遇到的链接错误原因,涉及CRT库与MFC库的new/delete函数冲突。提供三种解决方案:调整链接顺序、使用/FORCE选项及优化CMake脚本。

当以/MT选项编译MFC项目时,会报下面的错误

1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) 已经在 LIBCMTD.lib(new_scalar.obj) 中定义
1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z) 已经在 LIBCMTD.lib(delete_scalar.obj) 中定义
1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned __int64)" (??_U@YAPEAX_K@Z) 已经在 LIBCMTD.lib(new_array.obj) 中定义
1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPEAX@Z) 已经在 LIBCMTD.lib(delete_array.obj) 中定义
1>J:\gfirfid\project.vs\bin\Debug\Ast2600FaceSample.exe : fatal error LNK1169: 找到一个或多个多重定义的符号

关于为什么会报这个错误,还是要看microsoft官方的说明:
A LNK2005 error occurs when the CRT library and MFC libraries are linked in the wrong order in Visual C++

英文一大堆,其实简要说来就是,CRT库和MFC库都定义了new,delete和 DllMain 函数,这些函数要求先链接 MFC 库,然后再链接 CRT 库。
因为连接顺序不正确造成编译错误。

解决办法–修改连接顺序

如果你是手工创建的MSVC工程,解决办法很简单,网上类似的文章很多,方法都一样,就是修改uafxcwd.lib,libmcmtd.lib的连接顺序,确保uafxcwd.lib在libmcmtd.lib前面。
参见:https://www.cnblogs.com/qingtian224/p/5833456.html

解决办法–/FORCE选项

还有个比较懒的办法,就是用在连接命令中加上/FORCE选项,忽略这个错误
在这里插入图片描述

这样以来上面的连接错误就成警告:

1>LINK : warning LNK4075: 忽略“/INCREMENTAL”(由于“/FORCE”规范)
1>nafxcwd.lib(afxmem.obj) : warning LNK4006: "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) 已在 LIBCMTD.lib(new_scalar.obj) 中定义;已忽略第二个定义
1>nafxcwd.lib(afxmem.obj) : warning LNK4006: "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z) 已在 LIBCMTD.lib(delete_scalar.obj) 中定义;已忽略第二个定义
1>nafxcwd.lib(afxmem.obj) : warning LNK4006: "void * __cdecl operator new[](unsigned __int64)" (??_U@YAPEAX_K@Z) 已在 LIBCMTD.lib(new_array.obj) 中定义;已忽略第二个定义
1>nafxcwd.lib(afxmem.obj) : warning LNK4006: "void __cdecl operator delete[](void *)" (??_V@YAXPEAX@Z) 已在 LIBCMTD.lib(delete_array.obj) 中定义;已忽略第二个定义
1>J:\gfirfid\project.vs\bin\Debug\Ast2600FaceSample.exe : warning LNK4088: 因 /FORCE 选项生成了映像;映像可能不能运行

个人认为这个办法是不可取的,属于掩盖问题,掩耳盗铃。

解决办法–cmake脚本

如果你的项目是cmake脚本创建的,手工修改MSVC的工程配置就不可取了。要从修改cmake脚本下手才能根本解决,不留后患。

	# WITH_STATIC_CRT在这里指定是否开启/MT (静态库连接)选项
	# 根据 WITH_STATIC_CRT 决定是否在_target中定义_AFXDLL宏
	# 这里$<...>用到了生CMAKE成器表达式(cmake-generator-expressions),参见CMAKE官方文档
	target_compile_definitions(${_target} PRIVATE $<$<NOT:$<BOOL:${WITH_STATIC_CRT}>>:_AFXDLL> )
	if(WITH_STATIC_CRT)
		# 定义nafxcw 和libcmt的连接顺序,库名根据$<CONFIG:Debug>表达式决定是否有d后缀
		# Debug版本为 nafxcwd,libcmtd,Release版本为nafxcw,libcmt
		target_link_libraries(${_target} nafxcw$<$<CONFIG:Debug>:d> libcmt$<$<CONFIG:Debug>:d>)
	endif()

<think>好的,用户遇到了一个链接错误:entityswitchcard.cpp.obj:-1: error: LNK2001: 无法解析的外部符号 "public: virtual void * __cdecl EntitySwitchCard::qt_metacast(char const *)" (?qt_metacast@EntitySwitchCard@@UEAAPEAXPEBD@Z)。我需要分析这个问题可能的原因和解决方案。 首先,这个错误是典型的Qt元对象系统相关的问题。LNK2001表示链接器找不到某个函数的实现。具体来说,用户代码中声明了qt_metacast但没有实现,或者元对象系统没有正确生成代码。 可能的原因有几个: 1. **Q_OBJECT宏缺失**:如果EntitySwitchCard类继承自QObject,并且使用了信号槽或Qt的属性系统,但没有在类声明中包含Q_OBJECT宏,那么moc(元对象编译器)就不会生成必要的元对象代码,包括qt_metacast函数。这会导致链接错误,因为函数只有声明没有实现。 2. **未重新运行qmake或CMake**:在添加Q_OBJECT宏之后,可能需要重新运行构建系统(qmake或CMake)来触发moc处理修改后的头文件。如果用户没有这样做,moc可能没有生成对应的moc_文件,导致链接错误。 3. **构建缓存未清理**:旧的构建缓存可能残留了之前的编译结果,导致新的moc生成的文件没有被正确包含进来。清理构建目录并重新构建可能会有帮助。 接下来,我需要建议用户逐步检查这些可能性。首先确认类声明中是否有Q_OBJECT宏。如果有,检查是否在修改后重新运行了构建系统,并清理了构建目录。如果用户使用的是CMake,可能需要检查是否包含了对Qt的自动moc处理,例如使用AUTOMOC属性。此外,确保文件路径没有特殊字符或空格,避免构建系统处理出错。 另外,用户可能在头文件中包含了QObject,但没有正确继承,或者没有在类定义中正确使用命名空间,导致moc无法生成代码。需要检查类定义的语法是否正确,比如是否有拼写错误或缺少的冒号继承。 最后,如果以上步骤都正确,可能需要检查项目文件(如.pro或CMakeLists.txt)是否正确包含了所有源文件和头文件,特别是与EntitySwitchCard相关的文件。确保没有遗漏moc生成的文件,或者在构建过程中被忽略。 总结解决方案步骤:检查Q_OBJECT宏,重新运行构建系统,清理项目,确保正确的继承和命名空间,验证项目配置。如果问题仍然存在,需要更详细的项目信息来进一步诊断。</think>--- ### **错误分析:LNK2001(无法解析的外部符号)** 你遇到的 `LNK2001: 无法解析的外部符号 "public: virtual void * __cdecl EntitySwitchCard::qt_metacast(char const *)"` 是典型的 **Qt 元对象系统(Meta-Object System)未正确生成代码**导致的链接错误。以下是具体原因和解决方案: --- ### **1. 核心原因** - **`Q_OBJECT` 宏缺失** 若 `EntitySwitchCard` 类派生自 `QObject` 并使用了信号槽、属性系统或元对象功能,但未在类声明中添加 `Q_OBJECT` 宏,则 `moc`(元对象编译器)不会生成 `qt_metacast`、`qt_metacall` 等虚函数,导致链接失败。 --- ### **2. 分步解决方案** #### **步骤1:检查类声明** 确保 `EntitySwitchCard` 类的头文件(如 `entityswitchcard.h`)中包含 `Q_OBJECT` 宏: ```cpp #include <QObject> class EntitySwitchCard : public QObject { Q_OBJECT // ← 必须添加 public: // ... 其他代码 }; ``` #### **步骤2:重新运行构建系统** - **qmake 项目** 右键项目 → 执行 `qmake` → 清理并重新构建。 - **CMake 项目** 重新配置 CMake(删除 `build` 目录或执行 `CMake: 重新配置项目`)。 #### **步骤3:验证 `moc` 生成文件** 检查构建目录中是否生成了 `moc_entityswitchcard.cpp` 文件(路径示例): ``` build/moc/moc_entityswitchcard.cpp ``` 若该文件缺失,说明 `moc` 未正确处理你的头文件,需检查: - 文件名拼写是否与类名一致(区分大小写)。 - 头文件是否被包含在项目配置中(如 `.pro` 的 `HEADERS` 或 `CMakeLists.txt` 的源文件列表)。 #### **步骤4:清理构建缓存** - 删除整个 `build` 目录。 - 在 Qt Creator 中:`构建 → 清理所有项目`。 - 重新生成项目。 --- ### **3. 其他可能原因** #### **头文件未正确继承 QObject** 确保类继承自 `QObject`(或 `QObject` 的子类,如 `QWidget`),且使用 `public` 继承: ```cpp class EntitySwitchCard : public QObject { // 正确 Q_OBJECT // ... }; ``` #### **命名空间干扰** 若类定义在命名空间内,需确保 `Q_OBJECT` 宏位于命名空间内部: ```cpp namespace MyNamespace { class EntitySwitchCard : public QObject { Q_OBJECT // ← 必须在命名空间内部 public: // ... }; } ``` #### **CMake 项目未启用 AUTOMOC** 在 `CMakeLists.txt` 中确保启用自动 MOC 处理: ```cmake set(CMAKE_AUTOMOC ON) # 启用自动 MOC add_executable(YourProject entityswitchcard.h # 头文件必须明确列出 entityswitchcard.cpp ) ``` --- ### **4. 验证修复结果** 1. 确保 `moc_entityswitchcard.cpp` 文件已生成。 2. 检查该文件是否包含 `qt_metacast` 函数的实现。 3. 重新编译项目,观察是否仍报 `LNK2001` 错误。 --- ### **5. 补充说明** - **信号槽或属性未正确使用** 如果类中声明了信号槽或 `Q_PROPERTY`,但未提供实现,也可能引发类似错误。确保所有信号槽均有逻辑(即使为空)。 - **多级继承问题** 若 `EntitySwitchCard` 通过多重继承引入 `QObject`,需将 `QObject` 放在继承链的首位: ```cpp class EntitySwitchCard : public QObject, public OtherClass { ... }; ``` --- 通过以上步骤,可解决因元对象系统未生成代码导致的链接错误。若问题仍未解决,请提供 `EntitySwitchCard` 类的完整头文件及项目构建配置(`.pro` 或 `CMakeLists.txt`),以便进一步分析。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值