記事
· 2023年6月6日 5m read

ルーチン/クラスの一括コンパイルの結果からエラー情報を取得する方法

これは InterSystems FAQ サイトの記事です。

ターミナルでルーチンやクラスのコンパイルを行う際、コンパイル結果が画面に表示されるのでエラーが発生した場合でも確認しやすいですが、一括コンパイルの場合は、大量のコンパイル結果の中にエラー情報が含まれてしまうためエラー情報だけを取得したい場合には少し工夫が必要です。

以下、ルーチン/クラスの一括コンパイル時の結果からエラー情報を取得する方法をご紹介します。

 

ルーチンの場合

ネームスペースにあるルーチンをターミナルで一括コンパイルするには、%Library.Routine クラスの CompileAll() メソッドを使用します。

以下実行例は、USERネームスペースにあるルーチンを一括コンパイルした結果です。TestRoutine1でコンパイルエラーが発生しています。

USER>do ##class(%Routine).CompileAll()
 
Compiling in namespace USER at 11:50:47
Routine1.MAC TestRoutine1.MAC
TestRoutine1.MAC - Errors compiling routine
TestRoutine1.INT(3) : Error 8: <NOLINE> : '     do sub3()'
 
2 routines compiled with 1 errors at 11:50:47 in 00:00:00.030
USER>

大量にルーチンがある場合、出力結果が流れて画面から消えてしまうため、カレントデバイスに出力されている内容をファイル保存し、保存したファイルの中からエラー情報を取得するようにします。

 

1) コンパイル結果をファイルに保存する

CompileAll() メソッドの第2引数にファイル名をフルパスで指定します。

このメソッドは、第2引数に指定したデバイスがオープンされている場合、そのデバイスにログを書き込みます。

そのため、一旦ファイルを新規書き込みモードでオープンします(OPENコマンドを使用します)。

// ログファイルのフルパスを変数に設定します
set log="C:\temp\result.log"
//ファイルを新規書き込みモードでオープンします
open log:"NWS"
//第2引数にログ出力するファイル名を指定し、一括コンパイルを実行します。
do ##class(%Routine).CompileAll(,log)

//ファイルをクローズします。
close log

 

2) 1)で作成したファイルからエラー情報を取得する。

ファイルをオープンし、エラー発生時の文字列「Errors compiling routine」が含まれている場合にルーチン名を取り出して変数に設定する例をご紹介します。

 //文字列ファイル操作用のインスタンスを生成
 set file=##class(%Stream.FileCharacter).%New()
 //ファイルとのリンク付け
 do file.LinkToFile("c:\temp\result.log")
 //ファイルの終わりを検出するまで読み取りながら情報抽出
 //ファイルの終わりが検出されるとAtEndプロパティに1が設定される
 while file.AtEnd=0 {
  set reco=file.ReadLine()
  //読み取った行にエラー字の文字列が含まれる場合
  if reco["Errors compiling routine" {
    //スペース区切りの1番目にルーチン名が含まれているので取得
    set rtn=$piece(reco," ",1)
  }
  //ルーチン名が空だったら次のループへ移動
  if $get(rtn)="" {
    continue
  }
  //ローカル変数の添え字にルーチン名をセット
  set val(rtn)=""
 }
 zwrite val

ターミナルで実行する場合

set file=##class(%Stream.FileCharacter).%New()
do file.LinkToFile("c:\temp\result.log")
while file.AtEnd=0 { set reco=file.ReadLine() if reco["Errors compiling routine" { set rtn=$piece(reco," ",1)} if $get(rtn)="" { continue } set val(rtn)=""}
zwrite val

 

クラスの場合

ネームスペースにあるクラスをターミナルで一括コンパイルするには、%SYSTEM.OBJクラスのCompileAll()メソッドを使用します。

以下実行例は、USERネームスペースにあるクラスを一括コンパイルした結果で、Dummy.ErrorClass1でコンパイルエラーが発生しています。

USER>do $system.OBJ.CompileAll("ck")
 
04/20/2023 12:17:49 に修飾子 'ck' でコンパイルを開始しました。
エラー #5373: クラス 'Dummy.ErrorClass1:property:XYZ' が使用するクラス '%Library.Strig' は、存在しません
Skip class Dummy.ErrorClass1
, 72 クラスをコンパイル中
クラスのコンパイル中 CookBook.Class1
クラスのコンパイル中 A.b3
クラスのコンパイル中 A.B1
    《省略》
ルーチンのコンパイル中 F4.GoldMember.1
クラスのコンパイル中 MyApp.MyService.Test
ルーチンのコンパイル中 MyApp.MyService.Test.1
1.091s のコンパイル中に 1 エラーを検出しました。

第2引数を参照渡しで指定するとエラー情報が配列変数として設定されます。

USER>do $system.OBJ.CompileAll("ck",.log)

USER>zwrite log
log=1
log(1)="エラー #5373: クラス 'Dummy.ErrorClass1:property:XYZ' が使用するクラス '%Library.Strin' は、存在しません"
log(1,"caller")="findalldependencyclasses+149^%occDepend"
log(1,"code")=5373
log(1,"dcode")=5373
log(1,"domain")="%ObjectErrors"
log(1,"namespace")="USER"
log(1,"param")=2
log(1,"param",1)="%Library.Strin"
log(1,"param",2)="Dummy.ErrorClass1:property:XYZ"
log(1,"stack")=$lb("e^findalldependencyclasses+149^%occDepend^2","e^findalldependencyclasses+58^%occDepend^1","e^findalldependencyclasses+8^%occDepend^1","e^IncludeClasses+44^%occCompile^1","e^CompileList+59^%occCompile^1","e^CompileList+23^%apiOBJ^1","e^CompileAll+15^%apiOBJ^1","e^zCompileAll+1^%SYSTEM.OBJ.1^1","d^^^0")

複数エラーが発生した場合は、ログ用に指定した変数直下にエラー個数が設定されます。

エラーメッセージだけを取り出す方法は以下の通りです。

for i=1:1:log { write log(i),! }

マッピングされているクラス・ルーチンのコンパイル方法については、以下開発者コミュニティの記事をご参照ください。

マッピングされたクラス・ルーチンをコンパイルする方法

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください