文章目录

  • 概述
  • 场景复现
  • 用以测试的代码
  • 编译器位数不匹配导致?
  • 保持编译器类型一致
  • 再验证编译器位数的影响
  • 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" {//#endifenum 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的兼容性和正确的套接字编程。

IDE /skipping incompatible xxx_d.dll when searching for -lxxx_d相关推荐

  1. QtzCreator 编译时报警告:skipping incompatible kernel32.dll when searching for -lkernel32

    Qt系列文章目录 文章目录 Qt系列文章目录 前言 一.分析原因 二.解决 前言 在使用QtCreator编译程序时报警告: skipping incompatible kernel32.dll wh ...

  2. skipping incompatible xxxx.a when searching for -lxxx问题的解决

    今天编译时候遇到的问题,cannot find -lapi_gpio,我查了查搜索路径,确认路径没有写错.再看前一条报错,关键词incompatible [不协调,不匹配],怀疑是不是编译哪里出错了. ...

  3. error:/usr/bin/ld:skipping incompatible ./libxxxx.so when searching for -lxxxx

    转自: http://www.scalachina.com/home.php?mod=space&uid=1&do=blog&id=106 第一次在Redhat(64bit)下 ...

  4. skipping incompatible

    *bin/ld: skipping incompatible ./l*.a when searching for -l* */bin/ld: cannot find -l* collect2: ld ...

  5. windows10环境下QtCreator中出现skipping incompatible xxx when searching for xxx 问题解决办法

    windows10环境下QtCreator中出现skipping incompatible xxx when searching for xxx 首先看QtCreator 和 MinGW 是不是其中一 ...

  6. 64 SUSE 下GCC 4.8.2 编译的 skipping incompatible 问题

    最近把GCC升级到了 4.8.2 ,结果编译的时候提示以下错误: /usr/bin/ld: skipping incompatible /usr/local/lib/libstdc++.so when ...

  7. /usr/bin/ld: skipping incompatible -转

    今天碰到的问题: /usr/bin/ld: skipping incompatible qt在连接a和so文件时报错 分析:编译器给出的错误信息已经很清楚了:兼容性问题 解决方法: file xxx. ...

  8. Tina编译报错:/usr/bin/ld: skipping incompatible解决方案

    今天在做项目的时候,用make命令后出现了/usr/bin/ld: skipping incompatible-问题. 分析:编译器给出的错误信息已经很清楚了:兼容性问题,即产生了不兼容性且找不到li ...

  9. QT: skipping incompatible xx/xxx.dll when searching for -lxxx

    遇到这种问题, 属于编译的时候选错了库, 使用64bit的编译, 结果选的是32bit的dll库导致的 使用下面的配置区分i386 或者x64的环境, 分别将库放到对应位置即可 win32 {## 标 ...

最新文章

  1. CentOS 6.5 下配置Java环境
  2. Collections.addAll() 的使用 以及和list.addAll() 的区别
  3. 联通光纤限制连接数_从数百万个光纤(而不是数千个线程)中查询数据库
  4. Jqgried树形列表
  5. 如何在python官网下载pip_[Python]Pip的安装以及简单的使用
  6. ROS 教程之 vision: 摄像头标定camera calibration
  7. 2.6 更多导数的例子
  8. solve mass matrix in matlab
  9. oracle怎么截取long类型,Oracle 数据库中 Long 类型字段的读取
  10. JUC与JVM并发编程学习笔记03
  11. Linux的Cache Memory(缓存内存)机制
  12. 【VRP问题】基于狼群算法WPA求解带时间窗车辆路径规划问题(VRPTW)matlab源码
  13. 阿里巴巴上市路演ppt 官方完整版
  14. VMware出现“该虚拟机似乎正在使用中”问题
  15. html显示文件夹图片,Html读取本地文件夹下图片并显示
  16. oracle11g64位怎么用sql,PLSQL连接Oracle11g64位
  17. 图书馆小程序—Alpha迭代—第七周会议记录
  18. 回车、换行、空格的ASCII码值(不同OS平台下文件换行定义)
  19. 服务器指示灯详情 中兴,IBM System x服务器前面板指示灯说明(新版)
  20. GameFramework:打包资源,打随app发布包,打包生成文件夹说明,上传资源至服务器,下载资源,GameFreamworkList.dat 与GameFrameworkVersion.dat

热门文章

  1. html和css牛刀小试
  2. Apifox验签脚本大众版
  3. Codeforces 832D题解报告
  4. [附源码]计算机毕业设计JAVAjsp医院药房管理系统
  5. OO2023-U3-JML
  6. Python优雅地生成Morton码
  7. 14.1 NFS介绍 14.2 NFS服务端安装配置 14.3 NFS配置选项
  8. windows 网络编程 WinNet
  9. 微信小程序-获取当前城市位置
  10. 51单片机-灯饰自燃紧急处理系统设计(外部中断01定时器中断1)