2012年9月15日土曜日

秀丸エディタでC#のコードを実行する

【まえがき】

普段使っているテキストエディタ (秀丸エディタ)の公式サイトで公開されていた ohtorii 氏作の


が便利だったので、紹介もかねて解説してみたいと思います。

【この記事のおしながき】


  • マクロの紹介
  • 使い方
  • マクロの実装内容
  • 小改良
  • 改良案

【マクロの紹介】


 マクロ名の通り、秀丸エディタで編集中のC#のソースコードを実行するためのマクロです。
 内部的には、ソースコードのコンパイルから実行までを行ってくれます。

マクロ実行例

 このマクロを実行すると 標準出力への出力結果を、秀丸エディタのアウトプット枠へ書き出してくれます。このため、コーディングから実行までの一連の流れをまでを、秀丸エディタだけで完結させることができます。特に秀逸だなと思った点が、

秀丸エディタで、編集中の内容(コード)を実行する

という仕様です。 このおかげで、ちょっと動作を確認したい、といったレベルのコードは、ファイルに保存すること実行できます。まさに、ワンライナーのスクリプトを書く感覚で、C#のコードを文字通り書き捨てることができます。
 また、個人的には、『 VisualStudio などの開発環境がインストールされていないマシンでも、気楽に C# でコードを書ける (*)』というのが嬉しいです。

 (*) マクロ内部で C#のコードをコンパイルするために呼び出している csc.exe(C# コンパイラ)は、 .NET Framework がインストールされていれば存在するため

【使い方】

マクロを実行する前に、一手間かける必要があります(*)。

(*) 必ずしも必要ではないのですが、デフォルトでは、マクロ内部で 64bit版 の .NET Framework 4.0のcsc.exe を呼び出すように設定されています。このため、当該.NET Frameworkがインストールされていない場合には、そのままではマクロを実行できません。

 マクロファイル (cmd_c#.mac) を開いて、ファイル冒頭箇所(37~42行目) をマクロを実行するPC環境に合わせて編集します。
 具体的には、コードの実行に用いる .NET Frameworkの Versionに合う行をアンコメントするだけです。なお、必要ない行は忘れずコメントアウトして下さい。

設定箇所 (32bit版 .NET Framework 3.5 を用いる場合)
作者の方が、あらかじめ各Versionのcsc.exeのパスを用意してくれているおかげでお手軽です。感謝。

【マクロの実装内容】

どうやってこの機能を実現しているのか気になったので、マクロの中身を読んでみました。
 コード量自体は多くないので、詳しくはコードそのものに譲るとして、ここでは概略だけを記しておこうと思います。

コードの構造

  • Main:
    • Main() 関数的なもの
    • 秀丸の設定変更
    • Start: を呼び出し
  • Start:
    • 実質的には、このマクロのMain()関数
    • GetTempFile: で、作成するcsファイル、exeファイルの絶対パスを取得
    • MakeFile: で、csファイルを作成
    • SpawnCompiler:で、exeファイルを作成
    • SpawnExe: で、exeファイルを実行
    • csファイル、exeファイルを削除
  • MakeFile:
    • 編集中の内容(コード)をコピーして、テンポラリファイルを作成
    • csファイルを作成
  • SpawnCompiler:
    • csc.exeを用いてcsファイルをコンパイル(exeファイルを作成)
  • SpawnExe:
    • exeファイルを実行
  • CreateDir:
    • フォルダを作成
    • テンポラリフォルダ内に、マクロ実行時に使うフォルダを作成
  • GetTempFile:
    • テンポラリファイルの絶対パスを取得
    • CreateDir: を利用
  • WriteOutput:
    • 秀丸のアウトプット枠に文字列を出力
    • マクロ内で発生したエラーを出力するために使用

処理の流れ

  • 秀丸で編集中のファイル内容をコピーして、テンポラリフォルダに csファイルを作成
    • テンポラリフォルダは、環境変数 tmpを参照
    • (サブルーチン GetTempFile, MakeFile)
  • csc.exe を用いて、テンポラリフォルダ内で exeファイルを作成
    • (サブルーチン SpawnCompiler)
  • 作成したexeファイルを実行して、出力を秀丸のアウトプット枠に表示
    • 標準出力、標準エラー出力の両方を出力
    • (サブルーチン SpawnExe)
  • 作成したcsファイル、exeファイルを削除

【小改良】

csc.exe のデバッグオプションが有効になるように、$g_exe に直接 /debug+ を書き加えました。
 (自分の場合は横着をして $g_exeに書き加えましたが、今後の拡張を考えマクロにちゃんと手を加えるのであれば、SpawnCompilerサブルーチン 内にデバッグオプション用の変数を用意した方が良いかもしれません。)

x86版 .NET3.5の場合 (末尾の+は書かなくてもOK)
デバッグオプションを有効にしておくと、下図に示すように、実行時にエラーが発生した際、エラーの原因がコードの何行目かを明記してくれるようになります。

デバッグオプションを有効にした場合のエラー表示

 デバッグが必要になるほどのコードを書くことは、そうないとは思うのですが、念のため設定しておいてもよいのではないでしょうか。

 なお、/debug を有効にすると、exeファイル作成時に、同名のpdbファイルが作成されます。気になる方は、Startサブルーチンの末尾にpdbファイルを削除するためのコードを追加した方が良いかもしれません。(個人的には、テンポラリフォルダ内なので気にしていません。)

【改良案】

外部アセンブリの読み込みに対応できると、ネットの海から拾ってきたdllの動作確認ができるので何かしら使い勝手が良いかもなぁと思ったりします。(近々でそういった使い方をしたいというわけではないのですが)

 csc.exe 自体は /r: オプションでアセンブリの参照設定を追加できるので、例えば
  • 開いているファイルと同階層にあるdll一覧を取得
  • 各dllの絶対パスを /r: オプションで指定
とすれば、実現できそうです。