I am 开发者_StackOverflow中文版using ctags
to generate a tags
file for a C project I am working on, but many functions are missing in the file. This appears to be caused by unbalanced braces in the source files due to using #ifdef
. A (simplified) example:
#include <stdio.h>
struct mystruct {
long member;
#ifndef _MSC_VER
}__attribute__ ((packed));
#else /* _MSC_VER */
};
#pragma pack(pop)
#endif /* _MSC_VER */
char* greeting_text(){
return "Hello world\n";
}
int main( int argc, const char* argv[] ){
char * greeting = greeting_text();
printf(greeting);
return 0;
}
This compiles and works flawlessly with gcc -Wall
under Linux. However, if I parse it using ctags problem.c
, the tags
file only contains entries for mystruct
-- the functions are missing.
ctags --verbose
reports:
OPENING problem.c as C language file
problem.c: unexpected closing brace at line 8
problem.c: retrying file with fallback brace matching algorithm
OPENING problem.c as C language file
problem.c: unexpected closing brace at line 8
so apparently ctags
does not like the preprocessor tricks in the file.
Is there a way to make ctags
handle this?
The manpage of ctags
even explicitly mentions this problem, but indicates ctags
can work around this. However, this does not appear to work...
This is with Exuberant Ctags 5.8 (Debian package 1:5.8-4).
Edit:
I'm also interested in alternatives to ctags that handle these kinds of constructs.
Because of the problems with ctags, I ended up using cscope instead.
While it's not perfect, it handles macros better than ctags, and it can integrate with vim just like ctags can (see http://vimdoc.sourceforge.net/htmldoc/if_cscop.html#:cscope ).
I would try running the preprocessor (gcc -E
) on the files before giving them to ctags. Whether this will produce a good result I am not certain, but it would be worth a try. Certainly all components of your code should appear then, but will ctags recognize the other-file references that gcc leaves in the output? Not sure.
You could try to rewrite the code so that there only is one closing brace, for example:
struct mystruct {
long member;
}
#ifndef _MSC_VER
__attribute__ ((packed))
#endif
;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
Of course, you can define some convenience macros to make it easier to read.
You could run the unifdef
tool to selectively (and temporarily) replace the inactive part of the code with blank lines (unifdef -l -U_MSC_VER)
. The result is
#include <stdio.h>
struct mystruct {
long member;
}__attribute__ ((packed));
char* greeting_text(){
return "Hello world\n";
}
int main( int argc, const char* argv[] ){
char * greeting = greeting_text();
printf(greeting);
return 0;
}
Ctags has no problem parsing this correctly and the line numbers remain the same (important if you create ctags searches by line number):
$ cat tags
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.6 //
greeting_text y.c /^char* greeting_text(){$/;" f
main y.c /^int main( int argc, const char* argv[] ){$/;" f
member y.c /^ long member;$/;" m struct:mystruct file:
mystruct y.c /^struct mystruct {$/;" s file:
unifdef
is available on many operating systems as a package (e.g. FreeBSD, various Linux distris, Cygwin). Homepage: http://dotat.at/prog/unifdef/
精彩评论