C/C++のプリプロセッサを使ってHTMLやJavaScriptのデバッグ用コードを操作する。

HTMLやJavaScriptデバッグやテストのためだけのコードを書いておき、リリース時は消しておきたいといというシチュエーションがあると思います。 gulpなどを使うのかなと思って、調べたら意外にC/C++プリプロセッサを使う方法が出てきました。

perezvon.hatenablog.com

前提

  • clang Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)

プリプロセッサってなに?

Wikipediaによると

プリプロセッサ - Wikipedia

コンパイル処理において、プリプロセッサ(preprocessor)とは、コンパイラソースコードコンパイルする前に、一旦ソースコードに処理を施すためのプログラムである。

処理内容

以下のようなものがある。

  • ファイルの読み込み (including)
  • マクロの展開(文字列を、あらかじめ定義された規則に従って置換する)
  • 定数の数値への置き換え
  • コンパイル条件によるソースコードの部分的選択
  • コメントの削除

とのことです。 今回はコンパイル条件によるソースコードの部分的選択という機能を使ってデバッグ用コードをフィルタして取り除いてしまいます。(ということがオプションで選択できるので良いねという話)

準備

MacOSXの場合、XCodeのインストール時にclangというコンパイラがインストールされます。 コンソールからも確認できます。

$ which clang
/usr/bin/clang

Unix/Linuxの場合ディストリビューションによってclangやgccがあると思います。 今回使う程度の機能はclangでもgccでも大差なく備えている機能なので、好きな方を使いましょう。 大体の環境ではccコマンドでシステムデフォルトのコンパイラが使えます。

$ which cc
/usr/bin/cc
$ cc --version
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

ソースコードを編集

例えば以下の様なJavaScriptソースコードがあったとします。

function is_bigger(a, b) {
    console.log('is_bigger(' + a + ',' + b ');'); // デバッグ用
    return a > b;
}

ここでデバッグ用の行を以下のように囲みます。

function is_bigger(a, b) {
#ifndef NDEBUG
    console.log('is_bigger(' + a + ',' + b ');'); // デバッグ用
#endif
    return a > b;
}

なんとなくわかると思いますが、#ifndef ~ #endif部分はNDEBUGという定数が定義された場合、出力されなくなります。ここでのNDEBUGはJavaScriptの変数とは関係ないプリプロセッサのオプションみたいなものです。

プリプロセッサを実行する

ソースコードをsample.jsなどの名前で保存しておきます。

コマンドラインから以下のようにccを起動すると、

$ cc -E -C -P -x c -Wno-invalid-pp-token sample.js

デバッグ用コードが残ったソースコードが出力されます。

function is_bigger(a, b) {
    console.log('is_bigger(' + a + ',' + b ');'); // デバッグ用
    return a > b;
}

また、以下のようにccを起動すると、

$ cc -E -C -P -x c -Wno-invalid-pp-token -DNDEBUG sample.js

デバッグ用コードが無くなったソースコードが出力されます。

function is_bigger(a, b) {
    return a > b;
}

-DNDEBUGオプションでプリプロセッサにNDEBUGという定義を渡しています。これがifndefで評価されることで該当部分のソースコードの出力を制御しています。 引用元には-Eオプションと-Wno-invalid-pp-tokenがありませんでした。-Eばプリプロセッサだけ実行(指定しないとコンパイルしようとしてエラーになる)、-Wno-invalid-pp-tokenは余計な警告(C/C++だと文法的におかしいトークン)を無視しています。 同様の操作でHTML(というか、行頭の#記号に意味が与えられていないファイル)でもデバッグ用コードを操作することができます。 プリプロセッサ自体にはフィルタ以外にもイロイロ機能があります。

C言語 プリプロセッサ

活用すればもっと楽ができそうです。 欠点として、

  • 出力結果のJavaScriptやHTMLの行がプリプロセッサ分変化するので、ブラウザで出力された行数と修正対象の行数が異なる
  • エディタによってはインデントがおかしくなる(かもしれない)

チョット使う場所を選びそうです。