Qt:编译器、MSVC、Mingw、dll调用

一、两者的区别

1、MSVC

即Microsoft Visual C++ Compiler,即微软自己的编译器。

我们下载Windows下的OpenCV时,解压后里面有两个文件夹,一个是build,一个是source,build这个文件夹实际上是官方已经提前给我们编译好了的库,会带两个文件夹VC14,VC15(分别与Visual Studio的版本有对应关系),这两个文件夹下的库可以直接运行不需要编译将VS作为Qt的开发环境也是使用这个编译器的缘故,但是,使用的必须是msvc编译器,不能够跨平台。

2、MinGW

我们都知道GNU在Linux下面鼎鼎大名的gcc/g++,MinGW则是指Minimalist GNU for Windows的缩写它是将GNU开发工具移植到Win32平台下的产物,即一套Windows上的GNU工具集。
用其开发的程序不需要额外的第三方DLL支持就可以在Windows下运行,相对地,不使用动态库导致的就是编译出来的程序大很多。也是可以设置使用静态库的,mingw编译器需要自己手动编译source文件生成库文件,mingw这个编译器能够跨平台,能够在linux、arm等平台使用,这些平台使用的编译器都是g++、gcc。

二、两者优缺点

1、MSVC的优缺点

优点:

qtcreator的debuger有功能缺陷,经常会出现变量无法查看的问题,棘手的bug还是需要在VS环境下进行调试。很多人的开发模式就是qtcreator写代码,VS下面做调试。

缺点:

不能跨平台

编码的问题,QT5的Qstring默认是UTF8格式,QT5极力推介把源码用UTF8格式存储。 但是MSVC只支持带BOM的UTF8格式,qmake不支持带BOM的UTF8格式,逼我只能用GBK么。这样的话,用qt5,每次都要Qstring::fromLocal8bit(“我是中国人”);况且就算BOM问题解决了,源代码是UTF8了。MSVC的执行编码也是GBK

2、MinGW的优缺点

优点:

能跨平台

缺点:

MinGW无法利用生成的dump文件在windbg或VS下面定位到出错的代码

Scene3D在MinGW64位Release和MinGW32位Debug模式下运行直接闪退,而64位Debug和32位Release却正常运行。

动态删除继承QuickItem的对象,有几率导致非法内存访问,可以定位到问题在Qt源码中Renderer中的一处

三、两者的区别

1、编译器:

MinGW 使用GNU编译器集合(GCC)的变体,它是一个开源的编译器工具链,支持多种编程语言。MinGW 的编译器通常被称为 GCC 或 G++。
MSVC 使用 Microsoft 的专有编译器,该编译器是 Visual Studio 集成开发环境(IDE)的一部分,通常称为 cl.exe。

2、标准库:

MinGW 通常使用 GNU 的标准 C 库(glibc)或 MinGW-w64 中的 C 运行时库。它还可以使用 MinGW 专用的头文件和库,以便在 Windows 上开发。
MSVC 使用 Microsoft 的 C 运行时库(CRT),这意味着它具有与 Windows API 更好的集成,但在一些情况下可能不够跨平台。

3、开发环境:

MinGW 通常以类 Unix 的方式工作,可以使用命令行或与其他开发工具集成,通常是在 MSYS2 上开发
MSVC 通常与 Visual Studio IDE 一起使用,提供了一种集成的开发环境,具有丰富的图形用户界面和调试工具。


在编译产物上,它们都可以编译出 .exe 可执行程序,但是 MinGW 通常是依赖于 dll 动态库,因为静态库是 .a 文件,所以会在编译时将静态库链接到 exe 文件里,故 MinGW 编译出的 exe 文件通常比较大

而 MSVC 可以依赖 dll 动态库以及 lib 静态库,这就让编译出的 exe 文件可以比较小

下面是库依赖上的区别:

1、库文件格式:

MinGW 使用的是 GNU 工具链,因此它通常使用与 GNU 标准库兼容的库文件格式。这些库文件具有以  .a  为扩展名的静态库和以 .dll 为扩展名的动态链接库。
MSVC 使用 Microsoft 的 C/C++ 标准库格式,这些库文件通常以  .lib 为扩展名,但也可以包含 .dll 动态链接库文件。


2、库的兼容性:

MinGW 生成的库文件通常与 MSVC 生成的库文件不兼容。这意味着你不能将 MinGW 生成的对象文件与 MSVC 生成的库文件链接,反之亦然。
如果你使用 MinGW 编译你的应用程序,你需要确保你使用的库是专门为 MinGW 编译的,或者在构建库时采用兼容的编译选项。
同样,如果你使用 MSVC 编译,你需要使用与 MSVC 兼容的库文件。


3、第三方库支持:

一些第三方库可能会提供适用于 MinGW 和 MSVC 的不同版本。在选择库时,你需要确保选择与你的编译器兼容的版本。
有些库可能提供了 CMake 或其他构建工具的支持,这些工具可以帮助你在不同的编译器下进行构建。

 四、库引用方式

1、MSVC编译的库是xxx.dll和xxx.lib,MingW编译的库是libxxx.dll和libxxx.dll.a

其中lib文件和.a文件一般都是对dll的引导;或者是包含了所有的源码,作用和dll一样

2、Qt调用msvc的dll

INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/PluginFramework
INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/Libs/Core

LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_msvc2017/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework

INCLUDEPATH +是头文件路径

LIBS +是lib库路径,这个路径下需要同时有dll和lib文件

3、Qt调用mingw的dll

INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/Libs/PluginFramework
INCLUDEPATH += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/Libs/Core

LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/ -llibCTKCore
LIBS += -LC:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/ -llibCTKPluginFramework

LIBS += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/libCTKCore.dll.a
LIBS += C:/Users/Administrator/Desktop/new/CTK-master/build_mingw64/CTK-build/bin/libCTKPluginFramework.dll.a

五、最后的选择

到底选择哪个版本,MinGW 比较方便,配置易上手适合初学者,MSVC功能强大,适合进阶,但是具体项目上要根据依赖的第三方库选择版本。

如果你的第三方库是msvc的,能可能就必须msvc,如果第三方库是mingw的可能就必须mingw。

跨平台开发的话,用的库基本上一定是Linux能用的库,而Linux能用的库一定是在mingw下支持会比较好。(mingw甚至能 include unistd.h 之类的Linux专用头文件),那就优选mingw。

注意Qt版本:msvc和MinGW版本的区别。msvc使用的是vs的编译器,这个版本主要用于PC开发;MinGW版本使用MinGW编译器,主要用于跨平台开发。两个版本的Qt配置方式完全不同。因此在网上搜配置方法时候,要加上msvc或者MinGW这样的关键字一块搜索。网上大部分内容是关于MinGW版本的配置方法,我本地使用的是msvc版本。Msvc版本配置比较简单;MinGW版本需要下载cmake自行编译opencv。

六、Qt中的各种编译器

1.uic:UI编译器,将.ui文件转化为ui_*.h文件

2.rcc:资源编译器,将.qrc文件转换成qrc_*.h文件

3.moc:元对象编译器,将含有Q_OBJECT的头文件转换成标准.h文件

4.qmake : 把pro文件编译成makefile文件,然后可以调用make命令

5.MSVC:微软VC++编译器

6.MinGW:gcc编译器


 

七、使用QLibrary加载动态库

使用QLibrary可以在程序运行时加载动态链接库。一个QLibrary的实例作用于一个单一的共享库上。QLibrary提供了一种平台无关的方式访问库中的函数。可以在构建QLibrary的实例时将要加载的库文件传入,也可以在创建实例后使用setFileName()显式的设置要加载的文件名。当加载库文件时,QLibrary会搜索所有平台特定的库位置,除非传入的文件名具有绝对路径。

如果传入的文件名具有绝对路径,那么会首先尝试加载该目录。如果该文件找不到,QLibrary会使用不同的平台特定的文件前缀或后缀再次尝试,比如Unix和Mac平台的"lib"前缀,Unix平台的".so"后缀,Mac平台的".dylib",Windows平台的".dll"。如果文件名不是绝对路径,QLibrary会修改搜索顺序,首先尝试系统特定的前缀和后缀,紧接着是指定的文件路径。

所以,基于QLibrary对库文件的搜索机制,我们推荐在传入库文件时只传入该库文件的基名,不写前缀或后缀。这样一来,同一份代码可以在不同的操作系统上工作,并且该机制会保证进行最小次数的搜索。

该类中最重要的函数是load(),该函数动态的加载库文件,isLoaded()可以用来检查库文件是否成功加载,而resolve()函数则用来解析库中的符号地址,主要是函数地址。并且,resolve()函数在库文件未被加载时会隐式的尝试加载它。多个QLibrary实例可以可以访问同一个库文件。因为,库文件一旦被加载,就会驻留在内存中直到应用程序终止。当然,我们可以使用unload()函数来尝试卸载一个库文件,但是如果有其他的QLibrary实例正在引用同一个库文件,unload()会调用失败,并且该库文件会在所以实例都调用了unload()后才被卸载。

QLibrary库的典型用法是去解析一个库中的导出符号,并调用该符号表示的C函数。这被称为“显式链接”,而相对的“隐式链接”是在编译过程的链接阶段完成的。如下面的代码显示的那样,改代码先加载一个库,解析其中的"mysymbol"符号,并在成功的情况下,调用该函数。如果由于某种原因出错了,例如库文件不存在或该符号未被定义,那么相应的函数指针将被设为空,不会发生实际的调用:

QLibrary myLib("mylib");  
typedef void (*MyPrototype)();  
MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol");  
if (myFunction)  
    myFunction();  

但该符号必须被导出为C函数。也就是说,如果该库是由C++编译器编译的,那么该函数必须被包在extern "C"块中。并且在Windows平台上,还需要使用dllexport宏来修饰该函数。

出于方便,该类还提供了一个静态的resolve()函数,我们可以使用该函数来解析并调用一个库中的方法,而不需要先加载该库。如下代码所示:

typedef void (*MyPrototype)();  
MyPrototype myFunction =  
        (MyPrototype) QLibrary::resolve("mylib", "mysymbol");  
if (myFunction)  
    myFunction();  

其实,除了静态的resolve()函数,该类还提供了一个静态的isLibrary()函数,该函数可以根据特定平台来判断一个文件是否是可被加载的库。其所使用的规则如下:

八、QT MinGW 怎样调用 VS的DLL库

Qt 库用的是MinGW版本,g++编译器生成,与VC++编译器不是同个体系。所以工程不可以使用testdll.h头文件和testdll.lib引入库文件。
使用了在pro文件添加的方式 失败!
修改.lib为.a的方式 失败
添加静态库 也失败。在绝望时刻 发现了这个方法!!!太好了
对于调用DLL的方法,Qt本身就有相应的类来实现。

例1:

#include "dialog.h"
#include <QApplication>
#include <QLibrary>
**typedef int (*func_Add)(int a, int b); //定义函数指针**(一定要与要调用的库里面的参数类型及返回类型一致)
typedef int (*func_Sub)(int a, int b);
typedef int (*func_Mul)(int a, int b);

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

    QLibrary mylib("testdll.dll");//testdll.dll的存放路径与.exe一致
    if (mylib.load())
    {
        **//"?Add@Ctestdll@@QAEHHH@Z"等字符串其实就是动态库函数int Add(int a, int b)的变体,请使用微软工具DEPENDS.EXE查看得到**(最重要的一步 从?开始的所有内容都要复制)
        func_Add f1 = (func_Add)mylib.resolve("?Add@Ctestdll@@QAEHHH@Z");
        func_Sub f2 = (func_Sub)mylib.resolve("?Sub@Ctestdll@@QAEHHH@Z");
        func_Mul f3 = (func_Mul)mylib.resolve("?Mul@Ctestdll@@QAEHHH@Z");
        int rt = 0;

        if (f1 != NULL)
        {
            rt = f1(10, 12);
        }

        if (f2 != NULL)
        {
            rt = f2(10, 12);
        }

        if (f3 != NULL)
        {
            rt = f3(10, 12);
        }
    }`在这里插入代码片`
(完美运行!!!)
    Dialog w;
    w.show();
    return a.exec();
}

例2:

ZLGLIB.h

#ifndef _ZLBLIB_
#define _ZLBLIB_

#pragma once
#include "ControlCAN.h"


extern VCI_OpenDevice OpenDevice;
extern VCI_CloseDevice CloseDevice;
extern VCI_InitCAN InitCAN;
extern VCI_ReadBoardInfo ReadBoardInfo;
extern VCI_ReadErrInfo ReadErrInfo;
extern VCI_ReadCANStatus ReadCANStatus;
extern VCI_GetReference GetReference;
extern VCI_SetReference SetReference;
extern VCI_GetReceiveNum GetReceiveNum;
extern VCI_ClearBuffer ClearBuffer;
extern VCI_StartCAN StartCAN;
extern VCI_ResetCAN ResetCAN;
extern VCI_Transmit Transmit;
extern VCI_Receive Receive;


BOOL ZLGLIB();

#endif 

ZLGLIB.cpp

//
#include "stdafx.h"
#include "ZLGLIB.h"
#include <QLibrary>

VCI_OpenDevice OpenDevice;
VCI_CloseDevice CloseDevice;
VCI_InitCAN InitCAN;
VCI_ReadBoardInfo ReadBoardInfo;
VCI_ReadErrInfo ReadErrInfo;
VCI_ReadCANStatus ReadCANStatus;
VCI_GetReference GetReference;
VCI_SetReference SetReference;
VCI_GetReceiveNum GetReceiveNum;
VCI_ClearBuffer ClearBuffer;
VCI_StartCAN StartCAN;
VCI_ResetCAN ResetCAN;
VCI_Transmit Transmit;
VCI_Receive Receive;

QLibrary lib("ControlCAN.dll");

BOOL ZLGLIB()
{
	OpenDevice = NULL;
	CloseDevice = NULL;
	InitCAN = NULL;
	ReadBoardInfo = NULL;
	ReadErrInfo = NULL;
	ReadCANStatus = NULL;
	GetReference = NULL;
	SetReference = NULL;
	GetReceiveNum = NULL;
	ClearBuffer = NULL;
	StartCAN = NULL;
	ResetCAN = NULL;
	Transmit = NULL;
	Receive = NULL;

	if(!lib.load())
	{
		return FALSE;
	}

	OpenDevice = (VCI_OpenDevice)lib.resolve("VCI_OpenDevice");
	CloseDevice= (VCI_CloseDevice)lib.resolve("VCI_CloseDevice");
	InitCAN= (VCI_InitCAN)lib.resolve("VCI_InitCAN");
	ReadBoardInfo= (VCI_ReadBoardInfo)lib.resolve("VCI_ReadBoardInfo");
	ReadErrInfo= (VCI_ReadErrInfo)lib.resolve("VCI_ReadErrInfo");
	ReadCANStatus= (VCI_ReadCANStatus)lib.resolve("VCI_ReadCANStatus");
	GetReference= (VCI_GetReference)lib.resolve("VCI_GetReference");
	SetReference= (VCI_SetReference)lib.resolve("VCI_SetReference");
	GetReceiveNum= (VCI_GetReceiveNum)lib.resolve("VCI_GetReceiveNum");
	ClearBuffer= (VCI_ClearBuffer)lib.resolve("VCI_ClearBuffer");
	StartCAN= (VCI_StartCAN)lib.resolve("VCI_StartCAN");
	ResetCAN= (VCI_ResetCAN)lib.resolve("VCI_ResetCAN");
	Transmit= (VCI_Transmit)lib.resolve("VCI_Transmit");
	Receive= (VCI_Receive)lib.resolve("VCI_Receive");

	if (OpenDevice == NULL || CloseDevice == NULL|| InitCAN == NULL 
		|| ReadBoardInfo == NULL || ReadErrInfo == NULL || ReadCANStatus == NULL 
		|| GetReference == NULL || SetReference == NULL || GetReceiveNum == NULL 
		|| ClearBuffer == NULL || StartCAN == NULL || ResetCAN == NULL  
		|| Transmit == NULL || Receive == NULL 	)
	{
		return FALSE;
	}

	return TRUE;
}


  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
切换Qt MinGW编译器MSVC编译器需要进行以下步骤: 1. 首先,将项目中的编码问题解决。可以使用Notepad++将文件编码转换为usc-2 little endian编码或utf-8-bom编码格式,以解决中文问题。 2. 解决编译器报错问题。如果在编译过程中遇到类似于“qalgorithms.h:847: error: C3615: constexpr 函数 ‘qCountLeadingZeroBits’ 不会生成常数表达式”这样的错误,可以参考链接\[1\]中提供的解决办法。 3. 解决乱码问题。如果在运行程序时遇到乱码,可以在代码中添加以下语句来设置字符集: ``` #if _MSC_VER >= 1600 #pragma execution_character_set("utf-8") #endif ``` 这样可以确保程序以UTF-8字符集运行。 4. 切换编译器。将Qt MinGW编译器切换为MSVC编译器,可以下载Windows下的OpenCV,并解压后找到build文件夹。在build文件夹中,选择与你使用的Visual Studio版本对应的文件夹(如VC14或VC15),这些文件夹中已经包含了编译好的库,可以直接使用而无需再进行编译\[2\]。 请注意,切换编译器可能会导致一些依赖库的不兼容问题,需要确保项目中的其他依赖项与新的编译器兼容。 参考资料: \[1\] https://codereview.qt-project.org/c/qt/qtbase/+/236948/2/src/corelib/tools/qalgorithms.h#864 \[2\] https://blog.csdn.net/cn_cc/article/details/122220232 \[3\] https://blog.csdn.net/weixin_43943902/article/details/103654051 #### 引用[.reference_title] - *1* [QT MinGw编译项目代码转msvc编译器报错等问题](https://blog.csdn.net/cn_cc/article/details/122221036)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Qt编译器MinGWMSVC的区别](https://blog.csdn.net/qq_43445867/article/details/127889570)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

高亚奇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值