DBB/zAppBuildについてのメモ - (3)zAppBuildビルド・スクリプト

# はじめに
ここではzAppBuildが提供するビルド・スクリプトについて見ていきます。

※当記事はzAppBuild V3.1.0をベースにしています。

## 関連記事

[DBB/zAppBuildについてのメモ - (1)概要](https://qiita.com/tomotagwork/items/d3b08b10137a0d87416d)
[DBB/zAppBuildについてのメモ - (2)zAppBuildプロパティー・ファイル](https://qiita.com/tomotagwork/items/e6988a708a57d7296350)
[DBB/zAppBuildについてのメモ - (3)zAppBuildビルド・スクリプト](https://qiita.com/tomotagwork/items/f4df3965f62236689584)
[DBB/zAppBuildについてのメモ - (4)Metadata Store構成](https://qiita.com/tomotagwork/items/126907b52c3c8a5ec88d)

# zAppBuild全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/4e5551dd-344d-d1f8-aa05-9b9030e1a2ca.png)

ここでは上の赤字部分に着目してみます。

# ビルド・スクリプトの確認
スクリプトの基本的なフローを大まかに追ってみます。

## build.groovy

build.groovyがzAppBuildが提供する大元のスクリプトで、これがまず最初に実行されます。ここから、必要に応じて各言語ごとのビルド・スクリプトが実行されるという流れになっています。

### 1.initialize

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL32C1-L32C1

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L89

メソッド`initializeBuildProcess`にて必要な変数設定などを行います。

#### 1-(1) parse incoming options and arguments

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL92C13-L92C22

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL210C31-L210C31

ここでは、スクリプト実行時の引数の解析が行われます。引数の解析にはCliBuilderクラスが使用されています。
参考: [Class CliBuilder](https://docs.groovy-lang.org/4.0.3/html/gapi/index.html?groovy/util/CliBuilder.html)

#### 1-(2) populate build properties

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L93

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L300

ここでは、build-confのプロパティー・ファイル、application-confのプロパティー・ファイルをそれぞれ読み込み、スクリプトの引数と合わせてプロパティーの設定を行います。

#### 1-(3) create metadata store for this script

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L107

User Build以外の場合にmetadata storeのセットアップを行います。(User Buildの場合はmetadata storeは使用されない)

#### 1-(4) handle -r,--reset option

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L167

resetオプションが指定された場合、metadata storeから情報を削除します。

#### 1-(5) verify/create/clone the collections for this build

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL204C21-L204C21

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/ImpactUtilities.groovy#L925

metadata store上にCollectionが無ければ作成します。
(UserBuildの場合はMetadata Storeが作成されていないのでCollectionも作成されません。)

### 2.create build list

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL37C13-L37C28

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L485

ここでは、指定したオプションに応じたビルド対象となるプログラムのリストを作成します。
オプション等によってビルド対象のプログラムが変わってきます。例えば、User Buildの場合特定のプログラムをビルドすることになるので、引数で指定したプログラムがビルド対象になりますし、Full Buildの場合は含まれる全てのソースがビルド対象になります(application.propertiesのexcludeFileListに指定されたファイルは除外される)。


https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL50C3-L52C5

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL68C1-L80C2

上のコードは、Full Buildの場合のビルド対象プログラム抽出部分です。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL553C1-L563C3

上のコードで、ビルド対象ソースのファイル名のリストを書き出し(⇒buildList.txt)を行っています。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL578C1-L584C3

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/ImpactUtilities.groovy#L784

上のコードで、fullBuildの場合にソースをスキャンしてcollectionをUpdateしています。


### 3.build programs in the build list

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L39

2.で作成したビルド対象のプログラムのリスト(buildList)に基づき、実際にビルドのスクリプトを実行していきます。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L54

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/samples/MortgageApplication/application-conf/application.properties#L16

application-confのapplication.propertiesで指定したbuildOrderの順番に、ビルド用のスクリプトを実行していきます。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#LL57C21-L57C35

メソッド`ScriptMappings.getMappedList()`を使って、buildListから実行しようとしているスクリプトに該当するプログラムのみ抽出します。たとえばCOBOL用のビルド・スクリプトを実行する際には、buildListからCOBOLソースのみを抽出します。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/build.groovy#L62

メソッド`runScript()`を使用して、各言語ごとのビルド・スクリプト(Cobol.groovyなど)を実行します。

※`ScriptMappings.getMappedList()`、`runScript()`はDBBによって提供されるメソッドです。
参考: [DBB APIs - Build properties](https://www.ibm.com/docs/en/dbb/2.0.0?topic=apis-build-properties)

## Cobol.groovy

ビルド対象のアプリケーションの中にCOBOLのソースが含まれている場合、build.groovyからCobol.groovyが呼び出されることになります。
ここではCOBOL用のビルド・スクリプトであるCobol.groovyの中身を追ってみたいと思います。

### 1.create language datasets

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL22C1-L24C3

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL482C1-L510C2

各言語ごとに必要なPDSデータセットを作成します。例えばソース配置用、ロード・モジュール配置用などです。
ここではDBB提供の`CreatePDS()`というメソッドが使用されています。これは、データセットが存在しない場合にのみ新規で作成されることになります。
参考: [CreatePDS](https://www.ibm.com/docs/en/dbb/2.0.0?topic=apis-zos-commands#createpds)

### 2.sort the build list based on build file rank if provided

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#L27

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL227C1-L263C2

ここでは、1で作成されたビルド対象ソースのリストについて、ランクに応じてソートします(ランクはプロパティー`cobol_fileBuildRank`で指定されます)。
`TreeMap`オブジェクトでランクごとのファイルのリストを保持するようにしていますが、TreeMapに追加された値は内部で自動的に昇順ソートされます。
つまり、ランクの数値が低いソースほど優先度が高くなります。ランク付けされていないファイルはリストの最後にAppendされますので優先度は最下位となります。


### 3.iterate through build list

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#L34

ここがソースをビルドする本体部分となります。以下のビルド処理を対象のソース・ファイルごとに実行することになります。

#### 3-(1) configure dependency resolution

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL41C2-L43C3

ソースと直接的な依存関係を持つファイル(COPYBOOKなど)を調べるためのResolverを作成します。

参考: [How to manage build dependencies](https://www.ibm.com/docs/en/dbb/2.0.0?topic=apis-dependency-impact-resolution)

#### 3-(2) copy build file and dependency files to data sets

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL45C1-L50C3

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL94C3-L94C3

ターゲットのソースと、そのソースに直接的に依存関係のあるファイル(COPYBOOKなど)をzFSからPDSにコピーします。

VS CodeによるUserBuildの場合は、VS Code側で対象ソースの依存関係をサーチしてそのリストを作成し、それを引数で渡した上でzAppBuildを呼び出します。そのため、その受け渡されたファイル(userBuildDependencyFile)から依存関係のあるファイルを判別して、PDSにコピーすることになります。
FullBuildの場合は、各対象のソースごとにDBB提供のDependency Scanner機能を使ってソースをサーチして依存関係のあるファイル(COPYBOOKなど)を判別し、PDSにコピーすることになります。

PDSへのコピーは、DBB提供のCopyToPDSクラスが使用されます。

参考: [z/OS commands](https://www.ibm.com/docs/en/dbb/2.0.0?topic=apis-zos-commands)

#### 3-(3) Get logical file

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL53C77-L53C86

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BuildUtilities.groovy#LL314C1-L328C2

コンパイル対象のソースについてのLogicalFileを生成します。LogicalFileというのは、そのソースファイルの属性情報を以下のような構造で保持しているオブジェクトです。言語、ファイルパス、依存関係のあるファイル、などの情報を含みます。

```json:LogicalFile構造サンプル
{
   "cics": false,
   "dli": false,
   "file": "ISEConf2023_MySampleDBB01\/cobol\/TSUB03.cbl",
   "language": "COB",
   "lname": "TSUB03",
   "logicalDependencies": [
      {
         "category": "COPY",
         "library": "SYSLIB",
         "lname": "CPPARM03"
      }
   ],
   "mq": false,
   "sql": false
}
```

#### 3-(4) create mvs commands

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL55C1-L61C83

コンパイル対象のソースをPDSにコピーし、コンパイル用、および、リンク・エディット用のコマンド(JCLステップ相当)を生成します。

コンパイル・コマンドの生成

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#L174

リンク・エディット・コマンド生成

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL284C1-L284C1

※コンパイル・オプションについて
コンパイル・コマンド生成の中では、以下の関数でCOBOLのコンパイル・オプションがセットされます。

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL143C5-L143C21

ターゲットのソースがCICSアプリ(isCICSがtrue)の場合はCICS用のオプションが追加され、SQLを含むアプリ(isSQLがtrue)の場合はSQL用のオプションが追加されます。
つまり、CICS提供のトランスレーターやDb2提供のプリコンパイラを使う構成になっている訳ではなく、言語環境提供の統合トランスレーターが使われることになります。

#### 3-(5) execute mvs commands in a mvs job

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL63C1-L65C13

JOBを開始します。以降のステップを1つのJOBとして実行します。

#### 3-(6) compile the cobol program

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL67C1-L69C80

先に生成したコンパイル・コマンドを実行します。

#### 3-(7) link/edit

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL91C1-L92C79

リンク・エディット対象のソースの場合、コンパイルに続けてリンク・エディット・コマンドを実行します。
(他のモジュールに静的リンクしたいソースについては、cobol_linkEditプロパティーでリンク対象外として設定しておくことで、リンク・エディットのステップをスキップできます)

#### 3-(8) perform Db2 Bind only on User Build and perfromBindPackage property

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL112C1-L127C3

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/utilities/BindUtilities.groovy#L14

Db2バインド処理対象のものについてはバインド処理を行います。

#### 3-(9) clean up passed DD statements

https://github.com/IBM/dbb-zappbuild/blob/5a649f0a591625be0bfe39dd880ef1d43ba8272f/languages/Cobol.groovy#LL129C1-L130C12

JOBの終了処理を行います。ここまでのステップが1つのJOBとして実行されることになります。