2008/01/31


Googleが提供している開発用tagツールGoogle GTags(gtags)をWindowsで動かす手順です。
以下、パッチを上げてますが、接続タイムアウトのalarmを無効化しています。必要だと思われる人は、SIGALRMを別の方法で実装してください。
まず、サイトからsvnで最新ソースを取得します。
C:\TEMP> svn checkout http://google-gtags.googlecode.com/svn/trunk/ google-gtags 次に、以下のパッチを当てます。
Index: regexp.h
===================================================================
--- regexp.h    (revision 57)
+++ regexp.h    (working copy)
@@ -4,7 +4,9 @@
 #ifndef TOOLS_TAGS_REGEXP_H__
 #define TOOLS_TAGS_REGEXP_H__
 
+extern "C" {
 #include <regex.h>
+}
 #include "tagsutil.h"
 
 class RegExp {
Index: configure
===================================================================
--- configure   (revision 57)
+++ configure   (working copy)
@@ -10,7 +10,7 @@
 if [ ! -e "scons/scons.py" ]; then
     pushd scons > /dev/null
     echo "Unpacking scons..."
-    tar xzvf scons-local.tar.gz > /dev/null
+    gzip -dc scons-local.tar.gz | tar xv > /dev/null
     if [[ "$?" == 0 ]]; then
    echo "Done"
     else
Index: gtags.cc
===================================================================
--- gtags.cc    (revision 57)
+++ gtags.cc    (working copy)
@@ -49,6 +49,10 @@
 #include "tagsoptionparser.h"
 #include "tagsrequesthandler.h"
 
+#ifdef WIN32
+# include <winsock2.h>
+#endif
+
 DEFINE_STRING(tags_file, "", "The file containing the tags information.");
 
 
@@ -78,6 +82,11 @@
     return -1;
   }
 
+#ifdef _WIN32
+  WSAData wsadata;
+  WSAStartup(MAKEWORD(2,0), &wsadata);
+#endif
+
   logger = new StdErrLogger();
 
   tags_request_handler = new TagsRequestHandler(GET_FLAG(tags_file),
@@ -90,4 +99,9 @@
 
   delete tags_request_handler;
   delete logger;
+
+
+#ifdef _WIN32
+  WSACleanup();
+#endif
 }
Index: gtags.py
===================================================================
--- gtags.py    (revision 57)
+++ gtags.py    (working copy)
@@ -175,11 +175,11 @@
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      address = socket.getaddrinfo(host, port, socket.AF_INET,
                                socket.SOCK_STREAM)
-     signal.signal(signal.SIGALRM, alarm_handler)
-     signal.alarm(CONNECT_TIMEOUT)
+     #signal.signal(signal.SIGALRM, alarm_handler)
+     #signal.alarm(CONNECT_TIMEOUT)
      s.connect(address[0][4])
-     signal.alarm(0)
-     signal.alarm(DATA_TIMEOUT)
+     #signal.alarm(0)
+     #signal.alarm(DATA_TIMEOUT)
 
      # need \r\n to match telnet protocol
      s.sendall(command + '\r\n')
@@ -191,7 +191,7 @@
      while data:
        buf.write(data)
        data = s.recv(1024)
-     signal.alarm(0)
+     #signal.alarm(0)
      return buf.getvalue()
 
 # Instance of connection_manager that forwards client requests to gtags server
Index: tags_logger.h
===================================================================
--- tags_logger.h   (revision 57)
+++ tags_logger.h   (working copy)
@@ -67,6 +67,7 @@
   }
 };
 
+#undef ERROR
 const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3, NUM_SEVERITIES = 4;
 
 // uncomment out the standard google logger
Index: socket_server.cc
===================================================================
--- socket_server.cc    (revision 57)
+++ socket_server.cc    (working copy)
@@ -18,10 +18,14 @@
 
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
+#ifdef WIN32
+# include <winsock2.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <unistd.h>
+#endif
 #include <string>
 
 #include "tagsprofiler.h"
@@ -29,6 +33,12 @@
 #include "tagsrequesthandler.h"
 #include "socket_server.h"
 
+#ifdef WIN32
+typedef int socklen_t;
+#define write(x, y, z) send(x, y, z, 0)
+#define close(x) closesocket(x)
+#endif
+
 extern GtagsLogger* logger;
 
 DEFINE_INT32(tags_port, 2222, "port to tags server");
次にgoogle-gtagsのソースルートにregex for win32を解凍します。これで、gnu_regex_distというフォルダが出来ます。
zsh for win32等をお持ちの方ならば、そのまま sh configure
お持ちでない方でもconfigureの中身を見ると大体検討が付きます。
Makefile.w32は以下の通り。mingw32-makeでビルドします。
all: gtags.exe

gtags.exe : filename.cc gtags.cc sexpression.cc strutil.cc symboltable.cc tagsoptionparser.cc tagsprofiler.cc tagsrequesthandler.cc tagstable.cc socket_server.cc gnu_regex_dist/regex.c
    gcc -DHAVE_STRING_H -c -I. gnu_regex_dist/regex.c
    gcc -I. -Ignu_regex_dist -o gtags.exe filename.cc gtags.cc sexpression.cc strutil.cc symboltable.cc tagsoptionparser.cc tagsprofiler.cc tagsrequesthandler.cc tagstable.cc socket_server.cc regex.o -lstdc++ -lws2_32
あとはspiritlooseのはてなダイアリー - [Vim]Google Tags(GTags)を試してみた(with Vim)を参考に lang_call_to_server = {
  "c++" : { "definition" : [("localhost", 2222)],
            "callgraph" : [] },
  "java" : { "definition" : [],
             "callgraph" : [] },
  "python" : { "definition" : [],
               "callgraph" : [] } }
等と設定して、vimrcに exec "set runtimepath+=".escape(globpath(&runtimepath, 'gtags'), ' ')
nmap <C-]> :call Gtag(expand('<cword>'))<CR>
を追加します。
これで設定はOKです。次に以下の手順でソースツリーでtagsファイルを生成します。
python c:/temp/google-gtags/gentags.py --etags=c:/emacs/bin/etags.exe --rtags=c:/temp/google-gtags/rtags.py --etags_to_tags=c:/temp/google-gtags/etags_to_tags.py ここではetagsとしてemacsに含まれるバイナリを使用しましたが、ctags.exeをetags.exeにリネームしても同様に使えます。
これで「cpp.tags.gz」というファイルが生成されますので、あとはサーバを起動します。
c:/temp/gtags.exe --tags_file ./cpp.tags.gz --tags_port 2222 --gunzip 起動したらvim(gvim)を起動して、タグジャンプしたい部分でC-]します。
spiritlooseさんの言うように確かに速いですね。共同開発等では便利かもしれませんね。

オフトピですが、このライブラリに含まれるSconsというビルドツールについて今度調べてみようかと思います。
Posted at by




コマンドモードで :help! 結果↓ E478: 慌てないでください!
tipsというよりイースターエッグかな...
Posted at by




vimを使っていらっしゃる半数以上は開発者の方かと思います。
今日は、そんな開発者の方に便利なtipsをご紹介。

Makefile編集中のファイル名補完

一般的なファイルシステムでは、ファイル名に「=」という文字を使うことが出来ます。ただ、実際に使っているかどうかといえば、めったに使われる事はありません。なのに TOP_DIR=/usr/inc
まで打って<c-x><c-f>とタイプしてもファイル名が補完されないのは、悲しかったりします。 こんなときには以下の設定をvimrcに入れておくと便利です。
autocmd FileType Makefile setlocal isfname-== isfname+=32
通常、フォルダ名やファイル名に「=」やスペースを使う事はまずありませんし、*unix系の開発を経験された事がある方ならば、スペースが混じってしまう事は一大事になる事もご存知かと思います。
この設定だと、Makefileにだけ適応されますし補完もサクサク出来ますね。
ちなみにWindowsで「C:/Program Files/hogehoge」を補完されたいならば TOP_DIR="C:/Progra
と「"」を先頭にしておく事で補完出来ます。
もしかすると、*unixな方は「I」や「L」もisfnameから消してしまう事で CFLAGS=-I/usr/inc
とか LDFLAGS=-L/usr/li
でも補完出来て幸せかもしれません。

長いブロックや複数ブロックがある言語の開発

jsp(JavaServerPages)やASP(ActiveServerPage)、php等で開発される場合には、開始タグで各言語の処理を開始します。例えばphpであれば <?php
$f = fopen("test.dat", "r");
と「<?php」が開始タグとなります。
vimでは各言語に合わせてシンタックスハイライト表示する機能を持っていますが、この開始/終了タグを辿って色付けをしています。この開始/終了タグの検索は、最悪ファイル全体を検索してしまい重たくなってしまう可能性がある為、vimでは閾値範囲内しか検索しないようになっています。
ただ、全ての言語でこの閾値が相応しいものとは限らず、まれに長いブロックが存在するとシンタックスハイライトが効かなくなってしまう事もあります。ここではこの閾値の変更方法を説明します。
閾値は、「syntax sync 」コマンドの「minlines」という値で設定でき、以下のようにautocmdで設定します。
autocmd FileType jsp,asp,php,xml,perl syntax sync minlines=500 maxlines=1000
私は上記の設定を使っています。

pythonのインデントをタブではなくスペースにする

これはvimユーザでpythonの開発をされる方であれば、これは必須ですね。
以下の設定はタブ幅4で、expandtabにしています。
autocmd FileType python setlocal ts=4 sw=4 sta et sts ai
ただ、まれにスペース2つの人とかもいますから、人のソースを修正する際には向かないかもしれませんね。

Emacsユーザに送るキーバインド

これはおまけ。
nmap <m-x> :
nmap <silent> <c-x>1 :only<cr>
nmap <silent> <c-x>2 :sp<cr>
nmap <c-x><c-w><c-w>
cmap <m-x> <nop>
もっとこだわりたい方は、vimacsの方をお勧めします。

追記1:リンクが間違ってました
追記2:KoRoN氏の指摘で「BufEnter」から「FileType」に修正(コピペ元がマズってました)
追記3:さらにKoRoN氏の指摘で「FileType」のpatternが間違ってるとの指摘で修正(もしかしたらBufEnter使ってたのは拡張子使いたいからだったのかな?覚えてないや)

mattn the Onsen Ikitai!
Posted at by