IDE /skipping incompatible xxx_d.dll when searching for -lxxx_d

文章目录

  • 概述
  • 场景复现
  • 用以测试的代码
  • 编译器位数不匹配导致?
  • 保持编译器类型一致
  • 再验证编译器位数的影响
  • MingW下调用OS的库咋不告警?
    • 以mingW下使用winSocket为例
    • MingW下网络编程的头文件分析
    • 该环境下链接的ws2_32库文件在哪里?
    • mingW为啥可以兼容window下的动态库

概述

该部分内容,是从《IDE/在Qt Creator (pro文件) 下DLL动态库的部署和加载问题分析》中独立出来的。
如下是首次遇到该问题时的记录,大约是5年前了。现在只能看出,当时调用DLL调用者程序使用的是 mingW 编译器,至于是引用的哪个动态库,以及这个动态库是使用MSVC还是使用MingW 编译的,都已无从知晓。
E:/Qt/Qt5.12.9/Tools/mingw730_64/bin/…/lib/gcc/x86_64-w64-mingw32/7.3.0/…/…/…/…/x86_64-w64-mingw32/bin/ld.exe: skipping incompatible D:\MMM\bin/xxx_d.dll when searching for -lxxx_d
当时只简单记录了猜测:如上问题是发生在从32位切换到64位程序时,因此可能是动态库位数不一致导致的。
后来在编写《Qt Quick /将C/C++中的枚举定义导出到Qml中》的 Demo 时,我又遇到了类似错误,因此来整理了此篇文章。

场景复现

编写《Qt Quick /将C/C++中的枚举定义导出到Qml中》的 Demo 时, 我先构建了名为DLL_Of_C 的动态库工程,然后使用之前的某个名为QmlA的项目部署和调用它。
我在起初犯了两个乌龙错误,
1、没有注意到 DLL_Of_C项目, 是默认x86平台而不是x64平台。
2、这个以前的项目 QmlA 实际上是使用的 Qt Creator + Qt_5_12_8_MinGW_64_bit 集成开发环境,我却误以为它是使用的 Qt Creator + MSVC 141集成开发环境。
当时在QmlA项目中pro工程文件中的相关配置如下。这个配置并无任何问题。

# 设置文件生成路径 /该路径包含其依赖的dll文件
DESTDIR = ../bin
# 设置依赖的动态链接库 
LIBS += -L../bin -lDLL_Of_C

在上述境况下,编译报错,
在这里插入图片描述
: -1: error: skipping incompatible …\bin/DLL_Of_C.dll when searching for -lDLL_Of_C

最开始我走的是老路,怀疑是不是路径写法啥的不对啊?哈哈,于是从翻出了概述中的那段草稿。原来一毛一样的错误提示,早些年就遇到过,还做了记录,只是没有验证。要注意,incompatible 并不是找不到,而是找到了但不匹配!
incompatible
adj. 不相容的,不能共存的;不能和谐相处的,合不来的;不兼容的,互斥的 n. 互不相容的人或事物
从 “不兼容的” 这个方向上继续分析,终于又发现了第二个乌龙错误:DLL是使用MSCV编译的,而QmlA项目实际上使用了MingW工具集,不是MSVC。

用以测试的代码

近来不忙,于是编写了单独的测试代码来验证和解决此问题。

动态库,
使用 VS2017 - VC++ - Windows 桌面 - 动态库链接(DLL),新建名为 DllByMsvc 项目。配置不使用预编译头,不关注dllmian实现。配置项目属性 - 常规 - 输出目录为 …/bin/ ;配置项目属性 - C/C++ - 预处理器 - 预处理器定义,增加 COMM_LIBRARY 宏定义;视测试需要选择平台为 x64 或 x86。

//dll_c_if.h
//#pragma once //确保头文件只被编译一次,防止重复包含 /仅VS适用
#ifndef DLL_C_IF_H_
#define DLL_C_IF_H_

#include <string>

#ifdef COMM_LIBRARY
#ifdef _WIN32 
#define COMM_API_EXPORT /*extern "C"*/ __declspec(dllexport) 
#else
#define COMM_API_EXPORT __attribute__((visibility("default")))
#endif
#else
#ifdef _WIN32
#define COMM_API_EXPORT /*extern "C"*/ __declspec(dllimport)
#else
#define COMM_API_EXPORT __attribute__((visibility("hidden")))
#endif
#endif

//接口中使用了非C的std::string //若强行声明 extern "C" 会有编译告警
//#ifdef __cplusplus
//extern "C" {
//#endif

    enum EnumRegID {
        ID_E_REG_M = 10,
        ID_E_REG_N,
        ID_E_REG_P
    };

    //dll导出的接口
    COMM_API_EXPORT std::string RegTable_Name(EnumRegID u16RegID);

//#ifdef __cplusplus
//}
//#endif

#endif // DLL_C_IF_H_
//dll_c_if.cpp
#include "dll_c_if.h"

//函数接口实现
std::string RegTable_Name(EnumRegID u16RegID)
{
    return "river.qu@" + std::to_string(u16RegID);
}

可执行程序,
在 Qt Creator 新建 Qt 控制台应用程序, 项目名 UseDllInQt。视测试需求配置为mingW64或msvc64编译套件。

//pro文件节选
HEADERS += \
    dll_c_if.h

# 设置文件生成路径 /该路径包含其依赖的dll文件
DESTDIR = ../bin

# 设置依赖的动态链接库
LIBS += -L../bin -lDllByMsvc
//mian.cpp
#include <QCoreApplication>
#include <QDebug>
#include "dll_c_if.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug()<< QString::fromLocal8Bit(RegTable_Name(ID_E_REG_N).c_str());

    return a.exec();
}

相关目录配置如下,根目录 E:\DLLTest,其下设子目录:
bin目录;库项目 DllByMsvc;Qt 控制台应用程序项目目录 UseDllInQt;两个工程的输出目录都配置指向 bin 目录。

编译器位数不匹配导致?

按照场景复现中提到的那样,假设此时我还没有意识到所有的错误。首先我将 DllByMsvc 项目配置为 x86平台进行编译生成。项目 UseDllIQt 使用 mingW64套件,执行编译。
在这里插入图片描述
假设我现在意识到了生产DLL的编译器和调用DLL的编译器,其位数是不一样的,并怀疑它。于是乎,我修改 DllByMsvc 工程的目标平台为 x64 并重新生成,再重新编译使用它的 UseDllIQt 项目。
在这里插入图片描述
依然存在编译警告,但此处不再提示 incompatible 那样的内容。

仅针对我遇到的上述问题,测试分析至此,可以断定:
编译错误 “跳过 incompatible 不兼容的动态库”,其主要原因在于 Dll实现者 与DLL使用者,在编译器平台位数上的不一致。但同时,即使位数是一致的,若编译器类型不一致,也有有编译错误,而且是更加隐晦的提示。

写在前面,
解决标题中问题的最终方案是:使得 <DLL实现项目> 与 <DLL使用项目>,其编译器平台位数和编译器类型保持一致。 下文是得出此结论的过程。

保持编译器类型一致

如下,在 UseDllInQt 项目 - Buid & Run 下双击 MSVC2015_64,即可切换到对应的Kits上,(我这里没有安装Qt的MSVC2017库)
在这里插入图片描述
使用 VS2017平台x64重新编译生成 DllByMsvc 项目,在 UseDllInQt 项目(已选用MSVC编译器)中部署调用,使用前文配置的 LIBS,编译情况如下,
: -1: error: LNK1146: 没有用选项“/LIBPATH:”指定的参数
这又是闹哪门子,
经过排查发现,实际的pro文件中,我画蛇添足,将 LIBS += -L…/bin -lDllByMsvc 错误的写成了 LIBS += -L …/bin -lDllByMsvc,问题在于-L 和 …/bin 路径之间是不可以有空格。从这里我们也可基本猜测,LIBS使用 -L参数,与直接使用LIBPATH编写配置,其效果应是一致的。修改后,再次重新编译,没有告警。

附加的对LIBS配置插入几句,
DllByMsvc 项目设置输出目录后,不仅会将 DLL_Of_C.dll 文件生成在该目录下,DllByMsvc.lib、DllByMsvc.ilk、DllByMsvc.exp 等编译结果都生成在了该目录下。其中在编译阶段,起到作用的是 DllByMsvc.lib 而不是 DllByMsvcdll 文件。
也即在在msvc编译器下, pro工程文件中配置的 LIBS,其作用是告诉链接器在指定的库文件路径中查找所需的库文件。
相关更细致的讲解,可参考 《IDE/在Qt Creator (pro文件) 下DLL动态库的部署和加载问题分析》中的章节。

至此,我们已经明晰并解决了 skipping incompatible xxx_d.dll when searching for -lxxx_d 问题。

再验证编译器位数的影响

在上一节的测试基础(UseDllInQt 项目使用Qt Creator + MSVC 64 编译器)上,将DLL工程修改回使用x86平台,重新编译生成DLL实现项目和DLL使用项目,异常如下,
在这里插入图片描述
DLL_Of_C.lib(DLL_Of_C.dll): -1: error: LNK1112: 模块计算机类型“X86”与目标计算机类型“x64冲突

要注意的是,不同于本文一开始的原始场景,此时 DLL实现项目和DLL使用项目编译器类型是一样的,仅仅是编译器的平台位数不一致。此时的编译报错,也与原始场景中完全不一致。
因此,导致 “skipping incompatible xxx_d.dll when searching for -lxxx_d” 编译的原因,应该描述为:它是 DLL实现项目和DLL使用项目编译器类型及编译器平台位数都不一致的综合结果。
在我的草稿中,还记录着一些内容,说是有网友在Linux上的一些实践,只是编译器类型不一致的情况下就会出现 skipping incompatible 类似的编译错误,我这里没有实际验证过,仅备案。

MingW下调用OS的库咋不告警?

我比较清晰的记着,几年前我是在 Qt Creator + MingW 集成开发环境下实践过Windows网络编程的,只需要在 pro 中包含 ws2_32 库即可,也使用过 user32 等系统库。当时还留下过疑问:
为啥Windows OS的库能在MingW下调用,而没有本文中描述的那些问题。我自己在MSCV下编写的库,事事就这么多?

以mingW下使用winSocket为例

如下,新建名为 WinProgramInMingW 的工程,使用 Qt_5_12_8_MinGW_64_bit 开发套件。示例将试图在该项目下使用 Windows 网络编程类和接口。为了更好的说明,先故意制造个错误,
在这里插入图片描述
很容易知道,这是因为没有在 pro 下配置包含WSADATA实现的库。可修改pro文件,

# 设置依赖的动态链接库
LIBS += -L../bin    \   #自定义库目录
        #-lDllByMsvc \  #MSVC编译的自定库文件
        -lws2_32        #OS库文件

如上,引用 ws2_32 库后,将编译正常,不会出现 skipping incompatible 等问题。以前不知道原因,总觉很奇怪。接下来,我们将从<windows.h>头文件和该项目的Makefile文件下手,来分析为啥不告警。

MingW下网络编程的头文件分析

先看看MingW环境下的 windows.h 头文件
在main.cpp下的头文件包含行上执行跳转,可以发现该 windows.h 文件位于 D:\Qt\Qt5.12.8\Tools\mingw730_64\x86_64-w64-mingw32\include 目录下,并不是系统目录下的,也不是VS安装目录下的。打开一些包含网络编程的VS下的项目,查看同名文件,会发现他们位于,C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um、C:\Program Files (x86)\Windows Kits\8.1\Include\um 等Windows SDK的安装目录。Windows SDK 可以随VS安装,也可以独立安装,要详细了解它们,可以参考 《IDE/记录VS2015&WinSDK安装过程中增删的系统组件和环境变量》、《IDE/Windows SDK /Windows CDB调试器安装和使用总结》等文章。姑且先分析到这。

我们在 WSADATA 这个结构类型上跳转,发现其位于,
D:\Qt\Qt5.12.8\Tools\mingw730_64\x86_64-w64-mingw32\include\psdk_inc 的 _wsadata.h 头文件中。而我们在Windows编程中常用的 winsock.h 、 winsock2.h 位于 D:\Qt\Qt5.12.8\Tools\mingw730_64\x86_64-w64-mingw32\include 目录下。也就是说,MingW为了提供Windows网络编程能力,它自己定义了全部相关头文件,这样说可能有点欠妥,请继续往后看。

基于上述头文件的分析,我想说,难不成MingW自己也实现了Windows的套接字编程?

该环境下链接的ws2_32库文件在哪里?

我想知道该环境下链接的ws2_32库文件是系统的还是MingW自己的? 打开该项目下的 Makefile.Debug 文件,查找 ws2_32 文件,只有一行,
LIBS = -L…\bin -lws2_32 D:\Qt\Qt5.12.8\5.12.8\mingw73_64\lib\libQt5Cored.a
由于不是全路径,这并不能告诉我 ws2_32 到底是哪里的。

MinGW(Minimalist GNU for Windows)是一个用于Windows平台的开源软件开发工具集,它使用GNU工具链,包括GCC编译器和一系列的工具。它的目标是使开发人员能够在Windows平台上使用GNU工具和编译器来编译和构建应用程序。
我在D:\Qt\Qt5.12.8\Tools\mingw730_64下搜索ws2_32库文件,可见 D:\Qt\Qt5.12.8\Tools\mingw730_64\x86_64-w64-mingw32\lib 存在一个 libws2_32.a 文件。可是我们知道,后缀.a的文件,是静态库文件,不是我们使用的动态库。至于这里的.a是不是真正的静态库文件,还是说他是与MSVC动态链接库的.lib引导文件相似,在这里我还拿不准,我后续可能会在 《IDE/在Qt Creator (pro文件) 下DLL动态库的部署和加载问题分析》继续整理它。

如果使用系统Everything搜索,可在系统几十个目录中看到它,有lib后缀有dll后缀。其中几个主要的:
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0\um\x64\WS2_32.Lib、C:\Windows\System32\ws2_32.dll
但我还是不知道,我的项目中到底链接了哪一个。还好,我想起了 Dependency Walker 依赖分析工具,
在这里插入图片描述
通过上述分析可以看出来,我引用的 ws2_32最终是链接到了 C:\Windows\System32\ws2_32.dll 操作系统下边的库,不是mingW的库,MingW也确实没有找到。也就是说,MinGW并没有重新实现套接字库,而是通过与系统的动态库进行链接来使用Windows的套接字编程接口。但这是如何做到的,我自己用MSVC开发的库,可以做到吗?

mingW为啥可以兼容window下的动态库

经过分析,我推测这种兼容性的实现主要基于如下两点:

  • 基于Windows操作系统的开放性和兼容性要求,Microsoft为其他编译器和工具链提供了一些兼容性支持,以确保它们可以在Windows系统中正常使用。
  • 对于像ws2_32.dll这样的系统库,在MinGW等工具链中使用时,通常会提供与MSVC兼容的封装和适配层。这些封装层的作用是将MinGW使用的编译和链接规范转换为与ws2_32.dll兼容的调用方式,以实现与Windows套接字编程接口的交互。
    这种兼容性是通过适当的编译选项、链接设置和调用约定的处理来实现的。MinGW编译器和工具链通过特定的设置和封装层,确保在编译和链接时正确地引用和调用ws2_32.dll中的函数和符号,以实现套接字编程。

虽然Windows系统的库,也极有可能是通过MSVC等工具生成的,毕竟是一家子嘛。但是人家是系统的,人家威望高,而MinGW的目标之一就是在Windows上运行和使用这些系统库,所以作为MingW的开发者,它必须去对这些系统的库做一些封装和适配。而我们自己通过MSVC编译生成的库,是不可能有这种待遇的。分析到这里,我终于有点释怀了,这太复杂,我有点力所不及。

即使MingW套件的开发者,已经尽力的去保证MinGW工具链可以去兼容ws2_32.dll等系统库,但由于编译器和工具链之间的差异,以及特定的编译和链接规范,可能会存在一些细微的差异和限制。因此,在使用MinGW或其他工具链时,建议确保适当的编译选项和设置,以及正确的库文件和版本,以确保与ws2_32.dll的兼容性和正确的套接字编程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/36370.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Flutter】Audioplayers 4.1.0 简要使用说明

文章目录 一、前言二、安装和设置三、基本使用1.创建 AudioPlayer 实例2.设置音频源3.控制播放 四、示例代码五、总结 一、前言 Audioplayers 是一个非常实用的 Flutter 插件&#xff0c;它可以帮助我们在 Flutter 应用中播放音频。无论你是想在你的应用中添加背景音乐&#x…

Docker: 改变容器化世界的革命性技术

目录 1.1什么是虚拟化 1.2什么是Docker 1.3容器与虚拟机的比较 1.4Docker组建 2、Docker安装 2.2设置ustc的镜像 2.3Docker的启动与停止 3、docker常用命令 3.1镜像 3.2容器相关命令 1.1什么是虚拟化 在计算机中&#xff0c;虚拟化&#xff08;Vitualization&#x…

如何从一个仪表盘管理多个WordPress网站?

您是否正在寻找一种管理多个WordPress网站的简单方法&#xff1f; 监控多个网站并使其保持更新可能非常耗时。 幸运的是&#xff0c;有几种 WordPress 管理工具可以让您从单个仪表板管理多个 WordPress 网站变得非常容易。这将帮助您节省大量时间&#xff0c;同时使所有 Word…

赋能智能智造-RK3568智能主板助力机器人产业高速发展

机器人作为现代制造业的重要一环&#xff0c;正在以惊人的速度推动着生产效率和智能化水平的提升&#xff0c;它们在生产线上的准确操作和高效工作&#xff0c;为企业带来了巨大的竞争优势。关于工业机器人的编程和控制技术&#xff0c;在过去几年中已经有了很多发展和新的应用…

Coggle 30 Days of ML(23年7月)任务九:学会Bert基础,transformer库基础使用

Coggle 30 Days of ML&#xff08;23年7月&#xff09;任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 说明&#xff1a;在这个任务中&#xff0c;你将学习Bert模型的基础知识&#xff…

【安全】Xsslabs(1~13)基于白盒测试浅析

目录 环境 关卡 level 1 level 2 level 3 level 4 level 5 level 6 level 7 level 8 扩展 level 9 level 10 level 11 level 12 level 13 总结 环境 PHP&#xff1a;php7.3.4nts 中间件&#xff1a;Nginx1.15.11 工具&#xff1a;Hackbar 关卡 level …

计网简答题

答案不保证正确性&#xff0c;仅供参考。 1.有如图所示的以太网&#xff0c;每个交换机的名字及接口号、主机的名字及MAC地址都标明在图中。网络初启动时&#xff0c;两个交换机的转发表都为空&#xff0c;接着先后进行以下MAC帧传输&#xff1a;H1→H5&#xff0c;H3→H2&…

SPEC CPU 2006 在 CentOS 5.0 x86_64 古老系统测试【2】

上一篇 SPEC CPU 2006 在 CentOS 5.0 x86_64 古老系统测试_hkNaruto的博客-CSDN博客 虚拟机时间&#xff0c;一天后获得结果 由于ssh版本太低&#xff0c;采用nc把文件拷贝出来 结果 SPEC CFP2006 Result Copyright 2006-2023 Standard Performance Evaluation Corporatio…

vue3+cesium项目搭建

前言 最近需要在一个Vue3的项目中使用到cesium&#xff0c;对于一个cesium没有太多了解的人来说&#xff0c;还是比较麻烦的&#xff0c;本篇博文就将自己在这个过程踩的坑记录下来&#xff0c;有需要的可以看一下 1、vuecesium框架搭建 2、项目运行起来后&#xff0c;球体不…

IP协议【图解TCP/IP(笔记九)】

文章目录 IP即网际协议IP相当于OSI参考模型的第3层网络层与数据链路层的关系 IP基础知识IP地址属于网络层地址路由控制■ 发送数据至最终目标地址■ 路由控制表 数据链路的抽象化IP属于面向无连接型 IP即网际协议 TCP/IP的心脏是互联网层。这一层主要由IP&#xff08;Internet…

【MySQL系列】在Centos7环境安装MySQL

「前言」文章内容大致是在Centos7环境安装MySQL&#xff0c;演示安装的版本为5.7 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 浮生梦&#xff0c;三生渺渺&#xff0c; 因缘无踪&#xff0c;虽堪恋&#xff0c;何必…

uniapp 微信小程序导航功能(从地址列表内点击某一个地址)

效果图&#xff1a; <template><view class"user"><view class"list"><view class"title">地址列表</view><view class"title-label"><view>名称</view><view>距离&#xff…

如何做好大客户管理?一文讲清方法、策略、案例

《连线》杂志创始人凯文凯利&#xff08;Kevin Kelly&#xff09;在《技术元素》一书中写道&#xff1a;“数量不是目的&#xff0c;质量才是根本&#xff0c;重视1%的超级用户才是提高效率的关键。” 根据“二八定律”&#xff0c;通常20%的大客户会带来80%的项目和收益。这点…

react 利用antd-mobile实现楼层效果

首先是js模块 import React, { useEffect, useRef, useState } from react import { SideBar } from antd-mobile import ./louceng.css import { useThrottleFn } from ahooksconst items [{ key: 1, title: 第一项, text: <div>12313212313第一项12313212313第一项1…

Python 运算符(一)

文章目录 前言什么是运算符&#xff1f;Python算术运算符Python比较运算符Python赋值运算符Python位运算符 前言 Python 运算符是用于执行各种运算的符号。Python 支持各种类型的运算符&#xff0c;包括算术运算符、比较运算符、逻辑运算符等。在使用 Python 进行编程时&#…

qt 闹钟实现

实现一个闹钟 自定义时间 按下开始后 开始计时&#xff0c;结束计时会播报语音 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer> #include <QTimerEvent> #include <QDateTime> #include <QTime> #include …

【LittleXi】 N-gram模型(C++实现)

LittleXi N-gram模型&#xff08;C实现&#xff09;马尔科夫性 (独立性假设)代码实现英文训练版本中文训练版本 训练效果 N-gram模型&#xff08;C实现&#xff09; 定义&#xff1a;通俗地讲&#xff0c;就是利用前文的单词&#xff0c;来推算下一个最大概率出现的单词 马尔…

springboot超市进销存系统

本次设计任务是要设计一个超市进销存系统&#xff0c;通过这个系统能够满足超市进销存系统的管理及员工的超市进销存管理功能。系统的主要功能包括&#xff1a;首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 商品信息管理、采购信…

Elasticsearch 8.8.1安装及启动

华为云的镜像去下载 ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?CN&OD logstash: https://mirrors.huaweicloud.com/logstash/?CN&OD kibana: https://mirrors.huaweicloud.com/kibana/?CN&OD 原文链接&#xff1a;https://blog.csdn.ne…

2022前端趋势报告(下)

前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 一、前言 本文内容来自于《St…