Qt 加载 libjpeg 库出现“长跳转已经运行”错误问题解决

2023-05-17 08:05:34 错误 加载 跳转

参考资料:Qt5.15.0 升级至 Qt5.15.9 遇到的一些错误

篇幅有点长,先说解决方法,在编译静态库时加上 -qt-libjpeg,编译出 libjpeg 库后,在项目中使用 #pragma comment 链接即可

OK,开始回顾痛苦经历

在我以为升级到 Qt5.15.9 后,运行没有什么问题时,问题就来了

在加载 jpeg 格式的图片时,出现了“长跳转已经运行”的错误

这个错误一般是由 setjmp/longjmp 函数触发的,出现的可能的原因有以下几种(听听 chatgpt 的回答)

longjmp 是 C 标准库中的一个函数,用于跳转到之前通过 setjmp 函数设置的跳转点,并在跳转时返回指定的错误码。如果在调用 longjmp 函数时出现错误,通常会表现为程序异常终止、崩溃或死等问题。

longjmp 函数可能出现错误的原因和解决方法如下:

1.调用 setjmp 的函数已经返回

使用 longjmp 函数必须要在之前调用过 setjmp 函数并且还没有从 setjmp 函数返回时才能使用。如果在 setjmp 函数返回后再调用 longjmp 函数,就会导致未定义行为,可能会导致程序崩溃或死锁。解决方法是检查 longjmp 函数的调用时机,并确保它是在 setjmp 函数之后而且还没有从 setjmp 函数返回时调用的。

2.跳转目标不存在

当 longjmp 函数尝试跳转到之前设置的跳转点时,如果该跳转点已经不存在,就会导致错误。这种情况通常发生在跳转点所在的函数已经返回或者被释放时。解决方法是检查跳转点是否存在,并确保跳转点所在的函数仍然有效。

3.跨线程调用

longjmp 函数通常不适用于多线程程序。如果在一个线程中设置了跳转点,然后在另一个线程中调用 longjmp 函数来跳转到该点,就会导致未定义行为。解决方法是使用线程安全的异常处理机制来代替 longjmp 和 setjmp 函数。

4.其他原因

除了上述几种情况外,还有可能是其他一些原因导致 longjmp 错误。例如,内存泄漏、非法指针访问、堆栈溢出等问题都可能导致 longjmp 函数失败。解决方法是根据具体错误信息进行排查和修复。

我这边是触发 ERREXIT2 后而跳出的错误

ERREXIT2 的原型如下

触发 ERREXIT2,进入 my_error_exit 函数,然后调用 longjmp,最后程序异常崩溃

为何有这种丑陋的报错呢?官方应该可以把这种报错 catch 下来,而不是让程序闪退,看看 llbjpeg-turbo 作者给出的解释

原始链接:Possibility of non-unwinding error handling

简单说来,ERREXIT 是官方的 libjpeg 遗留下来的,代码很古老,至今没人修,而 libjpeg-turbo 只是包装了 libjpeg 库,这样加载更快,对 libjpeg 中的 api 没有任何改变,他也可以帮忙包装下这个报错,只是要加钱

话说回来,我为何会遇到 ERREXIT 呢?

那就不得不说 Qt 对 5.15 后续版本做出的一些改动了

见:https://doc.qt.io/qt-5/qtgui-attribution-libjpeg.html

就是说 libjpeg 要你自己去链接,我们不再帮你集成到 qjpeg.lib 中了,可能是协议问题

Independent JPEG Group License and BSD 3-Clause "New" or "Revised" License and zlib License.

既然问题找到了,那解决方法“应该”也能浮出水面了,对,打上双引号的应该

事实上是我低估了这个问题,原本我以为加个 libjpeg-turbo 的库之后就能万事大吉时,结果往往给你一个嘴巴子

我用 vcpkg 包管理器添加了 libjpeg-turbo:x86-windows-static,程序编译通过,也没有出现 ERROR2019 的错误,但是使用 loadFromData 加载 jpeg 图片数据还是会报错

QImage photo;
photo.loadFromData(buffer.GetBuffer(), buffer.GetBufferLen()); // buffer 里放置 jpeg 图片数据

我第一反应是 libjpeg-turbo 的库版本太高了,就查阅低版本的库,想通过 vcpkg 新出的版本控制来实现的,奈何水平有限,没弄出来,就去官网下载 2.1.3 的压缩包自己编译

之所以编译 2.1.3 的包,是因为 Qt5.15.9 版本将 libjpeg-turbo 更新至 2.1.3

见:Https://code.qt.io/cgit/qt/qtreleasenotes.git/about/qt/5.15.9/release-note.md

编译出一个 lib 库后,链接到程序中,还是会报错,嗯,那先排除 libjpeg 版本问题

从堆栈下手吧,一层一层的剥开问题表皮,看本质

报错是停在红框中的 ERREXIT2 中,单步调试后发现,qt 里要求 libjpeg-turbo 的 version 为 80,而 vcpkg 提供的所有 libjpeg-turbo 版本都是 62,可以在 jconfig.h 中查看 version

嗯,80 的为 qt 专属,这就解释了为啥触发了 ERREXIT2 了,顺便说一句,vcpkg 提供的库其实就是官方的库,libjpeg-turbo 不管是 2.1.5 还是 2.1.3,JPEG_LIB_VERSION 都是 62

因此我们只要编译一个 libjpeg 的 qt 三方库就行了

参考资料:这篇教程

使用 Qt Creator(我使用的 Qt Creator 10.0.0) 打开 libjpeg.pro,再在 .pro 文件里改 lib 输出路径就行

顺便贴上构建设置

可能需要将 jom.exe 改成 nmake.exe(打开 pro 项目后,在构建和运行中选择)

这些都准备后,点击编译即可,在 lib 文件夹中就可以找到了

把库放到项目文件的库目录下,并静态绑定即可

是不是很复杂,直到上一步我也是这么以为的,在我全局搜索 qtlibjpeg.lib 时,我发现 qt 下已经给你编译好了

惊不惊喜意不意外(我都要骂娘了)

重新阅读了官方文档,上面说你可以选择在编译静态库时添加一些参数来一起编译你需要的三方库,比如 libjpeg

见:https://doc.qt.io/arcHives/qt-6.0/configure-options.html

是我大意了,附上编译命令,

configure -static -static-runtime -debug-and-release -mp -prefix "..\msvc2019_x86_static" -opensource -confirm-license -optimize-size -qt-libjpeg -make libs -nomake examples -nomake tests -skip qtWEBengine

编译出的库文件就在 lib 下

小结:还是对 Qt 的库配置不熟悉,导致花了大量工夫来解决这种问题;好在有了这次经验后,以后再遇到类似问题,就能手到擒来了

到此这篇关于Qt 加载 libjpeg 库出现“长跳转已经运行”错误的文章就介绍到这了,更多相关Qt 加载 libjpeg 库内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

到此这篇关于Qt 加载 libjpeg 库出现“长跳转已经运行”错误问题解决的文章就介绍到这了,更多相关Qt 加载 libjpeg 库内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

相关文章