昨天无意发现 ctags 竟然没有生成标准库中 fopen 的 tag。太诡异了,多方询问未果只好问 ctags 的 mailing list:
On Sun, August 17, 2008 03:37, AutumnCat wrote:
> > ctags /usr/include/stdio.h grep fopen tags (Found nothing)
> >
> > ctags –c-kinds=+x /usr/include/stdio.h grep fopen tags (Found nothing)
+x asks for variable declarations, not function declarations. you want +p.
–verbose will probably show that your .h file is being interpreted as C++
(though that won’t matter in this case).
depending on the actual contents of your stdio.h (you don’t say what
system you’re on), you may have extra stuff in your declarations. for
example. glibc on Ubuntu 8.04 has something like "fopen1" here:
extern FILE *fopen1 (__const char *__restrict __filename, __const char
*__restrict __modes) __wur;
extern FILE *fopen2 (__const char *__restrict __filename, __const char
*__restrict __modes) ;
extern FILE *fopen3 (__const char * __filename, __const char * __modes)
__wur;
extern FILE *fopen4 (__const char * __filename, __const char * __modes) ;
extern FILE *fopen5 ( char * __filename, char * __modes) ;
extern void f ( char * __filename, char * __modes) ;
extern void f_wur ( char * __filename, char * __modes) __wur ;
but you can see that ctags only copes with a subset of these:
lithium:/tmp$ ctags -o – –c++-kinds=+xp –verbose /tmp/stdio.h
Reading command line arguments
OPENING /tmp/stdio.h as C++ language include file
sorting tag file
f /tmp/stdio.h /^extern void f ( char * __filename, char * __modes) ;$/;" p
fopen2 /tmp/stdio.h /^extern FILE *fopen2 (__const char *__restrict
__filename, __const char *__restrict __modes) ;$/;" p
fopen4 /tmp/stdio.h /^extern FILE *fopen4 (__const char * __filename,
__const char * __modes) ;$/;" p
fopen5 /tmp/stdio.h /^extern FILE *fopen5 ( char * __filename, char *
__modes) ;$/;" p
lithium:/tmp$
adding -I_wur works around this:
lithium:/tmp$ ctags -o – –c++-kinds=+xp -I__wur –verbose /tmp/stdio.h
Reading command line arguments
OPENING /tmp/stdio.h as C++ language include file
sorting tag file
f /tmp/stdio.h /^extern void f ( char * __filename, char * __modes) ;$/;" p
f_wur /tmp/stdio.h /^extern void f_wur ( char * __filename, char *
__modes) __wur ;$/;" p
fopen1 /tmp/stdio.h /^extern FILE *fopen1 (__const char *__restrict
__filename, __const char *__restrict __modes) __wur;$/;" p
fopen2 /tmp/stdio.h /^extern FILE *fopen2 (__const char *__restrict
__filename, __const char *__restrict __modes) ;$/;" p
fopen3 /tmp/stdio.h /^extern FILE *fopen3 (__const char * __filename,
__const char * __modes) __wur;$/;" p
fopen4 /tmp/stdio.h /^extern FILE *fopen4 (__const char * __filename,
__const char * __modes) ;$/;" p
fopen5 /tmp/stdio.h /^extern FILE *fopen5 ( char * __filename, char *
__modes) ;$/;" p
lithium:/tmp$
_wur, since you ask, is a glibc macro for the GCC 3.4 or later
__attribute__ ((__warn_unused_result__)).
–elliott
> > but
> >
> > grep fopen /usr/include/stdio.h extern FILE *fopen (__const char
> > *__restrict __filename,
> > extern FILE *__REDIRECT (fopen, (__const char *__restrict __filename,
> > __const char *__restrict __modes), fopen64)
> > # define fopen fopen64
> > extern FILE *fopen64 (__const char *__restrict __filename, extern FILE
> > *fopencookie (void *__restrict __magic_cookie,
> >
> >
> > Why ?
> >
> >
> > ————————————————————————-
> > This SF.Net email is sponsored by the Moblin Your Move Developer’s
> > challenge Build the coolest Linux based applications with Moblin SDK & win
> > great prizes Grand prize is a trip for two to an Open Source event
> > anywhere in the world
> > http://moblin-contest.org/redirect.php?banner_id=100&url=/_______________
> > ________________________________
> > Ctags-users mailing list
> > Ctags-users@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/ctags-users
> >
> >
– Elliott Hughes, http://www.jessies.org/~enh/
换句话说,就是个 gcc 的扩展在作怪,__wur 干扰了 ctags 的解析。
经 hellwolf,manphiz 指导,终于发现问题所在。
举一个例子:
/* a.h */
#define foobar
/* a.c */
#include "a.h"
void foo(void) foobar
{
;
}
int main (int argc, char const* argv[])
{
foo();
return 0;
}
看这个:
$ ctags --language-force=c --c-kinds=+xp -o - -R .
foobar a.h 1;" d
main a.c /^int main (int argc, char const* argv[])$/;" f
噢?void foo(void) 到哪去了呢?加上 -I 参数试试:
$ ctags --language-force=c --c-kinds=+xp -o - -I foobar -R .
foo a.c /^void foo(void) foobar$/;" f
foobar a.h 1;" d
main a.c /^int main (int argc, char const* argv[])$/;" f
由此看出,ctags 并不展开宏。由于宏 foobar 没有被展开,造成了错误的语法。其实 ctags 的 man 中早有提及(果然还是要RTFM……):
Because ctags is neither a preprocessor nor a compiler, use of preprocessor macros can fool ctags into either missing tags or improperly generating inappropriate tags. Although ctags has been designed to handle certain common cases, this is the single biggest cause of reported problems. In particular, the use of preprocessor constructs which alter the textual syntax of C can fool ctags. You can work around many such problems by using the -I option.