为了给自己写的C++ GUI库做宣传,在几个月前我决定要给他做一个网站,经历了这几个月不断的重构,现在网站的架构终于定型了。考虑到在这之前我几乎没有开发网站的经验,所以在这里做点小总结来介绍自己一路走来发生的事情。
一开始为了制作这个网站购买了万网的域名和一个很便宜的一年500块钱的空间。这个空间支持低版本的asp.net,不过当时还没学会这方面的东西。后来我就开始学习HTML和CSS,然后做出了几个页面。不同的浏览器有不同的bug,导致HTML和CSS搞起来相当复杂,特别是div和float的结合,更是焦头烂额。后来索性整个网页都用表格布局。虽然表格布局并不是什么流行的做法,但是鉴于GacUI的网站并没有多么复杂的内容,因此最后这么做,避开了很多跨浏览器的问题。当然以后如果网页内容变得太复杂的话总是要改回div的吧。对于常年写图形和编译器方面的我来说,刚开始深入接触HTM和CSS的时候就对他的杂乱无章所震惊。使用programming language领域的经验和标准来看,HTML、CSS和Javascript作为编程的工具实在是烂到不能再烂了。不过事物的存在总是有其合理性的,纵观这三样东西的发展和历史,我们会发现其过程充满了各种巧合,而且当初这些东西在发明的时候就仅仅是为了解决一些简单的问题。如今流行了,就跟COBOL、Java和C语言一样,全世界的程序员都只能接受其不可忽视的弱点而就这么开发下去了。
在熟悉了简单的HTML和CSS之后,我就开始给GacUI做网站了。这个网站的主要目的就是用来介绍GacUI的特点、展示一些Demo、告诉人们如何下载并使用,最后就是提供一个在线文档。文档就跟MSDN一样,当然搜索功能还不存在。刚开始就遇到了美工问题。技能书都点在了系统软件上,自己的美工自然是连自己都不能满足的。后来找了几个例子,看来看去觉得还是
http://www.codeplex.com最顺眼。但是它的代码复杂到吐血,我便只好依样画葫芦,自己慢慢复刻。最后复刻的结果还是令我比较满意的。在做完了导航条之后,我就发现了一个问题。如果不使用如今的框架来做网页,而采用手写的方法来生成HTML文件的话,势必是无法DIY的。不过那个时候还没有意识到这个问题的严重性,于是就采用了简单粗暴的复制代码的方法来做好那五个页面。这也为我之后转向Windows Azure埋下了伏笔。
之后做Demo的展示页面比较顺利。因为目前展示Demo的方法就是先贴效果图,然后贴C++代码,十分的简单粗暴。于是立刻就遇到了一个新的障碍,要如何写一个类似MSDN的HTML文档。其实这件事情跟做网站本身是没什么关系的,但是自从决定了要提供在线文档之后,这个问题也就无法避免了。C++生成文档地方法之前略有研究,毕竟关于这个功能的一个简单的原型就是我跟几个朋友在大一的时候参加学校的软件竞赛的作品。后来还考虑过诸如Doxygen这样的工具。但是由于Doxygen生成的文档很难调整风格,使其整体融入我的网站的样式里,因此最终就放弃了。然后我便想起了Visual Studio的XML注释功能。在略为研究之后,我便给我的整个GacUI的类库的public class编写了XML注释。当我最终要执行生成文档的这一步的时候,我才发现所有的工具都不支持原生C++程序和XML注释的文档生成功能。不过想来其实也有道理。Visual Studio在编译了XML注释之后提供的一个xml文件只包含符号和注释的对应关系。至于符号究竟是什么内容,则完全没有。因此.net的程序是怎么生成文档的呢?自然是利用反射了。C++的苦逼就在这里啊,除了直接写代码,就没有任何方法。但是写了这么多的XML文档要放弃实在是太可惜了,所以我就不断的找呀找,然后发现Visual Studio在安装的时候提供了一个叫做DIA的库,可以让我阅读pdb文件!
这让我欣喜若狂啊。既然Visual C++的调试器可以通过阅读pdb就得到了一切的信息(看那个完美的调试器界面就知道了!),那我自然也可以从pdb里面找到所有东西的。抱着这个想法,我开始研究原生C++的pdb文件的符号的语义结构,后来就把我的经验写成了这两篇博客:
http://www.cppblog.com/vczh/archive/2012/03/10/167538.html和
http://www.cppblog.com/vczh/archive/2012/03/10/167539.html。虽然PDB并没有包含模板类的直接信息,不过这暂时不成问题,因为GacUI的大部分类也不是模板类。经过了这些研究,我就得到了一个相当于静态反射的功能了。之所以说是静态,是因为我没办法跟.net程序一样通过反射来调用函数。但是这对于生成文档来说已经足够了。后来我做了一件事情,就是写了个程序,读pdb获得所有的符号dump出一份xml,然后再写一个程序把xml里面的符号和Visual Studio产生的那个XML总注释文件的符号联系起来(这个过程有点复杂,因为两边的表示方法不一样……),得到了一份既包含符号的完整内容又包含对应的注释的这么个几十M的XML文件。之后我设计了一个简单的文档格式,写了个程序把那个几十M的XML文件转换成用那个简单的文档格式表达的文档。之所以这样做是考虑到将来说不定除了HTML还要生成其他格式的文档,于是就做了那么个程序可读的中间格式。最后一步当然是读这些文件产生HTML文件了。整个流程如下所示:
PDB(VC++编译器提供) -> Symbols.XML (因为DIA是一个COM组件,所以这一步我用C++写,下面所有的步骤都用C#写。C#用起来还是更容易啊……)
Symbols.XML + Comment.XML(VC++编译器提供) -> FullSymbols.XML
FullSymbols.XML -> *.docitem.txt
*.docitem.txt -> *.html
经过了这些步骤,我就得到了整整一个文件夹的一千五百多个HTML文件了。然后我把这些文件跟我的网站合并在一起上传,就得到了第一个版本的GacUI网站了:
http://www.gaclib.net。当然现在已经看不到第一个版本的网站了。做完这些步骤之后,我就暂停了下来,继续开发GacUI。一边开发一边产生Demo,添加Demo页面,产生新的文档,消灭一些没用的函数的文档。写代码的时候还比较容易,再把代码的更改反映到这个网站的时候,就体现出了手写纯静态网站的弱点:维护起来真TMD麻烦啊!虽然上面的这些步骤已经被我合并到了一个bat文件,每次双击就能自动完成,但是修改Demo页面的时候还是人肉的。这让我十分不爽。
一个偶然的机会,我用了信用卡注册了一个Windows Azure的空间。这个空间其实并不powerful,只给了我相当于六颗CPU的计算能力。不过用来做这个网站已经足够了。想到每次修改网站都要复制HTML代码,修改了结构的话还要动所有的HTML文件,烦了大概一个月之后我就下定决心要把HTML做成动态生成的。在看了Windows Azure的一些介绍之后,我觉得ASP.NET MVC3加上Windows Azure的简单存储功能十分适合用来作这种东西。
刚开始接触MVC3还是让我觉得比较困难,不过最大的困难还是在于理解router的机制那里。GacUI的网站内容简单,所以并不需要ASP.NET的其他高级技术。结果所有的困难都出现在router机制里面。在经过了两天的学习之后,我初步的掌握了它的使用方法。MVC3的router基本上就是一个pattern matching的过程,把你的url映射到一个对controller的调用上面。你不仅可以映射controller的类名和函数名,还可以从url抽取一些参数。在掌握了它的原理之后,操作router的感觉就跟写haskell一样,又直接又清爽。接下来就是razor模板的事情。从programming language的观点上看,razor是一个设计的相当出色地模板语言。第一个特点就是和宿主语言C#融合的十分紧密,第二个特点就是几乎一点语法噪音都没有。用过原始asp和php的人都知道代码里面充满了<%%>是一件十分令人讨厌的事情。每一处代码和HTML的切换都要<%%>,整个文件一眼望去就是一坨屎。razor很好地解决了这个问题。他采用了复杂的判断方法来分辨哪些东西是C#,哪些东西是HTML。小部分C#和HTML的切换至需要一个@符号就搞定了,大部分的切换都是自动的。虽然偶尔razor会有分析错误的情况,但是他仍然提供了@:操作符来让我们workaround这个分析过程。整个模板语言下来毫无语法噪音,写起来十分直接,十分干净。
在网站差不多做完之后,我往生成HTML文档的程序添加了一个功能:生成一个包含HTML文档内容和元数据的XML。然后我写了一个程序把这一大堆XML灌入了Windows Azure的Blob Storage里面。Blob Storage就跟一个硬盘一样,可以用来存放大量的不需要计算(SQL数据库就属于那种需要计算的)数据。然后我给每一个文档页面建立了一个统一的Model,Model里面包含了“读取和分析这些XML文件”的功能,controller则做一个简单的转发,最后在model里面把所有被Model标记出来的需要改写的URL都用@Url.Action来处理。在这个过程中我学到了一个razor的小技巧:虽然不是很安全,但是在razor里面使用MvcHtmlString可以绕过html encoding的功能,把存储在变量里面的HTML代码直接嵌进页面。这么用的时候需要有清醒的意识。
如今GacUI终于有了镜像网站:
http://asia.gaclib.net和
http://us.gaclib.net了。万网的破烂空间自然不可能直接访问Windows Azure Storage了。所以我采用了一个看起来比较傻逼的方法。首先我修改好网站之后,上传到EastAsia和West US两个服务器,然后我写了一个程序再把每一个生成好的HTML页面下载下来。下载的过程其实就和写爬虫差不多,每获得一个新的HTML文件就去分析里面的链接,然后继续下载。写完了之后我发现这个小程序还有了发现死链的功能,直接找出了网站代码的几个bug。下载完之后FTP到万网的空间里面。这个服务器在杭州。因此网站就有三个服务器了。
整个过程零零碎碎耗费了大约半年的时间,都是利用每天下班后的时间完成的。自己又点了技能树的一个新子树,涨了点经验值,觉得这些经验对于某些人来说可能还有参考的价值,于是就写了这篇博客,大家共勉。
posted on 2012-07-09 10:27
陈梓瀚(vczh) 阅读(4679)
评论(9) 编辑 收藏 引用 所属分类:
其他 、
GacUI