wxJson 介绍
wxJson 是 专门为 wxWidgets 这个C++ 跨平台框架量身定做的 JSON 类库, 这个库本身很小,支持JSON读写操作,总共7个源文件,2009年 就已经开发好了,目前不再更新。不过官方依旧可以看到详细的开发文档,整整10年过去了,在这个新技术层出不穷的年代,这么老的古董依旧散发着余热. 下面 挖坑(金子) 的故事稍稍有点长,请大家耐住性子,备好茶,枸杞泡起来. (加班熬夜的你是不是身体已经垮了…?)
1. 无法编译 wxJson 为 DLL库
从官网下载最新 wxJson安装包,解压后打开 Visual Studio 自带的命令行工具(我的机器上是 x64 Native Tools Command Prompt for VS 2017
),你们的环境可能和我不一样,因为我要编译 64位 的wxJson。请注意,使用系统自带的命令行是不行的,不能正常编译。 进入解压后的 build 子目录,使用最新64位版 mingw32-make(版本4.2.1) , 运行语句 mingw32-make makefile.gcc
, 会出现下面的错误提示, 本人试过调整 makefile.gcc 文件里面的编译参数,依旧无果.
/usr/bin/sh: wx-config: command not found
/usr/bin/sh: wx-config: command not found
/usr/bin/sh: wx-config: command not found
process_begin: CreateProcess(NULL, wx-config --static=no --toolkit= --version=., ...) failed.
make (e=2): ϵͳ�Ҳ���ָ�����ļ���
mingw32-make: *** [GNUmakefile:206: test_for_selected_wxbuild] Error 2
这个错误提示无法提供有用的线索,然后在安装包根目录下我发现一个叫 INSTALL.txt 的文件,里面是wxJson的编译说明。看了半天(下面是英文原话),作者想告诉我们,wxJson 源代码其实不复杂,cpp文件就3个,直接拷贝文件到自己的项目中编译也是不错的选择,这样一来,不用操心 makefile 文件各种跨平台编译配置,也没有单独编译wxJson ANSI/UNICODE,DEBUG/RELEASSE
各种版本的麻烦,何乐而不为呢?.
The library itself is only 150 KB in release mode and 460 KB in debug
mode so it is more simple to just include it in your own sources and
let the compiler of your application to compile the library itself.
You just have to copy the three source files located in the ‘src/’
subfolder in your own source folder and the four header files
located in the ‘include/’ subfolder in your own header folder.
Be sure to preserve the ‘wx/’ folder under the ‘include/’.
Next add the three source ‘.cpp’ files to your project and you are done.
This way, your application does not depend on wxJSON because it is
embedded in your app and you do not need to deal with ‘makefiles’,
‘bakefiles’, ‘configs’ and so on.
2. 拷贝wxJson源文件到工程目录
因为wxJson 库本身文件目录结构的原因, 把四个头文件都放在 include/wx
子目录下,我拷贝到自己项目中后,直接将源代码和头文件放在一个目录里,这样就需要调整一下cpp源代码文件包含的头文件路径,这个非常简单,比如 将 #include <wx/jsonreader.h>
修改为 "#include jsonreader.h"
;然后按照官方的例子,在项目中依葫芦画瓢。再次编译,出现下面这种错误提示。
D:\work_c++\sniper\lib\wxJSON\jsonwriter.cpp|891|warning: 'int wxJSONWriter::WriteNullValue(wxOutputStream&)' redeclared without dllimport attribute after being referenced with dll linkage|
D:\work_c++\sniper\lib\spider.cpp|44|undefined reference to `__imp__ZN12wxJSONReaderC1Eii'|
一看是 dllimport 这个鬼东西搞得鬼,于是打开 json_defs.h
看到下面的宏定义
#ifdef WXMAKINGDLL_JSON
#define WXDLLIMPEXP_JSON WXEXPORT
#define WXDLLIMPEXP_DATA_JSON(type) WXEXPORT type
#elif defined(WXUSINGDLL)
#define WXDLLIMPEXP_JSON WXIMPORT
#define WXDLLIMPEXP_DATA_JSON(type) WXIMPORT type
#else // not making nor using DLL
#define WXDLLIMPEXP_JSON
#define WXDLLIMPEXP_DATA_JSON(type) type
#endif
因为我项目中定义了 WXUSINGDLL
这个宏,所以上面这一段 if 宏定义块只有这段代码工作:
#define WXDLLIMPEXP_JSON WXIMPORT
#define WXDLLIMPEXP_DATA_JSON(type) WXIMPORT type
于是我机智的将 #elif defined(WXUSINGDLL)
注释掉 ,于是上面的宏就执行 #else
块了,变成
#define WXDLLIMPEXP_JSON
#define WXDLLIMPEXP_DATA_JSON(type) type
继续编译,这个时候调用代码直接蹦了. ?
3. 函数传参类型错误
天呐撸!不给人活路, 苦逼的我含着泪 单击Stop 按钮
停止了调试。这个时候,调试器打开了strvararg.h
, 定位到下面这个函数。卧槽,完全懵逼!仔细一看,这个文件是wxWidgets-3.1.2
库包含的文件,我开始有点凌乱了.
// normalizer for passing arguments to functions working with wchar_t* (and
// until ANSI build is removed, char* in ANSI build as well - FIXME-UTF8)
// string representation
#if !wxUSE_UTF8_LOCALE_ONLY
template<typename T>
struct wxArgNormalizerWchar : public wxArgNormalizer<T>
{
wxArgNormalizerWchar(T value,
const wxFormatString *fmt, unsigned index)
: wxArgNormalizer<T>(value, fmt, index) {}
};
#endif // !wxUSE_UTF8_LOCALE_ONLY
思索半天也不知道原因,初步估计应该是wxJson调用wxWidgets的函数出现问题。无奈之下,我放了个大招,开始在wxJson源文件下断点,从调用的入口开始,密密麻麻放了一堆红点点。单步开始运行,一路追踪,半个小时过去了,有了重大发现。在 jsonval.cpp
源文件 第 1818
行, 代码运行崩溃了. 就是下面这个函数第二条 wxLogTrace
. 打印语句报错了.
//! Return the item at the specified key.
/*!
The function returns a reference to the object in the map
that has the specified key.
If \c key does not exist, a new NULL value is created with
the provided key and a reference to it is returned.
If this object does not contain a map, the old value is
replaced by a map object.
*/
wxJSONValue&
wxJSONValue::Item( const wxString& key )
{
wxLogTrace( traceMask, _T("(%s) searched key=\'%s\'"), __PRETTY_FUNCTION__, key.c_str());
wxLogTrace( traceMask, _T("(%s) actual object: %s"), __PRETTY_FUNCTION__, GetInfo().c_str());
//上面这条语句是报错的源头,需要注释掉。
wxJSONRefData* data = COW();
wxJSON_ASSERT( data );
if ( data->m_type != wxJSONTYPE_OBJECT ) {
// deletes the contained value;
data = SetType( wxJSONTYPE_OBJECT );
return data->m_valMap[key];
}
wxLogTrace( traceMask, _T("(%s) searching key \'%s' in the actual object"),
__PRETTY_FUNCTION__, key.c_str() );
return data->m_valMap[key];
}
wxLogTrace
是 wxWidgets
自带的函数,我尝试注释掉这一句 wxLogTrace( traceMask, _T("(%s) actual object: %s"), __PRETTY_FUNCTION__, GetInfo().c_str())
,重新编译运行, 程序正常了!?
好奇的你一定想知道,为啥第二条 wxLogTrace
崩溃了呢? 具体原因我也不清楚,不过以我多年的经验来看,wxLogTrace
的调用失败应该是 wxWidgets 升级的缘故。新版 wxWidgets 已经不支持 wxJson
那种方式调用 wxLogTrace
了,毕竟 wxJson 已经十年不更新了,而 wxWidgets 还在缓慢升级维护中。 wxJson 源码我大概看了个遍,注释掉上面那条打印语句,完全不会影响 wxJson 的功能,大家可以放心去试。 如果在尝试的过程中,你们有新的发现,请在评论区留言。