こんにちは、高木です。
前回に引き続き、PHPを使ってC言語やC++のソースコードをコンパイルする話題です。前回のやり方はGCCやClangでコンパイルするときはいいのですが、Visual C++ではうまくいきません。依存関係を表すファイルの形式がまったく異なるからです。今回はVisual C++に特化したやり方を解説したいと思います。
おさらいとして、コンパイルする対象となるソースファイル「a.cc」をもう一度掲載しておきます。
0 1 2 3 4 5 6 7 |
#include "b.hh" #include "c.hh" int main() { } |
これをコンパイルするには、コマンドプロンプトから次のようなコマンドを実行します。
0 1 2 |
cl /Fe:a a.cc |
細かいコマンドプションは省略しています。唯一指定している/Feオプションは出力するファイル名を指定するためのものです。上記の例では「a」を指定していますので、「a.exe」が出力されます。
これだけでは依存関係を表すファイルは出力されません。Visual Studio 2019で導入された/sourceDependenciesオプションを指定する必要があります。このオプションのパラメータで渡した名前のファイルに依存関係を表すJSONが出力されます。
JSONファイルの名前を「a.json」とした場合、コマンドは次のようになります。
0 1 2 |
cl /sourceDependencies:a.json /Fe:a a.cc |
あとは、前回と同じように、生成されたa.jsonを解析して依存するファイル名を洗い出し、更新時刻を比較してあげればOKです。
PHPのコードは次のようになります。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php $source_file = 'a.cc'; $target_file = 'a.exe'; $dependency_file = str_replace('.cc', '.json', $source_file); // コンパイル要求フラグ $compile_request = !file_exists($target_file); if (!$compile_request) { // 依存するファイルの更新時刻を調べてコンパイル要求フラグを立てる。 $target_mtime = filemtime($target_file); if (file_exists($dependency_file)) { // JSONファイルの読み込み $json = file_get_contents($dependency_file); $obj = json_decode($json); // 依存ファイルの抽出 $data = $obj->{'Data'}; $dependency = $data->{'Includes'}; $dependency[] = $data->{'Source'}; // 更新時刻のチェック foreach ($dependency as $file) { if (filemtime($file) > $target_mtime) { $compile_request = true; break; } } } else { $compile_request = filemtime($source_file) > $target_mtime; } } // コンパイル要求フラグが立っている場合だけコンパイルする。 if ($compile_request) { $output = str_replace('.exe', '', $target_file); $command = "cl /sourceDependencies:$dependency_file /Fe:$output $source_file"; passthru($command); } |
概念的なことは前回と同じですので割愛します。json_decode関数等については、PHPの公式リファレンスを参照するようにしてください。今回は簡単な解説だけにとどめておくことにします。
ところで、前処理とは直接関係ないコンパイルをなぜわざわざPHPを使って行うのかについては、のちほど機会を見つけて解説したいと思います。とりあえず今回はこのあたりで。