由于历史的原因,项目一直在使用vs2005进行开发,据说其他老一点的游戏项目很多也用05的,包括WOW,大概是因为05年正好是端游最火爆时期吧,但是都过去10年了,是时候拥抱一下新的东西了:D。
最近不是很忙,就把之前一直想做的这件事情做了,花了两周的时间,算是基本升级完成了,升级的过程中遇到各种问题,还是挺有意思的。
准备
说起来惭愧,工作两年多还没有系统的了解过项目的工程结构,趁这个机会也可以系统的了解下。
结果着实吓了一跳,单是solution就有5个,project大大小小有上百个。当然了,实际用到的没有这么多 ,有部分的是以前用的工具或者已经废弃的功能。
由于我们平时开发都是在window上进行的,包括server也是自己编译用来单服测试,所以就存在一套linux编译的工具链,这部分成了升级的头疼问题。
大概了解了一下vs2013的工程构建体系,在vs2010之后微软大改了一次构建体系,使用MSBuild系统来构建vs项目,和之前的差别还是挺大的。
比如05的工程后缀名是vcproj,而13的是vcxpro。之后比较了一下同样一个工程下这两种格式,发现后者比前者精简不少,确实进步了。
还有不得不说下MSDN的资料越来越周全了,包括vs2013工程的各种参数解释都有,还有常见的warming和error的解决方法。
开始之前整理了一下几个目标点:
- 保持原来的工程结构,也就是满足同时用05和13进行开发
- 尽量少的代码改动,防止出现bug
- 梳理工程间关联
- 修改版本发布工具(未完成)
开始
首先先复制一份sln,改名字,用13打开,再自动让它自动转换一下。
既然是自动转换,肯定是会有问题的,建议工程比较多的时候不要转换后就直接编译solution,而是从耦合度较小的工程开始一个个编译。
而且是每个工程都要过一遍,因为vs的自动转换非常不靠谱!
< 顺序可能是:Local lib —-> 3rd lib —-> local dll —-> local exe。local表示自己编写的工程。
我们的client相对server来说,引用的lib比较多,那就先从client开始吧,难的骨头先啃掉。而client不仅仅就是一个exe,还包括各种dll,大概数了一下相关工程有30+,杯具的是我开始做的时候没想到要上InCrediBuild,导致花在编译上的时间就很多了(哭)。建议有条件的还是早早上InCrediBuild吧,能节省不少时间,13的编译速度相对05来说还是慢了一点的。
在这里挑出几个值得注意的点说一下:
兼容xp及以上的系统。
开始我并没有注意到这个严重的问题,后来在xp上测试的时候才发现之前一直没考虑到,所以走了一点弯路了。
解决方式已有很多现成的了,知乎这个回答得比较全 http://www.zhihu.com/question/25415940
可能你会遇到下面这些问题:
warning C4005: '__useHeader' : macro redefinition
C/C++ -> Preprocessor-> add -> _USING_V110_SDK71_;
warning MSB8030: The linker switch "Minimum Required Version" requires "SubSystem" to be set
Linker -> System -> Minimum Required Version -> 5.01;
Linker -> System -> SubSystem -> windows(or concole 要看你的工程性质)
还有其他的就不一一列举了,大部分都可以通过google解决,千万不要用baidu。
这里最有用的技巧是善用Preprocessor(预编译宏)。在工程里设置好之后就不用在代码里面写死了,方便管理。
重新编译第三方库
其实local lib的问题还好解决,但是一些3rd lib就有点麻烦了。因为升级得首先保证稳定性,不能随意升级,比如:
boost: Unknown compiler version - please run the configure tests and report the results
在include\boost\config\compiler\visualc.hpp这个文件可以看到条信息是怎么产生的,
还是由于我们使用的boost库版本太老了。
只好去取了一下最新的boost库的这个文件来修改,支持vs2013的编译就好了。
还有Protobuf,需要重新编译出lib,另外还得区分13和05编译的版本,分别连接。
还有一个常见的warming:
warning MSB8012: TargetPath xxx does not match the Library's OutputFile property value xxx
原因是General的Output Directory 和 Link 的 OutPut File 输出文件路径不一致。
推荐在ganeral的Output Directory 写上你想要输出的路径,
然后在Link的OutPutFile 填上$(OutDir)$(TargetName)$(TargetExt),如果需要改变也只需要改一处。
历尽千辛万苦终于搞好了client的编译,自己测试一下暂时没发现啥问题,但是还是得经过严密的测试才能发布出去,比如跨平台可能出现的问题。
对了,关于MFC库缺失的问题,我们并不是全部连接静态库的做法,而是把需要的库文件打包在游戏安装包里,数M的dll库相对数G的客户端来说,不算什么的。
接下来是server。
server关联的工程并不多,而且大部分坑在编译client的时候已经遇到过,所以整个编译过程还算顺利,但是测试的时候发现登录的时候会宕机。
调试了一下,发现是一个比较隐晦的STL的问题,直接上测试代码吧:
#include <stdio.h>
#include <vector>
typedef std::vector<int> TEST_V;
class TEST_C
{
public:
TEST_V t_v;
const TEST_V& GetVR() const { return t_v; };
};
int main()
{
TEST_C c;
memset(&c, 0, sizeof(c)); // vector不能被memset!
const TEST_V& ref = c.GetVR();
for (TEST_V::const_iterator it = ref.begin(); it != ref.end(); ++it){}
system("pause");
return 0;
}
跟进去发现_Myproxy为NULL,说明vector的结构已经被破坏了:
const _Container_base12 *_Getcont() const
{ // get owning container
return (_Myproxy == 0 ? 0 : _Myproxy->_Mycont);
}
#if _ITERATOR_DEBUG_LEVEL == 2
void _Compat(const _Myiter& _Right) const
{ // test for compatible iterator pair
if (this->_Getcont() == 0
|| this->_Getcont() != _Right._Getcont())
{ // report error
_DEBUG_ERROR("vector iterators incompatible");
_SCL_SECURE_INVALID_ARGUMENT;
}
}
#elif _ITERATOR_DEBUG_LEVEL == 1
void _Compat(const _Myiter& _Right) const
{ // test for compatible iterator pair
_SCL_SECURE_VALIDATE(this->_Getcont() != 0);
_SCL_SECURE_VALIDATE_RANGE(this->_Getcont() == _Right._Getcont());
}
#else /* _ITERATOR_DEBUG_LEVEL == 0 */
void _Compat(const _Myiter&) const
{ // test for compatible iterator pair
}
#endif /* _ITERATOR_DEBUG_LEVEL */
更为隐蔽的是,release版本不会有这个异常。而在vs2005上,不管debug,release都不会有异常(因为版本不一致)。
这样的写法肯定是存在问题的,还好这次发现了,也可以改下。
最后
最终的结果是,改动了7处代码,每个solution和proj都有对应的2013的版本,只需要把新加的这部分入库管理就好了。之后想用13开发的同事打开xx2013.sln,还继续想用05的打开原来的sln。
但是有一个不好的地方在于,新加文件或者工程会比较麻烦,得两种solution都要加上。
未解决的问题:
还需要修改我们的版本发布工具链,因为我们要发布出去的程序都有一套编译机来进行编译,现在只能说能让我们开发的时候用到。还不能发布给用户使用。不过呢,这个过程还需慢慢推进,为了稳(mei)定(you)性(bug)。
client只需要在对应的编译机上安装vs2013,然后改一下编译工具应该就好了的。而真正难搞的问题是linux的编译。我们的linux编译工具是根据自己写的一套根据vcproj文件生成的规则的文件生成的。由于05到13的工程文件变化比较大,修改这部分又是一个体力活了。索性就还是不改,只要保留着原来的05的proj,linux的编译就不会有问题。
stack overflow和msdn在这次过程中帮了大忙,很多琐碎的问题都在上面有了解答。
最最后,想说一下自己上面写的东西好啰嗦呵呵呵。文字表达能力越来越退化了。所以得坚持写blog下去!