技术宅和经济盲

Monday, February 28, 2011

Error of "Undefined reference to: XXX"...

Wow, waste some hours (in fact some days in total in the past, because don't know the root cause very clearly before!), and now I can wrote some summary on this error. It dues to two reasons: (at least in gcc-3.4)
- Forgot to link library with func XXX.
- Order of libraries is wrong!

Most of Google result mentioned the first case, but for the second one, it is really difficult to catch. It happens like you have some components, like A, B, C. A depends on B and C depends on A and B. And we will use libA / libB / libC to replace library of A / B / C. So, if you have command like:

g++-3.4 -o <binary> <objects> ...libB libA

then you will found libA can't find functions defined in libB. It often makes you confused, but in fact, the only problem is the order, you can try

g++-3.4 -o <binary> <objs> ... libA libB

And then you found it PASSed link stage! By using "nm" command, you can get a bit hints as below:
$nm libB | grep XXX
00000000 T XXX(...)
$nm libA | grep XXX
                   U XXX(...)
From document, "T" means "a global definition", and "U" means "an external reference". If you put them into a C++ file, it should be:

void XXX(...) {
...
}

void XXX(...);

Because the later one will replace the first one in the symbol table, you can't find definition of XXX(...) any more. That is the root-cause of the problem.

So, once you failed on linking, try "nm" and think it in source code level to figure it out.

Labels:

Tuesday, February 15, 2011

Frequently used Java technologies

Google collection (now named guava-libraries)
thrift

Thursday, February 10, 2011

Apache hooks简介

项目需要,而且网上的中英文材料都语焉不详,所以看了看apache hooks的代码。

我们的代码是:

static void register_hooks(apr_pool_t *pool) {
  ...
  ap_hook_translate_name(set_cookie, NULL, NULL, APR_HOOK_FIRST);
  ap_hook_handler(process_request, NULL, NULL, APR_HOOK_FIRST);
}

module another_client = {
  ...;
  register_hooks;
};

我想搞明白来一个request,到底cookie是怎么handle的,所以需要知道到底set_cookie和process_request的调用的order到底是怎样的。好了,然后这个问题看了我快一天,这代码写的。

首先是ap_hook_translate_name(...)。这个的函数是有宏写的定义,方便扩展到自定义的hooks上。(我不是很确定这是一种很现代化的实现,不过在那个用C来写可扩展程序的年代,貌似也是一种唯一的办法了)下面是我手动扩展出来的定义代码:(你也可以用-E的选项生成语编译代码来看看是否是你需要的东西,定义在include/http_request.h,实现在server/request.c


// Declaration
typedef int ap_HOOK_translate_name_t (request_rec *r);
void ap_hook_translate_name(ap_HOOK_translate_name_t *pf,
                            const char * const *aszPre,
                            const char * const *aszSucc, int nOrder);
int ap_run_translate_name (request_rec *r);
apr_array_header_t * ap_hook_get_translate_name(void)
typedef struct ap_LINK_translate_name_t {
  ap_HOOK_translate_name_t *pFunc;
  const char *szName;
  const char * const *aszPredecessors;
  const char * const *aszSuccessors;
  int nOrder;
} ap_LINK_translate_name_t;

// Implementation
void ap_hook_translate_name(
    ap_HOOK_translate_name_t *pf,
    const char * const *aszPre,
    const char * const *aszSucc,
    int nOrder)
{
  ap_LINK_translate_name_t *pHook;
  if(!_hooks.link_translate_name)
  {
    _hooks.link_translate_name = apr_array_make(
        apr_hook_global_pool,1,sizeof(ap_LINK_translate_name_t));
    apr_hook_sort_register(translate_name,
                           &_hooks.link_translate_name);
  }
  pHook=apr_array_push(_hooks.link_translate_name);
  pHook->pFunc=pf;
  pHook->aszPredecessors=aszPre;
  pHook->aszSuccessors=aszSucc;
  pHook->nOrder=nOrder;
  pHook->szName=apr_hook_debug_current;
  if(apr_hook_debug_enabled)
    apr_hook_debug_show(translate_name, aszPre, aszSucc);
}

apr_array_header_t * ap_hook_get_translate_name(void)
{
  return _hooks.link_translate_name;
}

int ap_run_translate_name (request_rec *r)
{
  ap_LINK_translate_name_t *pHook;
  int n;
  int rv;
 
  if(!_hooks.link_translate_name)
    return DECLINED;
 
  pHook=(ap_LINK_translate_name_t *)_hooks.link_translate_name->elts;
  for(n=0 ; n < _hooks.link_translate_name->nelts ; ++n)
  {
    rv=pHook[n].pFunc (r);
   
    if(rv != DECLINED)
      return rv;
  }
  return DECLINED;
}

可以看出来,调用translate_name的hook的入口是ap_run_translate_name。然后我们就可以关注到底那里调用了这个东西,以及另外ap_run_handler的位置在哪里了。这个任务相对比较简单,它们的位置分别是modules/http/http_request.c中的ap_process_request(...)和server/request.c中的ap_process_request_internal(...),下面是我根据这两个函数summarize出来的我所知道的所有hooks的order:

Read more »

Thursday, February 03, 2011

好累的C++

不知道是我太久没写了,还是coding style和C++的指针传递太危险了,编译和lint一直有问题。写程序花了2小时,让它编译通过花了6个小时,恐怕有重新学习C++的危险了。

下面举个例子:

hash_map<string, string=""> properties;
...
for (hash_map<string, string="">::const_iterator
    ii = properties.begin(); ii != properties.end(); ++ii) {
  LOG(INFO) << (ii-&gt;first) << " = " << (ii-&gt;second) << std:endl;
}

这不是一个很简单的code吗,结果死活编译不过去!爬到源码堆里一看,原来g++ 3.4 是这么定义的:

namespace __gnu_cxx {

template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
    class _EqualKey = equal_to<_Key>, class _Alloc = allocator<_Tp> >
class hash_map;

也就是说,你写一个hash_map<string, string>啥的的话,它回去lookup下面三个函数对象(是不是这个名字阿?):
struct hash<string> {  // just for simplication, in STL, it is basic_string
  size_t operator()(string s) const {...}
};
struct equal_to<string> {...};
struct allocator<string> {...};


然后我看了一下在hash_fun.h里的定义,就悲剧了!原来只有hash<const char *>。

所以,同学们,写C++的话,不会看源代码,大约只能等死了。而且,熟悉它的话,恐怕要花点时间,譬如说半年。当然,现在有些库已经挺好用的了,特别是boost。所以,你还是很有机会在很熟悉的情况下用的挺好的的。

至于我,我觉着language应该需要有些进步了,否则真的太浪费engineer的时间了。特别是好多C++ coding style方面的限制,真的就是用来防止函数副作用的而已。但是已经搞得写code和读code都不是那么方便了。

写code,应该和写文章一样让人有赏心悦目的感觉!