理论上,gsoap生成的代码是可以在各种编译器下编译的。但现实是我用gsoap生成的c++代码,在windows/mingw就没办法编译,在windows/vs2015下可以正常编译,在linux/gcc也能 正常编译,给人的感觉似乎是没有在mingw下做过基本测试(真的是这样吗???)。
简单的错误
仔细研究了编译错误,其实都很简单,都是没有正确判断win32下的编译器类型。
例如下面这段代码(version 2.8.33的stdsoap2.cpp line 12973, soap_string_in函数)
#ifdef WIN32
m = 0;
wctomb_s(&m, buf, sizeof(buf), (wchar_t)(c & 0x7FFFFFFF));
#else
m = wctomb(buf, (wchar_t)(c & 0x7FFFFFFF));
#endif
显然《wctomb》是标准c函数,而 带_s
后缀的[《wctomb_s》] 2是msvc扩展的安全增强版本的函数。
只用#ifdef WIN32
来判断,在msvc下编译是没问题,但用mingw编译时就报错了,因为mingw并没有实现wctomb_s
还好,gsoap的版本更新很快,当我更新到上个月(2016-08-17)发布的最新版本(2.8.34)时,发现上面这个问题被开发者修改了(version 2.8.33的stdsoap2.cpp line 12925, soap_string_in函数)
#if defined(WIN32) && !defined(CYGWIN) && !defined(__MINGW32__) && !defined(__MINGW64__)
m = 0;
wctomb_s(&m, buf, sizeof(buf), (wchar_t)(c & 0x7FFFFFFF));
#else
m = wctomb(buf, (wchar_t)(c & 0x7FFFFFFF));
#endif
虽然修改的不那么漂亮,但总算是改了。
简单的修改
但当我用新版本重新运行wsdl2h,soapcpp2 生成了c++代码,再次尝试mingw下编译时,又报错了,还是类似的问题。
这次问题出在stdsoap2.h(version 2.8.34 line 1299,2.8.34以前的版本都一样)
#ifdef WIN32
# ifndef HAVE_ISNAN
# define HAVE_ISNAN
# endif
# define soap_isnan(n) _isnan(n)
# ifndef HAVE_ISINF
# define HAVE_ISINF
# endif
# define soap_isinf(n) (!_finite(n))
#endif
于是我也依样画葫芦将这段代码修改如下,则编译通过
#if defined(WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
# ifndef HAVE_ISNAN
# define HAVE_ISNAN
# endif
# define soap_isnan(n) _isnan(n)
# ifndef HAVE_ISINF
# define HAVE_ISINF
# endif
# define soap_isinf(n) (!_finite(n))
#endif
事情就这样结束了么?
我总觉得gsoap不会对这么明显而且简单的问题在之前的那么多版本都解决不了,对于本文一开始我的推断:gsoap没有在mingw下做过基本测试,我总是有点心虚的。
联想到我的系统代码都用c++11标准写的所以我的项目cmake脚本(CMakeLists.txt)中默认对整个项目都增加了-std=c++11
选项。
#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
也就是说stdsoap2.cpp实际是在-std=c++11
选项下编译的。
会不会是因为这个-std=c++11
选项引起的问题呢?
于是我尝试删除-std=c++11
选项,恢复前面的所有修改,再编译,则编译通过。
现在问题搞明白了,上面的实验推翻我前面的一系列结论:
gsoap生成的c++代码在c++98标准下编译应该是没问题的,
但gsoap的开发者并没有用-std=c++11
选项在mingw下编译测试过,所以会有前面那些问题。
所以解决在gsoap stub代码和C++11代码一起在mingw下编译的问题有两个方案:
方案1.修改自己CMakeLists.txt,将gsoap生成的C++代码与自己的项目c++11代码区分开,不用-std=c++11
选项编译gsoap代码,这样就可以避免修改gsoap代码(stdsoap2.h/stdsoap2.cpp)。
方案2.与方案1相反,就像前面的办法一样修改stdsoap2.h/stdsoap2.cpp以解决编译问题.这样可以不用修改自己的CMakeLists.txt,将gsoap生成的c++代码与自己的C++11代码混在一起编译。
选项哪个方案都可以取决哪个方案成本最低,
但我准备选择项方案1—原因是不到万不得已我不会修改第三方代码,这样会增加未来的维护成本 。
不过以现在gsoap每月发布一个版本的更新速度,下一个版本应该就能完美解决mingw下对-std=c++11
选项的支持问题了。