KAGURA実験室

KAGURA開発者の個人ブログ

Azure Pipelinesでzlibをマルチプラットフォームに自動ビルドする

KAGURAの自動ビルドをAzure Pipelinesで実現できるかどうか、検討しています。前回は、CMakeを使ってC++のコードを複数環境向け(UbuntuWindowsmacOS)にビルドできることまで確認しました。

複数のエージェントがMicrosoftによって用意されていて、設定ファイルを変更するだけで、ビルド環境を変えることができましたが、ビルドのたびに設定ファイルを書き換えるわけにはいかないので、一度に複数の環境でビルドを走らせてほしいです。

f:id:nkshigeru:20190125133515p:plain

今回は、zlibをビルドしてみます。なぜzlibかというと、KAGURAでも使用しているライブラリで、CMakeに対応し、比較的小さいライブラリであり、zlibほど多くの人に使われているライブラリのビルドが通らないなんてことは考えにくいからです。

ローカルでビルド

まずは、ローカルのUbuntu(WSL)環境でビルドできることを確認しておきます。ビルド手順はこのような流れになります。

  1. zlibソースコードのダウンロード
  2. ダウンロードファイルのチェック
  3. ファイルの展開
  4. CMakeの実行
  5. ビルド
  6. テスト
  7. インストール

Bash上で、次のようなコマンドを実行します。

# Download
curl -sLO https://www.zlib.net/zlib-1.2.11.tar.gz

# Verify SHA256
echo "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 *zlib-1.2.11.tar.gz" | shasum -a 256 --check 

# Extract
tar -xvf zlib-1.2.11.tar.gz

mkdir build
cd build
# Run CMake
cmake -DCMAKE_INSTALL_PREFIX=../dist ../zlib-1.2.11

# Build
cmake --build ./ --config Release

# Test
ctest --build-config Release

# Install
cmake --build ./ --config Release --target install

成功するとdistフォルダにビルド結果が出力されています。

dist
├── include
│   ├── zconf.h
│   └── zlib.h
├── lib
│   ├── libz.a
│   ├── libz.so -> libz.so.1
│   ├── libz.so.1 -> libz.so.1.2.11
│   └── libz.so.1.2.11
└── share
    ├── man
    │   └── man3
    │       └── zlib.3
    └── pkgconfig
        └── zlib.pc

Azure Pipelinesでビルド

上と同じことを実行するAzure Pipelinesの設定ファイルはこのようになります。

# azure-pipelines.yml
trigger:
- master

pool:
  vmImage: 'ubuntu-16.04'
  #vmImage: 'vs2017-win2016'
  #vmImage: 'macOS-10.13'

steps:
- script: |
    curl -sLO https://www.zlib.net/zlib-1.2.11.tar.gz
    echo "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 *zlib-1.2.11.tar.gz" | shasum -a 256 --check 
    tar -xvf zlib-1.2.11.tar.gz
  displayName: Download zlib

- task: CMake@1
  inputs:
    cmakeArgs: >
      -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory)
      $(Build.SourcesDirectory)/zlib-1.2.11

- task: CMake@1
  inputs:
    cmakeArgs: >
      --build ./
      --config Release

- script: ctest --build-config Release
  workingDirectory: build
  displayName: Test

- task: CMake@1
  inputs:
    cmakeArgs: >
      --build ./
      --config Release
      --target install

- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: $(Build.ArtifactStagingDirectory)
    artifactName: zlib-1.2.11

これを実行すると、できました!

f:id:nkshigeru:20190124230625p:plain
Ubuntu環境のビルド結果

さて、Windows環境でビルドを実行するには、設定ファイルのvmImagevs2017-win2016変更するだけ・・・と言いたいところですが、問題が発生しました。 f:id:nkshigeru:20190125012145p:plain

shasumコマンドなんて無いと。そりゃそうです、Windowsなんだもの。その前のcurlが通っていることのほうがびっくりです。

そこで、PowerShellを使ってみます。 curlInvoke-WebRequestに置き換えます。PowerShellにおけるcurlInvoke-WebRequestエイリアスであり、bashcurlとは挙動が違うので、そのまま使えません。shasumGet-FileHashに置き換え。tarはそのまま使えます。

# PowerShell
Invoke-WebRequest -Uri https://www.zlib.net/zlib-1.2.11.tar.gz -O zlib-1.2.11.tar.gz
if ((Get-FileHash zlib-1.2.11.tar.gz -Algorithm SHA256).Hash -ne "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1") {
    exit 1
}
tar -xvf zlib-1.2.11.tar.gz

azure-pipelines.ymlに組み込みます。variablesで変数を定義し、少し整理しました。

# azure-pipelines.yml  (変更)
variables:
  DOWNLOAD_URL: https://www.zlib.net/zlib-1.2.11.tar.gz
  DOWNLOAD_FILE: zlib-1.2.11.tar.gz
  DOWNLOAD_SHA256: c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 

- powershell: |
    Invoke-WebRequest -Uri $env:DOWNLOAD_URL -O $env:DOWNLOAD_FILE
    if ((Get-FileHash $env:DOWNLOAD_FILE -Algorithm SHA256).Hash -ne $env:DOWNLOAD_SHA256) {
      exit 1
    }
    tar -xvf $env:DOWNLOAD_FILE
  displayName: Download zlib

Windowsでもビルドできました!

そして、なんと同じ設定でUbuntuでもmacOSでもビルドできました!!PowerShellは今やUbuntumacOSでも使えるのです。

複数環境で一括ビルド

ここからが今日の本題です。vmImageを毎回書き換えずに、複数環境のビルドを実行するにはどうしたらいいでしょうか。

f:id:nkshigeru:20190125140440p:plain

パイプラインは1つ以上のジョブで構成されています。ジョブは1つ以上のステップで構成されます。ここではじめてジョブというものが出てきましたが、これまでのシンプルなパイプラインではジョブが1つしかないため、ジョブの記述を省略できていたのでした。

# azure-pipelines.yml
trigger:
- master

jobs:
  - job: 'ubuntu1604'
    pool: 
      vmImage: 'ubuntu-16.04'
    steps:
      - script: echo Ubuntu-16.04

  - job: 'win2016_vs2017'
    pool: 
      vmImage: 'vs2017-win2016'
    steps:
      - script: echo vs2017-win2016

  - job: 'macos1013'
    pool: 
      vmImage: 'macOS-10.13'
    steps:
      - script: echo macOS-10.13

このように、ジョブごとに異なるvmImageを設定することができます。

ビルドステップは共通化してあるので、別のymlファイルに切り出します。

# build-zlib.yml
steps:
- powershell: |
    Invoke-WebRequest -Uri $env:DOWNLOAD_URL -O $env:DOWNLOAD_FILE
    if ((Get-FileHash $env:DOWNLOAD_FILE -Algorithm SHA256).Hash -ne $env:DOWNLOAD_SHA256) {
      exit 1
    }
    tar -xvf $env:DOWNLOAD_FILE
  displayName: Download zlib

- task: CMake@1
  inputs:
    cmakeArgs: >
      -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory)
      $(Build.SourcesDirectory)/zlib-1.2.11

- task: CMake@1
  inputs:
    cmakeArgs: >
      --build ./
      --config Release

- script: ctest --build-config Release
  workingDirectory: build
  displayName: Test

- task: CMake@1
  inputs:
    cmakeArgs: >
      --build ./
      --config Release
      --target install

- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: $(Build.ArtifactStagingDirectory)
    artifactName: zlib-1.2.11_$(Agent.OS)

このbuild-zlib.ymlをテンプレートとして各ジョブで読み込みます。

# azure-pipelines.yml
trigger:
- master

variables:
  DOWNLOAD_URL: https://www.zlib.net/zlib-1.2.11.tar.gz
  DOWNLOAD_FILE: zlib-1.2.11.tar.gz
  DOWNLOAD_SHA256: c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 

jobs:
  - job: 'ubuntu1604'
    pool: 
      vmImage: 'ubuntu-16.04'
    steps:
      - template: build-zlib.yml

  - job: 'win2016_vs2017'
    pool: 
      vmImage: 'vs2017-win2016'
    steps:
      - template: build-zlib.yml

  - job: 'macos1013'
    pool: 
      vmImage: 'macOS-10.13'
    steps:
      - template: build-zlib.yml

できました! f:id:nkshigeru:20190125001805p:plain

まとめ

  • Azure Pipelineでzlibをビルドすることができました。この調子で外部ライブラリをビルドすることができそうです。
  • 複数環境で共通の処理はPowerShellを使うとよさそうです。
  • ジョブを複数使って、複数環境のビルドを一度に行うことができました。

外部ライブラリのビルドができるようになったので、次回は、ビルド済みの外部ライブラリを本体のビルドで読み込むにはどうしたらいいのか調べてみたいと思います。