Emacsのプログラミング支援ツール「CEDET」や「Magit」を活用する

Emacsにはプログラミングを支援するさまざまな機能が用意されている。今回はそのうち、Emacs 23.2よりデフォルトで利用可能になった「CEDET」と、Emacs上でGitによるソースコード管理を行える「magit」について紹介する。

Emacs上で利用できる統合開発支援ツール「CEDET」

Emacsはデフォルトでさまざまなプログラミング言語向けのモードが用意されていることもあり、プログラミングのためのエディタとして利用している人も多い。いっぽう、Visual StudioやEclipseなどの統合開発環境(IDE)はソースコードの編集やコンパイルなどの機能に加えてファイル管理機能や自動補完機能なども備えており、これら機能を目的としてIDEを利用する人も少なくない。Emacs 23.2でデフォルトで同梱されるようになった「CEDET」は、こういった補完機能やソースコードマネージャなどの機能をEmacsに追加するものだ(図1)。

図1 CEDETのWebサイト
図1 CEDETのWebサイト

CEDETが備える機能

CEDET(Collection of Emacs Development Environment Tools、直訳すると「Emacsの開発環境ツールコレクション」)はその名の通りさまざまな開発支援機能をまとめたもので、以下のような機能を提供している。

  • ソースコードなどのファイルを管理したり、Makefileなどを自動生成したり、ビルドを実行するプロジェクト管理機能
  • キーワードや変数、関数名などを補完するスマート補完(Smart Completion)機能
  • 関数や変数などの定義位置を表示するスマートジャンプ機能
  • 関数や変数などがどこで使われているかを参照できるシンボルリファレンス機能
  • ソースコードのひな形などをテンプレートから自動生成する機能
  • UML(Unified Modeling Language)ベースのダイアグラム作成機能
  • 関数やクラス、メソッドやソースファイルなどの一覧を表示するファイルブラウザ機能
  • コールツリーなどのグラフ表示

これらの機能はそれぞれ別のコンポーネントとして実装されており、たとえばプロジェクト管理機能は「EDE」、スマート補完機能は「Semantic」といったモジュールで実装されている(表1)。

表1 CEDETに含まれるコンポーネント
コンポーネント名 説明
EDE プロジェクト管理
Semantic ソースコード解析やスマート補完、スマートジャンプ、シンボルリファレンス機能
SRecode テンプレート機能
Cogre UMLダイアグラム作成
Speedbar ファイル/シンボルブラウザ
EIEIO コールツリーなどの表示

ただし、注意したいのが言語によってサポートされているレベルが異なる点だ。CEDETはさまざまな言語に対応しており、対応言語リストはCEDET Supported Languagesで確認できるが、CEDETのすべての機能を利用できるのはC/C++およびJavaのみだ。ほかの言語の場合、サポートされる機能が大きく限られてしまう。たとえばスマート補完機能はC/C++およびJava以外ではほぼ利用できないほか、スマートジャンプやシンボルリファレンス機能についても、C/C++およびJava以外ではソースコードの解析が不正確になるようで、正しく関数や変数を認識できない場合がある。

いっぽう、Speedbarは一部の表示が不正確になるものの、基本的にはすべての言語で利用できる。Semanticによるスマートジャンプやシンボルリファレンスについても、やはり同様に一部不正確なところは見られるものの多くの言語で利用が可能だ。そのため、本記事ではC/C++/Javaなどで有用なEDEと、多くの言語で利用できるSemanticおよびSpeedbarを中心に紹介する。

プロジェクト管理機能「EDE」を使う

EDEは、Makefileなどを使ったソフトウェアのコンパイルなどをサポートする機能だ。具体的には、「ターゲット」と呼ばれる、コンパイル等で生成されるファイルとそのコンパイルに必要なファイルを登録すると、自動でMakefileなどを作成してくれるというものになる。

Makefileを利用する点からも分かるとおり、この機能は基本的にはC/C++/Javaによるソフトウェア開発を想定している。また、ArduinoやAndroid向けのプロジェクトも作成可能だ。今回はC言語による、いわゆる「Hello, World」と呼ばれるシンプルなプログラムを作成する例でEDEの機能を紹介する。それ以外の利用方法についてはCEDETのマニュアルで解説されているので、そちらも参照して欲しい。

EDEを有効にする

EDEの機能を利用するには、「M-x global-ede-mode」コマンドを実行して「global-ede-mode」を有効にする必要がある。EDEを多用するという場合は、.emacsに下記を追加して起動時にglobal-ede-modeを有効にしておいても良いだろう。

(global-ede-mode 1)

global-ede-modeを有効にすると、メニューバーに「Development」という項目が追加され、ここからEDEの機能を利用できるようになる。

プロジェクトを作成する

それでは、Makefileを使ったプロジェクトを作成する例を紹介していこう。EDEの機能を利用するには、まずプロジェクトを作成したいディレクトリをEmacsで開き、続いて「Development」メニューから「Create Project」を選択するか、もしくは「M-x ede-new」コマンドを実行する。すると「Project Type:」と表示されるので、ここで「Make」と入力する。また、作業対象のディレクトリが今までEDEで使ったことのないディレクトリだった場合、EDEでの管理対象にするかどうかの確認メッセージが表示されるので、「y」で対象に追加する。最後にプロジェクト名を入力すると、ディレクトリ内に「Project.ede」という管理ファイルが作成される(図2~4)。

図2 Project Typeでは「Automake」と「Make」が選択できる
図2 Project Typeでは「Automake」と「Make」が選択できる
図3 プロジェクト名は任意のものが指定可能だ。ここでは「hello」とした
図3 プロジェクト名は任意のものが指定可能だ。ここでは「hello」とした
図4 プロジェクトを作成すると、ディレクトリ内に「Project.ede」という設定ファイルが作成される
図4 プロジェクトを作成すると、ディレクトリ内に「Project.ede」という設定ファイルが作成される

次に「M-x ede-new-target」コマンドを実行し、ターゲット(ビルドによって生成する実行ファイル)の情報を追加する。コマンドを実行するとまず「Name:」と表示されるので、ここで生成するファイルの名前を入力する(図5)。

図5 「M-x ede-new-target」コマンドで、プロジェクトで生成したいファイルを登録する。今回は「hello」というファイルを作成する
図5 「M-x ede-new-target」コマンドで、プロジェクトで生成したいファイルを登録する。今回は「hello」というファイルを作成する

続いて「Type:」と表示され、生成するファイルの種別の入力を求められる。今回は実行ファイルを作成するので、「program」と入力する(図6)。

図6 生成物の種別は「archive」や「program」、「sharedobject」などが用意されている。今回は実行ファイルを生成するので「program」を選択する
図6 生成物の種別は「archive」や「program」、「sharedobject」などが用意されている。今回は実行ファイルを生成するので「program」を選択する

ターゲットを登録したら、続いてそのターゲットを作成するために必要なファイルを作成・登録する。プロジェクトを作成したディレクトリに新たにファイルを作成すると、そこでそのファイルに対応付けるターゲットを指定するよう求められる(図7)。

図7 プロジェクトのディレクトリ内に新たなファイルを作成すると、そのファイルに対応付けるターゲットの入力が求められる。ここでは「hello.c」というファイルを作成し、先ほど作成した「hello」というターゲットに対応付けている
図7 プロジェクトのディレクトリ内に新たなファイルを作成すると、そのファイルに対応付けるターゲットの入力が求められる。ここでは「hello.c」というファイルを作成し、先ほど作成した「hello」というターゲットに対応付けている

続いて作成したファイルにコードを記述して保存する。今回は以下のようなシンプルな「hello, world!」という文字列を出力するコードを使用した。

#include <stdio.h>

int main(int argc, char *args[]) {
  printf("hello, world!\n");
  return 0;
}

今回プログラムに必要なのはこの1ファイルのみなので、ここでDevelopmentメニューから「Project Options」−「Regenerate Makefile」を選択するか「M-x ede-proj-regenerate」コマンドを実行すると、次のようなMakefileが自動生成される。

# Automatically Generated Makefile by EDE.
# For use with: make
# Relative File Name: Makefile
#
# DO NOT MODIFY THIS FILE OR YOUR CHANGES MAY BE LOST.
# EDE is the Emacs Development Environment.
# http://cedet.sourceforge.net/ede.shtml
#

top="$(CURDIR)"/
ede_FILES=Project.ede Makefile

hello_SOURCES=hello.c
hello_OBJ= hello.o
CC=gcc
C_COMPILE=$(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
C_DEPENDENCIES=-Wp,-MD,.deps/$(*F).P
C_LINK=$(CC) $(CFLAGS) $(LDFLAGS) -L.
VERSION=1.0
DISTDIR=$(top)hello-$(VERSION)
top_builddir = 

DEP_FILES=.deps/hello.P

all: hello

DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
-include $(DEP_FILES)

%.o: %.c
	@echo '$(C_COMPILE) -c $<'; \
	$(C_COMPILE) $(C_DEPENDENCIES) -o $@ -c $<

hello: $(hello_OBJ)
	$(C_LINK) -o $@ $^ $(LDDEPS)

tags: 


clean:
	rm -f *.mod *.o *.obj .deps/*.P .lo

.PHONY: dist

dist:
	rm -rf $(DISTDIR)
	mkdir $(DISTDIR)
	cp $(hello_SOURCES) $(ede_FILES) $(DISTDIR)
	tar -cvzf $(DISTDIR).tar.gz $(DISTDIR)
	rm -rf $(DISTDIR)

Makefile: Project.ede
	@echo Makefile is out of date!  It needs to be regenerated by EDE.
	@echo If you have not modified Project.ede, you can use ‘touch’ to update the Makefile time stamp.
	@false



# End of Makefile

最後に、Developmentメニューから「Build Project」−「Build Current Project」を選択するか「C-c . C」と入力すると作成されたMakefileを元にビルドが行われて「hello」プログラムが作成される。

図8 makeコマンドが呼び出されビルドが行われる
図8 makeコマンドが呼び出されビルドが行われる

今回の例では単一のファイルしか使用していないが、ターゲットに対し複数のファイルを登録したり、複数のターゲットを用意することももちろん可能だ。また、プロジェクトタイプとして「Automake」を選択すれば「configure」スクリプトを使ったビルド用のファイル一式を生成できる。

ソースコード解析機能「Semantic」を使う

Semanticは、ソースコードを解析して変数や関数などの定義位置をデータベース化し、それらを使ってさまざまな操作を行えるようにする機能だ。Semanticでは関数や変数、ソースコード内で参照しているファイル(たとえば「#include」などでインクルードしているファイル)などを「シンボル」と呼び、シンボルを定義するコードの情報を「タグ」として記録する。Semanticを利用することで、シンボルを指定してその定義位置に移動したり(タグジャンプ)、自動補完機能を利用できるようになる。

Semanticを利用するには、「M-x semantic-mode」コマンドを実行するか、もしくはツールバーの「Tools」−「Source Code Parsers (Semantic)」を選択してsemantic-modeを有効にすれば良い。semantic-modeはすべてのバッファに影響するglobal minor modeなので、一度有効にすればすべてのバッファでSemanticの機能が利用可能になる。

Semantic-modeを有効にすると、Semanticが対応するソースコードに対し自動的に構文解析が行われ、表2のキーバインディングが利用できるようになる。

表2 Semanticで利用できるキーバインディング
キーバインディング 説明
C-c , j 指定したシンボルの定義位置に移動する(タグジャンプ)
C-c , J C-c , jと同様だが、現在編集中のファイル以外で定義されているシンボルも対象にできる
C-c , SPC 文脈に応じた自動補完を行う
C-c , l 自動補完の候補を別バッファで表示する
C-c , g 指定したシンボルが参照されている(使われている)場所の一覧を表示する
C-c , G 現在のタグが参照されている(使われている)場所の一覧を表示する
C-c , p 一つ前のシンボル定義位置に移動する
C-c , n 一つ後のシンボル定義位置に移動する
C-c , u 上のシンボル定義位置に移動する
C-c , C-w 現在のタグを削除する
C-c , M-w 現在のタグをコピーする
C-c , C-y 現在のタグを挿入(yank)する
C-c , r 現在のタグをレジスタにコピーする
C-c , up 現在のタグを一つ前のタグと置き換える
C-c , down 現在のタグを一つ後のタグと置き換える

ここで「現在のタグ」という言葉はやや分かりにくいが、多くの場合これは現在カーソル位置がある関数に相当する。

ただし、前述のとおりSemanticは言語によってサポートレベルが異なるので注意したい。C/C++/Javaに関してはほぼ完璧に動作するが、それ以外の言語については変数定義を正しく認識できなかったり、コメント内の文字列を関数/変数として誤認識するような現象が見られた。

ファイルブラウザ的機能の「Speedbar」を使う

Speedbarは、開いているファイルと同じディレクトリ内にあるディレクトリやファイルの情報を表示したり、そのファイル内で定義されている関数や変数の情報を表示するウィンドウを表示する機能だ(図9)。

図9 Speedbarでは、開いているファイルと同じディレクトリ内にあるファイルや、各ファイル内のシンボルなどにアクセスできる
図9 Speedbarでは、開いているファイルと同じディレクトリ内にあるファイルや、各ファイル内のシンボルなどにアクセスできる

Speedbarを表示するには、「M-x speedbar」コマンドを実行すれば良い。Speedbarは通常のバッファとは異なる専用のウィンドウで表示され、編集対象の(アクティブな)ウィンドウに応じて自動的に表示される内容も更新される。

また、Speedbar内で表示されているファイル名や関数名などをクリックする、もしくはカーソルを合わせてEnterキーを押すと、そのファイルを開いたり、その関数の定義位置にジャンプできる(図10)。

図10 Speedbar内で表示されるファイル名やシンボルをクリックするとそのファイルを開いたり、関数の定義位置に移動できる
図10 Speedbar内で表示されるファイル名やシンボルをクリックするとそのファイルを開いたり、関数の定義位置に移動できる

Speedbarでは、Semanticによる構文解析を利用している。そのためSemanticと同様、言語によっては関数定義などを正しく認識できない場合がある点には注意したい。ただし、その場合でもファイル一覧表示やそのファイルを開く機能などは利用可能だ。

ちなみに、Speedbarはウィンドウシステムが利用できる環境でしか利用できず、仮想ターミナル上で起動したEmacsでは表示できない。そのため、仮想ターミナル上で別のバッファとしてSpeedbarを表示する「sr-speedbar」が公開されている。sr-speedbarはMELPAでパッケージが公開されており、Emacsのパッケージ管理機能を使ってインストールできる(図11)。MELPAの設定方法やパッケージマネージャについては、記事前編で説明しているので、そちらを参照して欲しい。

図11 sr-speedbarはMELPAを使ってインストールできる
図11 sr-speedbarはMELPAを使ってインストールできる

sr-speedbarパッケージのインストール後、「M-x sr-speedbar-open」コマンドを実行すると、開いているバッファの右側にSpeedbarが表示される。これはSSH経由でリモートログインしたシェル上でEmacsを利用する場合などに便利だ(図12)。

図12 sr-speedbarならリモートシェル上のEmacsでSpeedbarが利用できる
図12 sr-speedbarならリモートシェル上のEmacsでSpeedbarが利用できる

Emacs上で利用できるGitクライアント「Magit」

続いて、Emacs上で利用できるGitクライアントである「Magit」について紹介しよう。Magitは単にEmacs上でGitの各種コマンドが実行できるだけでなく、使いやすいインターフェイスも備えているのが特徴だ。

Magitのインストール

MagitはEmacsに標準では含まれていないが、MELPAを導入すればパッケージマネージャから簡単にインストールできる(図13)。

図13 MagitもMELPAでパッケージが公開されている
図13 MagitもMELPAでパッケージが公開されている

また、Magitは内部的にgitコマンドを呼び出しているが、こちらは別途インストールする必要がある。Windows環境の場合、GitのWebサイトでWindows向けバイナリが公開されているのでこちらを利用すれば良いだろう。

Magitを使ったコミット作業

それでは、Magitを使って変更点をコミットする流れを紹介しよう。「C-x magit-status」コマンドを実行すると、現在の作業ディレクトリの状態が表示された「Magitバッファ」が表示される(図14)。このバッファでは「git status」コマンドでの出力に相当するものが表示される。

図14 「M-x magit-status」コマンドを実行すると「Magitバッファ」が表示される
図14 「M-x magit-status」コマンドを実行すると「Magitバッファ」が表示される

このコマンドはMagitにおいて多用するので、適当なキーバインドに割り当てておくと良いだろう。たとえば「C-x g」にこのコマンドを割り当てる場合、以下のようになる。

(global-set-key "\C-xg" 'magit-status)

さて、ここで表示されているファイルパスにカーソルを合わせてEnterキーを押すと、そのファイルを開くことができる。また、Tabキーで各種情報の表示/非表示が切り替え可能だ。たとえば「Unstaged changes」以下で変更されたファイルが並んでいる行にカーソルを合わせてTabキーを押すと、変更点が差分の形で表示される(図15)。

図15 MagitバッファではTabキーで情報の表示/非表示を切り替えられる
図15 MagitバッファではTabキーで情報の表示/非表示を切り替えられる

コミットしたいファイルが表示されている行にカーソルを合わせて「s」を入力すると、そのファイルがコミット対象(「Staged changes」)に追加される(図16)。これは「git add」コマンドに相当する。また、一度コミット対象に追加したファイルを対象外にするには「u」を入力すれば良い。

図16 「s」を入力するとファイルをコミット対象に追加できる
図16 「s」を入力するとファイルをコミット対象に追加できる

差分ごとにコミット対象を指定することもできる。差分を表示させた状態で、コミットしたい差分にカーソルを移動させて「s」を入力すると、その部分のみがコミット対象になる(図17)。

図17 差分を表示させて「s」を入力すると、その差分のみをコミット対象に指定できる
図17 差分を表示させて「s」を入力すると、その差分のみをコミット対象に指定できる

コミットを実行するには、まず「c」を入力する。すると、コミットオプションや実行するアクションを指定するバッファが表示される(このバッファは「ポップアップ」などと呼ばれる)。単にコミットを実行するだけなら、ここでもう一度「c」を入力すれば良い(図18)。

図18 Magitバッファで「c」を入力するとオプションを指定する「popup」バッファが表示される。コミットを実行するにはここで再度「c」を入力する
図18 Magitバッファで「c」を入力するとオプションを指定する「popup」バッファが表示される。コミットを実行するにはここで再度「c」を入力する

続いてコミットメッセージを入力するためのバッファが表示されるので、ここでコミットメッセージを入力して「C-c C-c」を入力すればコミットが実行される(図19)。また、「C-c C-k」を入力するとコミット作業をキャンセルできる。

図19 コミットメッセージを編集するバッファが表示される
図19 コミットメッセージを編集するバッファが表示される

コミットログを見る

Magitバッファで「l」を入力すると、ログの表示方法を設定するためのポップアップ画面が表示される。ログを見るだけであれば再度「l」を入力すれば良い(図20)。

図20 ポップアップでログの表示オプションを指定できる
図20 ポップアップでログの表示オプションを指定できる

コミットログバッファでは、コミットIDやコミットメッセージなどが一覧表示される(図21)。さらに、ブランチによるコミットの分岐やマージなどの情報も確認可能だ。さらにここでEnterキーを押すと、カーソルがある行のコミットの情報(git showコマンドで表示される情報に相当)を確認できる。

図21 Magitのコミットログ一覧表示画面
図21 Magitのコミットログ一覧表示画面

この画面から特定のコミットをチェックアウトすることもできる。「M-x magit-checkout」コマンドを実行するとチェックアウトするコミットを尋ねられるが、このときカーソル位置にあるコミットがデフォルトとして設定されているので、そのままEnterキーを押せば良い(図22)。

図22 「M-x magit-checkout」コマンドでチェックアウトを実行できる
図22 「M-x magit-checkout」コマンドでチェックアウトを実行できる

もちろん、「M-x magit-checkout」コマンドはコミットログ一覧画面以外でも実行できる。この場合、「git checkout」とほぼ同じ感覚で「master」などのチェックアウト対象を指定可能だ。

また、指定したコミットから特定のファイルだけを復元するには、「M-x magit-file-checkout」コマンドを使用する。「M-x magit-checkout」コマンドと同様にまずチェックアウトするコミットを指定し、続けてチェックアウトするファイルを指定する(図23)。ここではTabキーによるファイル名の補完も利用可能だ。

図23 「M-x magit-file-checkout」コマンドで特定のファイルのみをチェックアウトできる
図23 「M-x magit-file-checkout」コマンドで特定のファイルのみをチェックアウトできる

新規にリポジトリを作成する

ここまででは既存のリポジトリ上での作業について説明したが、もちろんMagitを使って新たにリポジトリを作成したり、クローンしてくることも可能だ。まず新規にリポジトリを作成するには、「M-x magit-init」コマンドを使用する。これは「git init」コマンドに相当し、実行するとリポジトリを作成するディレクトリが尋ねられる(図24)。

図24 「M-x magit-init」コマンドを実行し、リポジトリを作成するディレクトリを入力するとリポジトリを新規に作成できる
図24 「M-x magit-init」コマンドを実行し、リポジトリを作成するディレクトリを入力するとリポジトリを新規に作成できる

リポジトリを作成後は、ここまでで説明したとおりの手順でファイルを追加したり、コミットを実行できる。

また、既存のリポジトリをクローンするには、「M-x magit-clone」コマンドを使用する。コマンドを実行してクローン対象のURLと、クローン先ディレクトリを指定するとクローンが実行される(図25)。

図25 「M-x magit-clone」コマンドでリポジトリのクローンを実行できる
図25 「M-x magit-clone」コマンドでリポジトリのクローンを実行できる

ブランチの情報を確認する

Magitバッファで「b」を入力すると、ブランチ関連の操作を行うための「*magit-branch-popup*」バッファが表示される(図26)。ここでは実行できる操作が一覧表示されているが、たとえば新たにブランチを作成してそのブランチをチェックアウトするには「c」を入力する。続けて作成元ブランチとブランチ名を入力すると、ブランチが作成される。

図26 Magitバッファで「b」を入力するとブランチ関連の情報とヘルプが表示される
図26 Magitバッファで「b」を入力するとブランチ関連の情報とヘルプが表示される

指定したファイルに加えた変更点を取り消す

あるファイルに加えた変更をリセットし、直近のコミット状態にまで戻したい場合、Magitバッファで対象とするファイルにカーソルを合わせて「k」を入力すれば良い。確認メッセージがメッセージが表示されるので、実行する場合は「y」を入力する(図27)。

図27 変更点を取り消してファイルを直近のコミットの状態に戻したい場合、「k」を入力する
図27 変更点を取り消してファイルを直近のコミットの状態に戻したい場合、「k」を入力する

これは、下記の処理に相当する。

git checkout <指定したファイル>

困ったら「?」を入力

Magitバッファなど、キー入力を受け付けるバッファでは「?」を入力するとヘルプが表示される(図28)。

図28 「?」を入力するとヘルプが表示される
図28 「?」を入力するとヘルプが表示される

ここに表示されているとおり、ヘルプ画面を閉じて前の画面に戻るには「g」を入力すれば良い。また、マージは「m」、プルは「F」、プッシュは「P」で実行可能だ。

このほかにも多くの支援ツールが用意されているEmacs

さて、今回はEmacsのプログラミング支援機能として、CEDETとMagitを紹介したが、これ以外にも便利なモジュールは多数提供されている。たとえばPerl向けの「pde」やJavaScript向けの「js2-mode」など、特定言語向けに特化したモジュールもある。こういったパッケージのほとんどはMELPA経由でインストールできるため、導入も容易だ。色々と試してみると良いだろう。