吴's profile囧尼的编程时间 (Johnny's Progra...PhotosBlogLists Tools Help

吴 杰

Occupation
Location
Interests
I'm a game-developer working in ubisoft.
Photo 1 of 2

囧尼的编程时间 (Johnny's Programming Hour)

a geek, a programmer, a gamer...
May 31

exVim 7.05 正式发布

几个礼拜下来,沉浸在收Mail,修Bug, 发Mail的快乐之中,收到了不少诸如 great work, nice tool, wonderful 之类的反馈,顿时感觉生活充实了许多。1个月的努力下来,终于搞了这个 exVim 7.05 版, 希望能够最大限度的除去此前的多种问题,更进一步地降低vim 的使用门槛。

你可以在这里下载到 exVim 的win32 安装包:
http://exvim.googlecode.com/files/exVim-installer-7.05.exe

希望使用过并且喜欢的朋友们能够到:
http://www.vim.org/scripts/script.php?script_id=2627 投上你宝贵的一票.

一个月下来,公司的事,exVim的事,自己的私事已经让我精疲力竭了。只是这周遭人事的变化,多少也让人有所叹息和失落,就不多说了。囧尼也开始盘算着是否要来次出游计划,不过这时间也由不得我来做主,只能听天由命了。

话说最近台球瘾严重,这每个礼拜不来上几局总觉得不爽,只不过这技术有限,斯诺克不是别人对手,只能耍耍美式,虐虐公司的某GD,偶尔打完后,喝上瓶黑啤,扯扯嘴皮子,还算能享受点生活的滋味,只不过到家后,又只能屁颠屁颠地打开电脑,收发mail,抓几只臭虫,然后呼呼睡上一觉。唯一让我觉得欣慰的是,最近酒后写代码的功力有所提升,怎么说咱也是练过的啊。

上周闲着无聊,到电影院看了把星际迷航,这Heroes的塞拉演的史巴克还真有那么回事,怎么说这片不在电影院里看还真是有点亏待了自己,光这声效和场面就够你值回票价。只是这买票的队伍排的还真是有点儿长,足足耗了我45分钟才把这票给买到。这不要紧,我想这一大帮子人来都是星际迷航fans的,还激动地用双眼向他们表达我们都是星航fan的情感。没想到前面一老头拿着喇叭喊了会:“注意,高考1997已经卖完,请要看的人们预购明天的票!” 顿时间队伍空荡了许多,耳边还传来一对母子的对话:“不如就看这个什么星际迷航的吧”, “不是,我不是说了吗我要看金刚狼!”.... T_T 哎,看来是我小众了。



May 03

exVim Release!

很久没来更新了,原因其实很简单,我觉得space上写东西不是很习惯,但又没有租用到比较好的个人服务器空间。姑且就还是现在这里放着吧,等到ex系列的产品都步入正轨了,到时再加挂一个blog页面,只是这步入正轨的时间往往都超乎我的想象。比如一眨眼,我开发ex系列的基础套件之一的exVim就用了近3年了,这当初仅仅是一个按3个月工作量估计的idea,连我自己也没想到会越搞越大搞到现在这样一个完整的代码编辑套件。虽说我本无推广之意,但是看到公司里已有不少同事陆续使用,并且好评不断,让我脑子抽筋有了把它推广到社区中的想法。于是就在最近花了几个月时间在google上搞了这个project:

http://code.google.com/p/exvim/

虽然还只是建设初期,也还是希望仍然关注这个空间的同学们过去拜访试用(当然这使用门槛稍微高了些)。我也终于能够兑现我对上个项目从法国过来的两个程序员的陈诺: "Right now, I don't have any document for the package, but I'll write one later...." 这一later可就是1年多啊,不知道他们带着我的拷贝欣喜地回去然后泪目的等待了几周后是不是就此放弃。无论如何,我总算是对这件事情有了个比较满意的答复。

比起exVim,自去年在游戏业界内刮起的indie game风潮让人们看到了独立游戏制作人的希望,这其中不乏优秀作品,而且也有不少业界奇闻。比如那个咖啡厅里完成的world of Goo,再比如那个古怪程序员的作品Braid,我甚至都有了想为其专门写一篇review的冲动。当然时间仍然是我现在最缺少的东西。

希望exVim能够如愿在社区中普及起来。小透露一下下一个产品是exProfile...



April 06

Using gcc to check syntax error in template.

我不知道大家有没有用过gcc 3.14版本后的gch pre-compile header. 其实和msvc的pch概念上是很相似的,这类预编译技术总是会做一些cpp的语法检测,来及早的发现代码编写中的错误.但是相比msvc只做普通class的编译,gcc更加入了template的预编译检测,这使得我们可以通过gch对我们编写的template做一个初级的语法解析和验证,很多vc中需要template instance后才会发现的语法问题,在这里可以得到轻松解决.我们再也不会遇到在msvc下编译通过仍然忧心匆匆,而不得不再一个test cpp代码中instance一个template来验证的困窘情况了(你可是要验证所有的member function,否则msvc只会check你调用的function的语法). 这对于库工作者和发布者无疑是一个很好的工具. 废话不多说,我就说说我的使用方法和新得.
 
编译生成gch方法很简单,你只需要在你的makefile中指定好要编译的header file,输出为与其同一目录下的gch文件即可,for example:
假设我们的目录结构为,gcc 操作目录为Solution
Solution
  |- Base
      |- base.h
      |- base.cpp
  |- Engine
      |- engine.h
      |- engine.cpp
 
我们需要编译base.h 为gch,写
c:\Solution:>  gcc -c ./Base/base.h -o./Base/base.h.gch
好了, 你不用特别指定gch,所有该目录下的cpp都会先找是否有gch文件存在,如果存在就会去include这个编译好的东西.
 
ok,介绍一下我的做法,由于跨平台工作的关系,每个平台都需要有自己的gch/pch file, msvc上可以通过指定pch来回避这个问题,但是gcc的gch文件必须要在和其原文件一致的目录下(我知道-I可以解决,但是那样太丑...), gcc提供的解决方案是:
把base.h.gch做成目录,然后在目录里放入你compile好的gch文件,而文件和文件数目并不受限制,gcc在compile到include base.h的cpp文件时,会把目录中的文件都搜索一遍找出第一个符合条件的文件(refer to: gcc manual-3.20 Using Precompiled Header - section 7 ), 所以我们就可以将上诉代码写成:
c:\Solution:>  gcc -c ./Base/base.h -o./Base/base.h.gch/base_win32_debug.h.gch (当然之前要把base.h.gch folder create出来) 我的makefile 写法如下:
 
# ----------------------------------------------------------------
 
Platform = PS3
Configuration = Debug
FullPath_GchSrcs += ./QuickTest.h
GchDir := $(addsuffix .gch,$(FullPath_GchSrcs))
FullPath_Gchs := $(addsuffix _$(Platform)_$(Configuration).h.gch,$(addprefix $(GchDir)/,$(basename $(notdir $(FullPath_GchSrcs)))))
 
# Debug Flag ( choose debug or not )
# Optimization Flag ( -O0:disable -O/-O1:general opt -O2:advance opt -O3:all opt )
ifeq ($(Configuration),Debug)
Flag_Debug := -g
Flag_Opt := -O0
else
Flag_Debug :=
Flag_Opt := -O1
endif
CFlags := $(Flag_Debug) $(Flag_Opt) $(Flag_PreDef) $(Flag_Inc) $(Flag_BuiltIn_Functions) $(CFlag_Spec)
 
# flag_inc, flag_predef, flag_builtin_functions, cflag_spec 的飞机自己搞
.PHONY: gchs clean-gchs
gchs: $(FullPath_Gchs)
$(FullPath_Gchs):
     $(MKDIR) $(ErrDir)
     $(MKDIR) $(GchDir)
     $(ECHO) compiling $(basename $@)...
     $(ECHO) - > $(ErrDir)/$(ErrLogName)
     $(ECHO) --[$(Project)]$(patsubst %/,%,$(notdir $@))-- >> $(ErrDir)/$(ErrLogName)
     $(CC) -c $(CFlags) $(basename $(GchDir)) -o $@ 2>>$(ErrDir)/$(ErrLogName)
     $(CAT) $(ErrDir)/$(ErrLogName) >> $(ErrDir)/$(Project).err
# ----------------------------------------------------------------
 
说了那么多但其实下面才是重点. 虽然说gch可以pre-check template 的 syntax, 但是这也带来了一些不必要的麻烦,比如说我们习惯性地在template 中写一些inline define, 而这些define往往会调用一些其他类或class, 在vc中由于template 编译放在template instance后, 一些因为头文件放置关系不严谨的define 和 declaration的问题不会很容易出现, 但是这种形式的放置在gch编译中就会出现错误.举个例子
 
在 test_tmpl.h 中我们有如下定义
template  <typename T>
class TTestUndefine
{
public:
    inline void test_function()
   {
          CTestMng::GetInstance()->DoSomething();
   }
};
 
在test_mng.h 中我们定义:
clas CTestMng
{
public:
      static CTestMng* GetInstance() { return ms_instance; }
      void DoSomething() { return; }
 
protected:
      static CTestMng* ms_instance;
};
 
OK, 我们不要care 这个Singleton的构造啊,销毁阿等OOXX的东西,就假设我们已经有这么一个singleton.
 
然后我们做了如下的precompile header
 
base.h
 
// api includes
 
// template includes
#include "test_tmpl.h"
#include ...
             ...
             ...
 
// common classes includes
#include "test_mgn.h"
#include ...
             ...
             ...
 
好了,这个base.pch文件在vc上编译不会出现问题,但是gcc中,由于会对template作预编译处理,我们会发现类似CTestMng undefine这样的错误,原因是由于我们的header file组织是按照先template后common class的顺序来的. 由于header file的include并没有特别好的组织形式,对于大型项目我们很难预知两个header file的dependence关系( 虽然我有自己做的exIncludeCheck 工具 :), 不过广大群众们没有:p ), 所以我的做法是,把template 的inline function defines都写入hpp中,然后在gch include的最末端include 这一系列的hpp文件,如下:
base.h
 
// api includes
 
// template includes
#include "test_tmpl.h"
#include ...
             ...
             ...
 
// common classes includes
#include "test_mgn.h"
#include ...
             ...
             ...
 
// late-inline defines
#include "test_tmpl.hpp" 
#include ...
             ...
 
这样的形式你就不用再为哪个头文件放前哪个头文件放后而烦恼了.
 
gch编译常见问题:
对于如下class (代码简写)
tmpl <typ T> struct classA { int data_mbr1; };
tmpl <typ T> struct classB : public classA<T>
{
    int dosomething() { return data_mbr1;}
    classB( const classB& _b )
       : data_mbr1(_b.data_mbr1)
    {
    }
};
会编译错误 -- undeclare data_mbr1. 
                -- undeclare _b.
这个虽然我觉得不应该,但gcc tmpl的check对于member的归属很严格,所以代码最后写成:
tmpl <typ T> struct classA { int data_mbr1; };
tmpl <typ T> struct classB : public classA<T>
{
    typedef classA<T> base_t;
    typedef classB<T> self_t;
    int dosomething() { return base_t::data_mbr1;}
    classB( const self_t& _b )
       : data_mbr1(_b.data_mbr1)
    {
    }
};
 
好了, 以上只是我用gch来写template的一些心得和技巧.
高效编程需要一系列辅助工具,还是希望大家多share技巧和工具.
众人: O_O O_O O_O O_O O_O O_O O_O O_O O_O
 
当然exIncludeCheck暂时不share了, 这个嘛..... 我开发很久的也,怎么能够说share 就 share !!!!!!
众人: 囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧
 
 
March 26

被这东西搞死了

Macro的一个大陷阱,今天被这个东西搞死了! 看看下面这段代码为何会编译错误:
 
// ===================================================================
 
#define EX_DEFINE_COMMON_CONTAINER_FUNCTIONS( _std_container_t )                                            \                 
    INLINE AllocatorType GetAllocator()                     { return _std_container_t::get_allocator(); }   \
    INLINE Iterator Begin()                                 { return _std_container_t::begin();         }   \
    INLINE ConstIterator Begin() const                      { return _std_container_t::begin();         }   \
    INLINE Iterator End()                                   { return _std_container_t::end();           }   \
    INLINE ConstIterator End() const                        { return _std_container_t::end();           }   \
    INLINE R_Iterator RBegin()                              { return _std_container_t::rbegin();        }   \
    INLINE R_ConstIterator RBegin() const                   { return _std_container_t::rbegin();        }   \
    INLINE R_Iterator REnd()                                { return _std_container_t::rend();          }   \
    INLINE R_ConstIterator REnd() const                     { return _std_container_t::rend();          }   \
    INLINE bool Empty() const                               { return _std_container_t::empty();         }   \
    INLINE SizeType Size() const                            { return _std_container_t::size();          }   \
    INLINE SizeType MaxSize() const                         { return _std_container_t::max_size();      }   \
    INLINE void Erase( Iterator _pos )                      { _std_container_t::erase( _pos );          }   \
    INLINE void Erase( Iterator _first, Iterator _last )    { _std_container_t::erase( _first, _last ); }   \
    INLINE void Clear()                                     { _std_container_t::clear();                }   \
    INLINE void Swap( self_t& _container )                  { _std_container_t::swap( _container );     }  
 
template < typename T >
class TVector : protected std::vector<T>
{
public:
    typedef TVector<T> self_t;
    typedef std::vector<T> base_container_t;
    EX_DEFINE_COMMON_CONTAINER_FUNCTIONS(base_container_t)
}; // end class
 
// ===================================================================
尽管复制上面的代码...错误原因居然是:
...............................
...............................
...............................
...............................
...............................
 
我在#define后面的那个 " \" 后面手贱多敲了几个空格.... 囧囧囧囧囧囧囧囧囧
还好vim的syntax highlight够强.....搞了我半个多小时,shit...........
March 04

我又开始幼稚了.....囧!!!

我发现我果然是狂热的技术主义者,所以我只能凸那些成天把商业盈利拿出来叫嚣的人啊,其实他们在寻找的是一种自我安慰而已-_-|||||,却发现技艺上已经追不上你的步伐了! 我正在找新一轮的挑战. 下个目标 -------------- 还是Griffon Engine (囧.....上次的不也是这个吗) 
August 28

加班归来

还在说周二打球可以慢有兴致地更新呢,结果 T_T 加班...........
最近最郁闷的事情要属我那台360 由传说中的3红变成1红,太猛了-_-||| 就等着秋季微软出65nm版本了, 要不是sony的PS3没游戏玩我真想买台来以示我对微软的抗议!!
话说回来ps3是可以装linux用cell sdk来写程序的, 就是gpu用不了, 有兴趣的玩家可以试试. 这算什么,算是sony对索饭们的弥补么?
再次喷一下360那无良的质量!
再说程序, 周六闲来写了棵红黑树, 结果bug太多于是放弃, 想想stl就有了何必再写, 顺手改了改, 加了些查找代码放到Griffon里运行正常, 也就没做太多测试了. 周日无聊写了个光源管理器,其实就是把LightGroup加上一堆范围检测最终得到每个物体的LightList. 写完了,但是还没来得及测试0_0....恩..不管了,能用就行,有bug再说......
 
August 21

Johnny的YY编程空间重新开张

重新整理空间,把所有以前的日记都删除了,所以留过言的同学们千万不要生气。。。

话说Beowulf的项目还没结束,所以也就不多说了。接下去准备好好把这个空间办起来,就以Griffon Engine 的开发作为日记吧。主要写空间太废时间了,最近又忙到飞起,想来周二公司有乒乓球可以打,所以回来后正好可以整理一周的头绪,所以暂定周二作为更新日记的时间,周六周天不定期更新。

那么。。。。。。今天还是就先这样吧-_-|||||||||| 华丽的闪人