Windows 下使用 gcc/g++ 编译器

MSVC:从入门到放弃

从一开始修改 JincResize 代码到现在,代码编译后 dll 运行缓慢的问题一直困扰着我。虽然原作者说运行速度慢,但我自己编译的也太慢了(1.5 fps vs 9 fps)。改了一些代码(主要是涉及 C 语言和 C++ 的区别),但对速度无肉眼可见的影响。这样下去,代码重构也没有动力。

思考了一下,做了一下对照实验。使用原作者代码,直接在 VS2019 中编译(除了为在 VS2019 中编译通过,修改了一处代码外,其余代码均未改动),也很慢,也是约9s/帧。这样让我明确了一点,就是编译方面的问题,导致运行速度缓慢的。

我又仿照 HomeOfVapourSynthEvolution 的预处理设置,并在编译中尽量使用加快代码速度的优化参数,但最终的编译结果仍没有什么改善。

所以我有理由判断,是编译器的锅。(也许是现在的代码,虽然做了从 C 到 C++ 的迁移,但仍有 C 的风格,导致和 VS 的纯 C++ 编译器八字不合?)

不管怎么说,改用 gcc/g++。

使用 gcc 编译 C 语言代码

前两天用了一次 gcc 编译 C 语言代码,但不知道怎么自行设置头文件和库文件路径,所以就放弃了。

今天明白了,库文件不一定需要,而反正我所需要的头文件就两个,直接复制过来就好了。

直接编译原作者代码。

1
gcc -o ewa_lanczos.dll -shared ewa_lanczos.c

能编译通过,但 VapourSynth 中无法调用。想了一下,这里的 gcc 是 32 位,和 64 位的 VapourSynth 不搭,于是换用64位的gcc,并打开-O2优化。

1
x86_64-w64-mingw32-gcc -o ewa_lanczos.dll -shared -O2 ewa_lanczos.c

VapourSynth 成功运行,而且速度也和原作者的差不多了!Dll 体积也差不多,我感觉原作者就是这么编译的

使用 g++ 编译 C++ 代码

动态编译

虽说 gcc 也不是不能编译 C++,但毕竟…还是用专业的 g++ 吧。

1
x86_64-w64-mingw32-g++ -shared -o JincResize.dll -O2 JincResize.cpp

编译出来的 dll,VapourSynth 无法调用。我怀疑是没有配置库文件的锅,因为在 CSDN 上看到一篇博文,说需要库文件却没有配置时,这样也能编译通过、不报错。也就是默认编译模式下,看不见缺失库文件的问题

于是我照这篇博文的方法,加上了-Wl,--no-undefined参数,这样就能暴露缺失库文件问题。

1
x86_64-w64-mingw32-g++ -o JincResize.dll -shared -O2 -Wl,--no-undefined JincResize.cpp

但我试了一次,仍没有报错,正常地编译通过。

这篇博文的帮助下,我明白了 g++ 是动态编译,编译好的 dll 依赖于其他 dll。想起了之前安装MXNet的踩坑经历,(我也能自引了,积累是有用的)。使用 Visual Studio 的 dumpbin 工具查到了依赖的两个dll。

但与博文中把 dll 放到程序目录就 OK 不同的是,这两个 dll 我无论是放到 VapourSynth 的文件(VapourSynth 下各种文件夹都试过了),还是System32中,都依然无法调用我编译的 dll。只得另寻他法。

(况且就算这种方法能行,我也不能这么干,我不可能在发布时再“顺带”发布两个依赖,这也太蛋疼了)

静态编译

这篇博文告诉我,可以通过静态编译的方式避免上述依赖的问题。

只加上-static-libgcc-static-libstdc++这两个参数,还是不行。于是干脆使用-static,全局静态编译。

1
x86_64-w64-mingw32-g++ -shared -o JincResize.dll -O2 -static JincResize.cpp

终于成功了。(dll 大小:63kb -> 415kb -> 451kb)

Dll 运行速度也是和原作者的相似(所以我增加模板函数和其他修改并没有拖垮速度嘛)。

这样后续的代码重构也有动力了!

后记

这半天加晚上的折腾过程,从一开始的毫无头绪,到折腾 CodeBlocks 和 MinGW,从第一次使用 gcc 编译成功 C 语言代码、获得能用的 dll,到动态编译 C++ 虽缺少依赖,但能平静地寻找解决办法。真的是很棒的经历。

加油吧,相信自己。