はじめに
これは Delphi Advent Calendar 2019 の 17 日目の記事です。
2019/12/17訂正
コメントで指摘されているとおり、インライン関数として定義することで、デバッグビルドのときだけログ出力が実現できるとのことです。
現存するオンラインドキュメントを眺めたところ、少なくともDelphi 2010以降は、確実にサポートしている模様です(see: プロシージャと関数の呼び出し)
残念ですがDelphi7はインライン関数をサポートしていないので、それ以前のバージョンで頑張っている方は諦めましょう。
ほんへ
デバッグ時だけにログ出力して、リリースでは出したくない場合、たいていは
{$IFDEF DEBUG}
OutputDebugString('Hoge');
{$ENDIF}
な事をすると思う。
けどIFDEFやENDIFが仰々しくてなんか嫌。
なら、「関数化すればいいじゃない」ということで、コードとしてはこんな感じか。
procedure OutputDebugOnlyString(M: string);
begin
{$IFDEF DEBUG}
OutputDebugString('Hoge');
{$ENDIF}
end;
// .....
begin
OutputDebugOnlyString('Uge');
end;
けどこの関数、ログ出力の有無にかかわらず、引数は評価されて渡されてしまう。
引数に渡す関数の実行が重い場合、リリース版なのに無駄に処理を食うのなんか嫌(2回目)
そんなわけで、いい方法はないかなと思案した結果がこちら
program DevTimeOnlyLog;
{$APPTYPE CONSOLE}
{$R *.res}
{$IFDEF DEBUG}
{$C+}
{$ELSE}
{$C-}
{$ENDIF}
uses
System.SysUtils,
Windows;
function TryOutputDebugString(Msg: string): boolean;
begin
OutputDebugString(PWideChar(Msg));
Exit(true);
end;
function HeavyFunc(M: string): string;
begin
OutputDebugString('Begin sleep 2000 ms');
Sleep(2000);
OutputDebugString('Complete sleep 2000 ms');
Result := M;
end;
begin
try
Assert(TryOutputDebugString(HeavyFunc('Some Message')));
Writeln('Press ANY Key');
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
ポイントは、ログ出力をAssert手続きでくくり、コンパイラ指令($C)でログ出力の有無を切り替えるという残念な方法。
ここでは、説明のためコードで直接コンパイラ指令を指定してますが、通常はプロジェクトオプションで。
リリース版では、ログ出力のコードすら生成されなくなって心の平穏を取り戻しましたとさ。ちゃんちゃん。
おまけ
実装・動作確認、Delphi XE5にて行ったのですが、なーぜーかリリースビルドであるにもかかわらず、Assertの生成がONになってた。
リリースビルドではAssertのコードを生成しないのが一般的だと思ってたので、ちょっと驚いた。
まぁ古いバージョンだし、今は昔で変わってるのかな?