使用软件版本:
下载好各版本的 wx 或者是 wxPack_v2.8.7.03,wxPack 包含的库文件较全,要正确编译工程,就需要设置定义以下编译选项,否则配置不正确,就算编译通过也无法运行:
这两个选项是对应工程向导中的 Use wxWidgets DLL 和 Enabled Unicode 两个选项。
wxPack安装包含动态链接和静态链接两个版本的文件,lib目录下gcc_dll对应动态链接,gcc_lib对应静态连接,这个文件夹也是没有DLL文件的,需要在编译选项中设置好路径指向。gcc_lib目录下就有这四个文件,分別是Unicode和非U版的,特别大的文件:
libwxmswu.a 98MB
libwxmswud.a 99MB
libwxmsw.a 17MB
libwxmswd.a 17MB
如果准备编译wx源代码如 wx 2.8.6,需要准备好 mingw32-make 3.8以上版本,编译wx时生成合集库文件,即 Monolithic Library,需指定MONOLITHIC=1,需要静态编译时要指定SHARED=0,这样才能进行静态链接的程序开发,j4表示四线程编译,如果有个4核的CPU就可以用它来提速,例如:
mingw32-make -j4 -f makefile.gcc MONOLITHIC=1 SHARED=0 UNICODE=1 BUILD=debug
mingw32-make -j4 -f makefile.gcc MONOLITHIC=1 SHARED=0 UNICODE=1 BUILD=release
以上使用的编译参数可以在wx安装目录下的build子目录下的配置文件找到,也可以直接修改配置文件来达到同样的效果。在构建合集库最后的链接阶段是非常耗内存,如果使用较新版的 mingw 编译则可以添加以下参数来尽量避免内存不足的问题,如果需要编译动态链接+DEBUG+MONOLITHIC则强烈建议采用,否32位机的内存很快就会被吃光 Memory exhausted。因此建议机子配置不高的情况下不要进行这样的高要求编译任务,否则到最后得来一句就是浪费电!
CXXFLAGS=-fno-keep-inline-dllexport 不导出内联符号,损失内联符号调试信息
USE_EXCEPTIONS=0 禁用内部异常处理
USE_RTTI=0 禁用内部运行时类型机制
官方文档 Reducing Executable Size 指导减小程序大小明确提到可以禁用RTTI,因此去掉这部分功能可以节省可观的内存。因为使用mingw平台来开发wxWidgets程序有大量的好工具可以使用,因此MS编译平台不是优先选择目标。但值得注意的是,MSVC的编译器生成的代码确实要比mingw的小,因此可以考虑在最后的编译阶段切换到MSVC平台下编译。要使用mingw编译wxWidgets源代码,可以直接进入win平台的配置目录:
@wxWidgets-2.8.12\build\msw
按以上提示进行修改,或保持默认值,通过命令行进行配置,并执行编译命令,或保存为脚本执行。由于当前使用 TDC-GCC 4.7.1中没有自带libgcc_s_dw2-1.dll
,而make命令又需要,因此直接从 4.8.1版本拷贝过来一份。命令中修改了VENDOR这个参数,因为它会影响编译结果输出的文件名后缀,默认值是custom,所以一些没有修改这个参数的编译结果就会带custom这个后缀。:
set mingw=C:\CodeBlocks\mingw471
set path=%mingw%\bin
set flags=INCLUDE="%mingw%\include" LIB="%mingw%\\lib"
set opts=BUILD=release UNICODE=1 VENDOR="" GCC_VERSION=4.7.1
set mod=MONOLITHIC=1 USE_GUI=1 USE_GDIPLUS=1 USE_OPENGL=1
set libtype=RUNTIME_LIBS=static SHARED=0
mingw32-make.exe -j4 -f makefile.gcc %flags% %opts% %mod% %libtype%
注意命令行中还使用了 j4 四线程加速,整个编译过程就很快了,十分钟这样子就好了,而且没有使用上面提到的CXXFLAGS,也没出现内存不足问题,这是因为静态编译节省了大量额外的动态链接工作。Unicode版的静态链接库其实是适用性较高的一种选择,编译好的库已经打包上传到CSDN,后面附上下载地址。
新建wx工程时,在向导界面设置 wxWidgets Library Setting 时,去掉 Use wxWidgets DLL 选项,而选择 Monolithic Library 选项。这样,工程才会以上面列出的链接库来生产程序。
测试中发现 Codeblock 10.05 + wxPack_v2.8.12 搭配运行是较稳定的,亦即 g++ 4.4.1 及 g++ 4.5.0 和 wxPack v2.8的组合较好。CodeBlocks 13.12 则和 wxMSM 3.0 搭配使用较好。尽管如此,通过下面的两组测试数据,发现 wxWidgets 的源代码移植问题应该是比较多的,工程质量可能会大受影响。
以下是一组搭配动态链接测试数据:
组合 | g++ 4.4.1 | g++ 4.6.2 | g++ 4.7.1 | g++ 4.8.1 | g++ 4.9.2 | g++ 5.1.0 |
---|---|---|---|---|---|---|
wxMSW 3.0.2 | 1 | 1 | OK | 2 | OK #i | 3 |
wxMSW 3.0 | 8 | 7 | OK #ii | OK | 3 | 3 |
wxPack2.8.12 | OK | OK | 4 | 5 | 4 | 6 |
以下是一组搭配静态链接测试数据:
组合 | g++ 4.4.1 | g++ 4.6.2 | g++ 4.7.1 | g++ 4.8.1 | g++ 4.9.2 | g++ 5.1.0 |
---|---|---|---|---|---|---|
wxPack 2.8.7 | OK | 10 | 11 | 5 | 11 | 6 |
wxPack2.8.12 | 10 | OK i3 | 10 | 10 | 10 | 6 #10 |
#1 Error wxbase30u_gcc471TDM.dll 模块问题
#2 Error pthreadGC2.dll 模块的错误
#3 Error 编译错误过多
#4 Error wxbase28ud_gcc.dll模块异常;或 StackHash 模块错误。
#5 Error 正常编译,可以运行,但是进程为僵尸状态,不显示界面不提示错误。
#6 Error 编译错误,提示语法问题。
#7 Error wxbase30u_gcc481TDM.dll、wxbase30ud_gcc481TDM.dll 模块问题。
#8 Error wxbase30u_gcc481TDM.dll 或 程序自身模块问题不能运行,但编译通过无出错。
#9 Error 错误过多,基本是符号引用错误。
#10 Error 符号_Unwind_Resume引用问题,涉及异常处理,包含 libgcc_s.a 亦未解决。
#11 Error 程序自身模块问题不能运行,但编译通过无出错。
#i Info 使用 ISO C++ 2011 ,添加编译参数 -std=c++11 or -std=gnu++11。
#ii Info 编译通过,可以运行,但程序加载有明显延时。
#i3 Info 编译通过,按链接程序提示,添加了一系列系统库文件引用。但静态链接程序带调试文件巨大 30MB+,发行版则为可接受的2.38MB。
以上测试所得的数据可以为配置 Codeblocks 提供配置参考,最佳配置应该是 g++ 4.4.1 和 g++ 4.7.1的组合,稍后将进行编译器的配置。特别地,对于第二组数据,g++ 4.7.1 和 g++ 4.8.1 这两个编译器配置特别搭配了官方给的预备环境要求文件CodeBlocks Prerequisites 预备环境要求。这里罗列一下可能需要用到的系统库文件引用,注意GDI有两个库一个gdi32,另一个是gdiplus,需要使用图形编程时,两个都引用就好了:
而wx的库文件则有以下这些,其中 wxmswu 则为合集库文件:
注意,静态编译时,一定要去掉编译参数 WXUSINGDLL。对于 g++ 4.7.1 以上版本没有成功进行静态编译的现象十分怪异,因为原因基本都是同样的符号引用问题:_Unwind_Resume
、__gxx_personality_v0
。推断它和g++升级后引入的功能有关,通常符号引用问题是可以通过引入正确的库文件解决的,这里引用以下库文件后,并未能解决问题。反而单独引入libgcc_s
时,会出现重复定义_Unwind_SjLj_Register
问题,是乎不修改原始代码就永远解决的的死胡同,还是用可用的编译器吧。:
有些文章说可以通过设置编译器参数 “-static-libstdc++” 来实现静态编译wx程序,这是对这个选项的一种误解,libstd++ 指的是 C++ 标准库,所以它与 wxWidgets 程序开发的静态链接关系不大。再次,这个选项对于 TDM-GCC 4.8.1 来说已经是默认选项了,所以可以完全忽略它的存在,不能忽略它也没办法,因为所有 C++ 程序都是会使用到标准库的,如果确实相连标准库也静态链接也可以使用链接参数 -static。倒是在 g++ 4.4.1中这个选项并未生效,它会导入动态链接库 mingwm10.dll,只有去掉 -mthreads (Use Mingw-specific thread support)链接参数才可以解决这个导入库。注意,Invoking GCC指明g++.exe只是一个有点自动化编译工具,它需要调用gcc.exe、ar.exe等等命令来完成编译工作,前者可以编译和链接生成程序或动态链接库,后者可以生成静态库。例如-c参数表示只进行编译而不链接
stackoverflow 有关于这个编译错误的解答,出现这种错误是因为 GCC 支持两套异常处理机制,一套异常处理称作 Setjmp and longjmp (sjlj exception handling),另一套是基于 DWARF-2 调试信息格式的 (DW2 exception handling)。当程序同时引发两套异常机制时就会出现上面提到的符号重复定义等等问题,系统环境变量配置不恰当、编译工具混用等等也可能因为激活了两套机制的库文件而引起这个问题。
TDM-GCC Quirks 提到默认的异常处理机制 SJLJ 虽然因为添加额外的条件语句会导致程序运行减速,但它可以支持 MSVC 抛出的异常。而 DW2 则是通过建立一个与代码隔离的数据表实现异常机制,这会使得程序比使用 SJLJ 方式的大,而且在进入异常时程序会更慢。为此官方提供两种版本供下载,对于 DW2 版本,其中包含相关的文件名会用“-dw2”进行标记。
WxWindowsQuickRef 给出的解决办法只有一个:自己重新编译一次!因为发行版本编译时使用的编译器版本不一定兼容当前使用的,所以最好的解决办法就是用当前的编译器重新编译一次,虽然这很耗时。我是属于比较懒的一类,所以选择使用现有的搭配,因为重新编译确实在耗时也耗电,我这机子试过编译了半个工作日,当然是单线程下的编译。还是用以下这些的组合吧,省时省力:
TDM-GCC 4.4.1 + wxPack 2.8.7
TDM-GCC 4.6.2 + wxPack 2.8.12
TDM-GCC 4.7.1 + wxWidgets 3.0
另外,库文件夹下还有一个setup.h头文件,专门用在Win32平台下的,因此需要在编译器选项中添加上msw**
这个路径。这样,一个正常的静态编译工程配置文件看起来应该是这样的:
RAD 就是 Rapid Application Development 就是图形界面工具,一款好的可视化工具可以让你的效率成部提高。Codeblock 就集成了wxSmith这款高兼容度的RAD工具,wxWidgets也提供了一个工具列表。就已经测试过的工具而言,较好用的除了wxSmith外,还有wxFormBuilder,DialogBlocks。至于wxDev-C++则是Dev-C++的一个改版,由于其本身界面不完善,所以适用性较差。建议从简为主,使用集成的工具就足够了。
使用CB的全局变量来保存wx的目录会更方便配置wx工程,打开 settings -> global variables,在界面中 current variable 指定一个变量对象,可以为它设置从属一系列变量。CB已经定义了常用的如 lib、include等等。例如设置一套 wxWidgets 3.0 对应的变量,先克隆当前的变量设置,在提示框中输出新的变量名wx30,然后在lib、include中输入对应的目录,设置好现有的wx,在配置工程时,可以这样调用:
$(#wx30.lib)
对于 wxWidgets 2.8 也同法炮制,这样在新建工程时,只需要替换一下变量名就可以更新wx的版本选择。接下来要对编译器进行设置,首先到 TDM-GCC安装包 下载到 4.4.1 和 4.7.1 两个安装包并安装到两个对应的目录下。也可以去下载带 mingw 的 CodeBlocks 安装包,安装好两者后,打开 setting -> compiler 设置编译器。 将 GNU GCC Compiler 拷贝一份,改名为 GNU GCC 4.7.1,先将 Toolchain executables 的目录改为 TDM-GCC-4.7.1 的安装目录,工具名称设置不用改。再将 Linker settings 和 Search directories 两个选项卡内的目录全部改过来,再以同样操作建立 TDM-GCC-4.4.1 的配置,最好TDM-GCC-4.6.2这个版本也安装好,方便使用。做这些工作后,今后开发 wxWidgets 程序就方便了,动态链接静态链接随便选,在向导界面中选好配套的 wx和g++版本就可以了。
另外,wx所有发行包中的库文件都是含有版本号的,如果工程向导配不能自动配置库文件时,手动置起来好凄难搞。官方 Using wxWidgets (MSW) 3.0 给出的解决方法是设置工程的自定义变量,再在程的编译链接选项中搭配这个信息来对应各版本,这种做法十分费力。如下,WX_COMPILER 和 WX_COMPILER_VERSION 就是两个自定义变量。
$(#wx30.lib)\$(WX_COMPILER)$(WX_COMPILER_VERSION)_dll
我的做法是直接将库文件改名,将版本号部分去掉,为了保留版本信息,只需要在目录名上添加上wx版本号,然后通过全局变量来引用目录,这样配置不同的wx版本就只需要修改一个全局目录就好了。需要还原文件名反过来执行就可以了,这些工作使用脚本来完成是很方便的。
| 去版本号命名 | 回复原文件名 |
|:----------------------------------------------------|:--------------------------------------------------|
| ren libwxbase28.a libwxbase.a | ren libwxbase.a libwxbase28.a |
| ren libwxbase28d.a libwxbased.a | ren libwxbased.a libwxbase28d.a |
| ren libwxbase28d_net.a libwxbased_net.a | ren libwxbased_net.a libwxbase28d_net.a |
| ren libwxbase28d_odbc.a libwxbased_odbc.a | ren libwxbased_odbc.a libwxbase28d_odbc.a |
| ren libwxbase28d_xml.a libwxbased_xml.a | ren libwxbased_xml.a libwxbase28d_xml.a |
| ren libwxbase28u.a libwxbaseu.a | ren libwxbaseu.a libwxbase28u.a |
| ren libwxbase28ud.a libwxbaseud.a | ren libwxbaseud.a libwxbase28ud.a |
| ren libwxbase28ud_net.a libwxbaseud_net.a | ren libwxbaseud_net.a libwxbase28ud_net.a |
| ren libwxbase28ud_odbc.a libwxbaseud_odbc.a | ren libwxbaseud_odbc.a libwxbase28ud_odbc.a |
| ren libwxbase28ud_xml.a libwxbaseud_xml.a | ren libwxbaseud_xml.a libwxbase28ud_xml.a |
| ren libwxbase28u_net.a libwxbaseu_net.a | ren libwxbaseu_net.a libwxbase28u_net.a |
| ren libwxbase28u_odbc.a libwxbaseu_odbc.a | ren libwxbaseu_odbc.a libwxbase28u_odbc.a |
| ren libwxbase28u_xml.a libwxbaseu_xml.a | ren libwxbaseu_xml.a libwxbase28u_xml.a |
| ren libwxbase28_net.a libwxbase_net.a | ren libwxbase_net.a libwxbase28_net.a |
| ren libwxbase28_odbc.a libwxbase_odbc.a | ren libwxbase_odbc.a libwxbase28_odbc.a |
| ren libwxbase28_xml.a libwxbase_xml.a | ren libwxbase_xml.a libwxbase28_xml.a |
| ren libwxmsw28.a libwxmsw.a | ren libwxmsw.a libwxmsw28.a |
| ren libwxmsw28d.a libwxmswd.a | ren libwxmswd.a libwxmsw28d.a |
| ren libwxmsw28d_adv.a libwxmswd_adv.a | ren libwxmswd_adv.a libwxmsw28d_adv.a |
| ren libwxmsw28d_aui.a libwxmswd_aui.a | ren libwxmswd_aui.a libwxmsw28d_aui.a |
| ren libwxmsw28d_core.a libwxmswd_core.a | ren libwxmswd_core.a libwxmsw28d_core.a |
| ren libwxmsw28d_dbgrid.a libwxmswd_dbgrid.a | ren libwxmswd_dbgrid.a libwxmsw28d_dbgrid.a |
| ren libwxmsw28d_gl.a libwxmswd_gl.a | ren libwxmswd_gl.a libwxmsw28d_gl.a |
| ren libwxmsw28d_html.a libwxmswd_html.a | ren libwxmswd_html.a libwxmsw28d_html.a |
| ren libwxmsw28d_media.a libwxmswd_media.a | ren libwxmswd_media.a libwxmsw28d_media.a |
| ren libwxmsw28d_qa.a libwxmswd_qa.a | ren libwxmswd_qa.a libwxmsw28d_qa.a |
| ren libwxmsw28d_richtext.a libwxmswd_richtext.a | ren libwxmswd_richtext.a libwxmsw28d_richtext.a |
| ren libwxmsw28d_xrc.a libwxmswd_xrc.a | ren libwxmswd_xrc.a libwxmsw28d_xrc.a |
| ren libwxmsw28u.a libwxmswu.a | ren libwxmswu.a libwxmsw28u.a |
| ren libwxmsw28ud.a libwxmswud.a | ren libwxmswud.a libwxmsw28ud.a |
| ren libwxmsw28ud_adv.a libwxmswud_adv.a | ren libwxmswud_adv.a libwxmsw28ud_adv.a |
| ren libwxmsw28ud_aui.a libwxmswud_aui.a | ren libwxmswud_aui.a libwxmsw28ud_aui.a |
| ren libwxmsw28ud_core.a libwxmswud_core.a | ren libwxmswud_core.a libwxmsw28ud_core.a |
| ren libwxmsw28ud_dbgrid.a libwxmswud_dbgrid.a | ren libwxmswud_dbgrid.a libwxmsw28ud_dbgrid.a |
| ren libwxmsw28ud_gl.a libwxmswud_gl.a | ren libwxmswud_gl.a libwxmsw28ud_gl.a |
| ren libwxmsw28ud_html.a libwxmswud_html.a | ren libwxmswud_html.a libwxmsw28ud_html.a |
| ren libwxmsw28ud_media.a libwxmswud_media.a | ren libwxmswud_media.a libwxmsw28ud_media.a |
| ren libwxmsw28ud_qa.a libwxmswud_qa.a | ren libwxmswud_qa.a libwxmsw28ud_qa.a |
| ren libwxmsw28ud_richtext.a libwxmswud_richtext.a | ren libwxmswud_richtext.a libwxmsw28ud_richtext.a |
| ren libwxmsw28ud_xrc.a libwxmswud_xrc.a | ren libwxmswud_xrc.a libwxmsw28ud_xrc.a |
| ren libwxmsw28u_adv.a libwxmswu_adv.a | ren libwxmswu_adv.a libwxmsw28u_adv.a |
| ren libwxmsw28u_aui.a libwxmswu_aui.a | ren libwxmswu_aui.a libwxmsw28u_aui.a |
| ren libwxmsw28u_core.a libwxmswu_core.a | ren libwxmswu_core.a libwxmsw28u_core.a |
| ren libwxmsw28u_dbgrid.a libwxmswu_dbgrid.a | ren libwxmswu_dbgrid.a libwxmsw28u_dbgrid.a |
| ren libwxmsw28u_gl.a libwxmswu_gl.a | ren libwxmswu_gl.a libwxmsw28u_gl.a |
| ren libwxmsw28u_html.a libwxmswu_html.a | ren libwxmswu_html.a libwxmsw28u_html.a |
| ren libwxmsw28u_media.a libwxmswu_media.a | ren libwxmswu_media.a libwxmsw28u_media.a |
| ren libwxmsw28u_qa.a libwxmswu_qa.a | ren libwxmswu_qa.a libwxmsw28u_qa.a |
| ren libwxmsw28u_richtext.a libwxmswu_richtext.a | ren libwxmswu_richtext.a libwxmsw28u_richtext.a |
| ren libwxmsw28u_xrc.a libwxmswu_xrc.a | ren libwxmswu_xrc.a libwxmsw28u_xrc.a |
| ren libwxmsw28_adv.a libwxmsw_adv.a | ren libwxmsw_adv.a libwxmsw28_adv.a |
| ren libwxmsw28_aui.a libwxmsw_aui.a | ren libwxmsw_aui.a libwxmsw28_aui.a |
| ren libwxmsw28_core.a libwxmsw_core.a | ren libwxmsw_core.a libwxmsw28_core.a |
| ren libwxmsw28_dbgrid.a libwxmsw_dbgrid.a | ren libwxmsw_dbgrid.a libwxmsw28_dbgrid.a |
| ren libwxmsw28_gl.a libwxmsw_gl.a | ren libwxmsw_gl.a libwxmsw28_gl.a |
| ren libwxmsw28_html.a libwxmsw_html.a | ren libwxmsw_html.a libwxmsw28_html.a |
| ren libwxmsw28_media.a libwxmsw_media.a | ren libwxmsw_media.a libwxmsw28_media.a |
| ren libwxmsw28_qa.a libwxmsw_qa.a | ren libwxmsw_qa.a libwxmsw28_qa.a |
| ren libwxmsw28_richtext.a libwxmsw_richtext.a | ren libwxmsw_richtext.a libwxmsw28_richtext.a |
| ren libwxmsw28_xrc.a libwxmsw_xrc.a | ren libwxmsw_xrc.a libwxmsw28_xrc.a |