Binary distributions

これらのノートは、さまざまなプラットフォームで配布するためのJuliaのバイナリディストリビューションをコンパイルしたい人々のためのものです。私たちは、ユーザーができるだけ広くJuliaを広め、できるだけ多くのオペレーティングシステムやハードウェア構成で試してみることを愛しています。各プラットフォームには、ポータブルで動作するJuliaディストリビューションを作成するために従うべき特定の注意点やプロセスがあるため、ほとんどのノートをOSごとに分けています。

注意してください。Juliaのコードは MIT-licensed, with a few exceptions ですが、ここで説明されている技術によって作成された配布物はGPLライセンスになります。これは、SuiteSparseなどのさまざまな依存ライブラリがGPLライセンスであるためです。将来的には非GPLのJulia配布物を持つことを期待しています。

Versioning and Git

Makefileは、VERSIONファイルとgitリポジトリからのコミットハッシュおよびタグの両方を使用して、スプラッシュスクリーンとversioninfo()出力を埋めるために使用する情報を含むbase/version_git.jlを生成します。何らかの理由でビルド時にgitリポジトリを利用したくない場合は、次のコマンドでbase/version_git.jlファイルを事前に生成する必要があります。

make -C base version_git.jl.phony

Juliaには、多くのビルド依存関係があり、人気のあるパッケージマネージャーにまだ含まれていないパッチ版を使用しています。これらの依存関係は通常、ビルド時に自動的にダウンロードされますが、インターネットに接続されていないコンピュータでJuliaをビルドできるようにするには、特別なmakeターゲットを使用してフルソースディストリビューションアーカイブを作成する必要があります。

make full-source-dist

それは、すべての必要な依存関係を含む julia-version-commit.tar.gz アーカイブを作成します。

タグ付きリリースをgitリポジトリでコンパイルする際、スプラッシュスクリーンにブランチ/コミットハッシュ情報は表示しません。この行を使用して、最大45文字のリリース説明を表示できます。この行を設定するには、Make.userファイルを作成する必要があります。

override TAGGED_RELEASE_BANNER = "my-package-repository build"

Target Architectures

デフォルトでは、Juliaはビルドマシンのネイティブアーキテクチャに最適化されたシステムイメージを生成します。これは通常、パッケージをビルドする際には望ましくなく、互換性のないCPU(特に、より制限された命令セットを持つ古いCPU)を持つ任意のマシンでJuliaが起動に失敗する原因となります。

したがって、makeを呼び出す際にMARCH変数を渡し、サポートする予定のベースラインターゲットに設定することをお勧めします。これにより、Julia実行可能ファイルとライブラリ、システムイメージのターゲットCPUが決まります(後者はJULIA_CPU_TARGETを使用して設定することもできます)。x86 CPUにとって通常有用な値は、x86-64およびcore2(64ビットビルド用)とpentium4(32ビットビルド用)です。残念ながら、Pentium 4より古いCPUは現在サポートされていません(this issueを参照してください)。

LLVMがサポートするCPUターゲットの完全なリストは、llc -mattr=helpを実行することで取得できます。

Linux

Linuxでは、make binary-distを実行すると、完全に機能するJuliaインストールを含むtarballが作成されます。.deb.rpmのような配布パッケージを作成したい場合は、追加の作業が必要です。DebianおよびUbuntuベースのシステム用の.debパッケージを作成するために必要なメタデータの例については、julia-debianリポジトリを参照してください。RPMベースのディストリビューションについては、Fedora packageを参照してください。まだ実験はしていませんが、Alienを使用して、さまざまなLinuxディストリビューション用のJuliaパッケージを生成することができるかもしれません。

Juliaは、makeおよびmake installを呼び出す際に渡すことができるprefixやその他の環境変数を介して標準のインストールディレクトリを上書きすることをサポートしています。これらのリストはMake.incに記載されています。DESTDIRを使用することで、一時ディレクトリへのインストールを強制することもできます。

デフォルトでは、Juliaはインストール全体の初期化ファイルとして$prefix/etc/julia/startup.jlを読み込みます。このファイルは、配布管理者がカスタムパスや初期化コードを設定するために使用できます。Linuxの配布パッケージの場合、$prefix/usrに設定されていると、調べるべき/usr/etcは存在しません。これにより、Juliaのプライベートetcディレクトリへのパスを変更する必要があります。これは、ビルド時にsysconfdirメイク変数を介して行うことができます。ビルド時にmakesysconfdir=/etcを渡すだけで、Juliaは最初に/etc/julia/startup.jlをチェックし、その後に$prefix/etc/julia/startup.jlを試みます。

OS X

OSXでバイナリ配布を作成するには、まずJuliaをビルドし、その後contrib/mac/appに移動して、Julia本体をビルドする際に使用したのと同じmakevarsでmakeを実行します。これにより、完全に自己完結したJulia.appを含む.dmgファイルがcontrib/mac/appディレクトリに作成されます。

代わりに、Juliaはmakedarwinframeworkターゲットで呼び出し、DARWIN_FRAMEWORK=1を設定することでフレームワークとしてビルドできます。例えば、make DARWIN_FRAMEWORK=1 darwinframework

Windows

Windows上でのJuliaディストリビューションの作成に関する手順は、build devdocs for Windowsに記載されています。

Notes on BLAS and LAPACK

JuliaはデフォルトでOpenBLASをビルドし、BLASおよびLAPACKライブラリを含みます。32ビットアーキテクチャでは、Juliaは32ビット整数を使用するようにOpenBLASをビルドし、64ビットアーキテクチャでは64ビット整数(ILP64)を使用するようにOpenBLASをビルドします。BLASおよびLAPACK APIルーチンを呼び出すすべてのJulia関数が正しい幅の整数を使用することが重要です。

ほとんどのBLASおよびLAPACKの配布物はLinuxディストリビューションで提供されており、商用実装でも32ビットAPIを使用するライブラリが出荷されています。多くの場合、64ビットAPIは別のライブラリとして提供されています。

ベンダー提供またはOS提供のライブラリを使用する際、Juliaビルドの一部としてUSE_BLAS64というmakeオプションが利用可能です。make USE_BLAS64=0を実行すると、Juliaは64ビットアーキテクチャ上でもすべての整数が32ビット幅であると仮定して、32ビットAPIを前提にBLASおよびLAPACKを呼び出します。

他のライブラリ、例えばSuiteSparseも内部でBLASとLAPACKを使用しています。APIは、BLASとLAPACKに依存するすべてのライブラリで一貫性を保つ必要があります。Juliaのビルドプロセスは、これらのライブラリを正しくビルドしますが、デフォルトをオーバーライドしてシステム提供のライブラリを使用する場合、この一貫性を確保する必要があります。

また、Linuxディストリビューションは、マルチスレッドを有効にしたバージョンと、シリアル方式でのみ動作するバージョンのいくつかを出荷することがあります。たとえば、Fedoraでは、libopenblasp.soはスレッド対応ですが、libopenblas.soはそうではありません。最適なパフォーマンスを得るためには、前者を使用することをお勧めします。デフォルトのlibopenblas.soとは異なる名前のOpenBLASライブラリを選択するには、makeLIBBLAS=-l$(YOURBLAS)およびLIBBLASNAME=lib$(YOURBLAS)を渡し、$(YOURBLAS)をライブラリの名前に置き換えます。また、バージョンなしの.soシンボリックリンクを必要とせずにパッケージを動作させたい場合は、ライブラリの名前に.so.0を追加することもできます。

最後に、OpenBLASは独自の最適化されたLAPACKバージョンを含んでいます。USE_SYSTEM_BLAS=1およびUSE_SYSTEM_LAPACK=1を設定した場合は、LIBLAPACK=-l$(YOURBLAS)およびLIBLAPACKNAME=lib$(YOURBLAS)も設定する必要があります。そうしないと、参照LAPACKが使用され、パフォーマンスは通常はるかに低くなります。

Julia 1.7以降、Juliaはlibblastrampolineを使用して、実行時に異なるBLASを選択します。

Point releasing 101

ポイント/パッチリリースの作成は、いくつかの異なるステップで構成されています。

Backporting commits

いくつかのプルリクエストには「backport pending x.y」というラベルが付けられています。例えば、「backport pending 0.6」です。これは、release-x.yブランチからタグ付けされた次のリリースに、そのプルリクエストのコミットが含まれるべきであることを示しています。プルリクエストがマスターにマージされると、各コミットは cherry picked という専用のブランチに移され、最終的にrelease-x.yにマージされることになります。

Creating a backports branch

まず、release-x.yに基づいて新しいブランチを作成します。Juliaのブランチの一般的な規則は、個人用のブランチである場合、ブランチ名の先頭にイニシャルを付けることです。例として、ブランチの作成者がジェーン・スミスであるとしましょう。

git fetch origin
git checkout release-x.y
git rebase origin/release-x.y
git checkout -b js/backport-x.y

これにより、新しいブランチを作成する前に、リリース-x.yのローカルコピーがoriginと最新の状態であることが保証されます。

Cherry picking commits

実際のバックポート作業を行います。「backport pending x.y」というラベルが付けられたすべてのマージされたプルリクエストをGitHubのウェブUIで見つけます。これらの各プルリクエストの下部にスクロールし、「someperson merged commit 123abc into master XX minutes ago」と表示されている部分を確認します。コミット名はリンクになっているので、クリックするとコミットの内容が表示されます。このページで123abcがマージコミットである場合は、PRページに戻ります。マージコミットは不要で、実際のコミットが必要です。しかし、これがマージコミットでない場合は、PRがスクワッシュマージされたことを意味します。その場合は、このページに表示されているコミットの横にあるgit SHAを使用します。

コミットのSHAを取得したら、それをバックポート用のブランチにチェリーピックします:

git cherry-pick -x -e <sha>

手動で解決する必要がある競合が発生する場合があります。競合が解決されたら(該当する場合)、コミットメッセージの本文にそのコミットを導入したGitHubプルリクエストへの参照を追加してください。

すべての関連するコミットがバックポートブランチにあることを確認したら、そのブランチをGitHubにプッシュします。

Checking for performance regressions

ポイントリリースは決してパフォーマンスの低下を引き起こすべきではありません。幸いなことに、JuliaのベンチマークボットであるNanosoldierは、マスターだけでなく任意のブランチに対してベンチマークを実行できます。この場合、js/backport-x.yのベンチマーク結果をrelease-x.yと比較したいと思います。これを行うには、バックポートのプルリクエストにコメントをしてNanosoldierをロボットの眠りから目覚めさせます:

@nanosoldier `runbenchmarks(ALL, vs=":release-x.y")`

これにより、release-x.yおよびjs/backport-x.yで登録されたすべてのベンチマークが実行され、結果の要約が生成され、すべての改善点と後退がマークされます。

Nanosoldierが何らかの回帰を見つけた場合は、ローカルで確認し、必要に応じてNanosoldierを再実行してください。回帰が単なるノイズではなく実際のものであると判断された場合は、それを修正するためのマスターブランチのコミットを見つけてバックポートする必要があります。もし存在しない場合は、回帰の原因を特定し、マスターブランチにパッチを提出する(またはコードを知っている誰かにパッチを提出してもらう)必要があります。その後、マージされたらコミットをバックポートしてください。(または、適切であればバックポートブランチに直接パッチを提出してください。)

Building test binaries

バックポートPRがrelease-x.yブランチにマージされた後、ローカルのJuliaクローンを更新し、次のコマンドを使用してブランチのSHAを取得します。

git rev-parse origin/release-x.y

それを手元に置いておいてください。これは、buildbot UIの「Revision」フィールドに入力する内容です。

今のところ、PackageEvaluatorを実行するために使用されるのはLinux x86-64のバイナリだけです。https://buildog.julialang.orgにアクセスし、nuke_linux64のジョブを提出し、その後、SHAをリビジョンとして指定してpackage_linux64のジョブをキューに追加します。パッケージングジョブが完了すると、バイナリがAWSのjulialang2バケットにアップロードされます。URLを取得してください。これはPackageEvaluatorで使用されます。

Checking for package breakages

ポイントリリースは、パッケージを壊すべきではありません。ユーザー向けではないBaseの内部を使って深刻に疑わしいハックを行っているパッケージを除いては。(その場合は、パッケージの作者と話をすることをお勧めします。)

変更が今後の新しいバージョンでパッケージを壊すかどうかを確認するには、PackageEvaluatorを使用することができます。これは一般に「PkgEval」と呼ばれています。PkgEvalは、GitHubリポジトリやpkg.julialang.orgのステータスバッジを生成します。通常、Nanosoldierのベンチマークを行わないノードの1つで実行され、Vagrantを使用して、別々の並列VirtualBox仮想マシンでその任務を遂行します。

Setting up PackageEvaluator

パッケージ評価者をクローンし、backport-x.y.zというブランチを作成してチェックアウトしてください。必要な変更は少しハッキーで混乱を招くものであり、将来的にはパッケージ評価者のバージョンで対処されることを期待しています。行うべき変更は、this commitをモデルにします。

セットアップスクリプトは、最初の引数を実行するJuliaのバージョンとして、2番目の引数をパッケージ名の範囲(A-Kの場合はAK、L-Zの場合はLZ)として受け取ります。基本的なアイデアは、現在のx.yリリースとバックポートバージョンの2つのJuliaバージョンのみを実行し、それぞれに3つのパッケージ範囲を設定することです。

リンクされた差分では、2番目の引数がLZの場合は、バックポートブランチからビルドされたバイナリを使用し、それ以外の場合(AK)はリリースバイナリを使用することを示しています。次に、最初の引数を使用してパッケージリストのセクションを実行します:入力0.4の場合はA-F、0.5の場合はG-N、0.6の場合はO-Zです。

Running PackageEvaluator

PkgEvalを実行するには、十分な性能を持つマシン(例えばNanosoldierノード1)を見つけて、次のコマンドを実行します。

git clone https://github.com/JuliaCI/PackageEvaluator.jl.git
cd PackageEvaluator.jl/scripts
git checkout backport-x.y.z
./runvagrant.sh

このスクリプトは、scripts/ ディレクトリにいくつかのフォルダーを生成します。フォルダー名とその内容は以下にデコードされています:

Folder nameJulia versionPackage range
0.4AKReleaseA-F
0.4LZBackportA-F
0.5AKReleaseG-N
0.5LZBackportG-N
0.6AKReleaseO-Z
0.6LZBackportO-Z

Investigating results

それが完了したら、同じディレクトリから ./summary.sh を使用して、調査結果の要約レポートを作成できます。各フォルダーについてこれを行い、バージョンごとの全体的な結果を集約します。

./summary.sh 0.4AK/*.json > summary_release.txt
./summary.sh 0.5AK/*.json >> summary_release.txt
./summary.sh 0.6AK/*.json >> summary_release.txt
./summary.sh 0.4LZ/*.json > summary_backport.txt
./summary.sh 0.5LZ/*.json >> summary_backport.txt
./summary.sh 0.6LZ/*.json >> summary_backport.txt

現在、summary_release.txtsummary_backport.txt の2つのファイルがあり、それぞれのバージョンに対する各パッケージのPackageEvaluatorテスト結果(合格/不合格)が含まれています。

これらをJuliaに取り込むのを簡単にするために、CSVファイルに変換し、その後DataFramesパッケージを使用して結果を処理します。CSVに変換するには、各.txtファイルを対応する.csvファイルにコピーし、次にVimを開いてggVGI"<esc>を実行し、次に:%s/\.json /",/gを入力します。(Vimを使用する必要はありません。これは単なる一つの方法です。)次に、以下のようなJuliaコードを使用して結果を処理します。

using DataFrames

release = readtable("summary_release.csv", header=false, names=[:package, :release])
backport = readtable("summary_backport.csv", header=false, names=[:package, :backport])

results = join(release, backport, on=:package, kind=:outer)

for result in eachrow(results)
    a = result[:release]
    b = result[:backport]
    if (isna(a) && !isna(b)) || (isna(b) && !isna(a))
        color = :yellow
    elseif a != b && occursin("pass", b)
        color = :green
    elseif a != b
        color = :red
    else
        continue
    end
    printstyled(result[:package], ": Release ", a, " -> Backport ", b, "\n", color=color)
end

これは stdout に色分けされた行を書き込みます。赤い行は潜在的な破損を示すため、調査する必要があります。黄色の行は、あるバージョンでは動作したが別のバージョンでは何らかの理由で動作しなかったことを意味するため、確認する必要があります。バックポートされたブランチが破損を引き起こしていることがわかった場合は、git bisect を使用して問題のあるコミットを特定し、git revert でそれらのコミットを元に戻し、プロセスを繰り返してください。

Merging backports into the release branch

その後、あなたが確認したら

  • バックポートされたコミットは、Juliaのすべてのユニットテストを通過します。
  • リリースブランチと比較して、バックポートされたコミットによってパフォーマンスの後退は導入されていません。
  • バックポートされたコミットは、登録されたパッケージに影響を与えません。

その後、バックポートブランチはリリース-x.yにマージする準備が整いました。マージが完了したら、バックポートされたコミットを含むすべてのプルリクエストから「backport pending x.y」ラベルを削除してください。バックポートされていないPRからはラベルを削除しないでください。

release-x.y ブランチにはすべての新しいコミットが含まれているはずです。ブランチに対して行いたい最後のことは、バージョン番号を調整することです。これを行うには、VERSION ファイルを編集してバージョン番号から -pre を削除する PR を release-x.y に提出します。それがマージされたら、タグ付けの準備が整います。

Tagging the release

今がその時です!release-x.y ブランチをチェックアウトし、ローカルのブランチがリモートブランチと最新の状態であることを確認してください。コマンドラインで、次のコマンドを実行します。

git tag v$(cat VERSION)
git push --tags

これにより、タグがローカルで作成され、GitHubにプッシュされます。

リリースにタグを付けた後、patch番号を上げ、末尾に-preを追加するためにrelease-x.yに別のPRを提出してください。これは、ブランチの状態がx.yシリーズの次のポイントリリースのプレリリースバージョンを反映していることを示します。

Makefileの残りの指示に従ってください。

Signing binaries

これらのステップのいくつかは、安全なパスワードを必要とします。適切なパスワードを取得するには、Elliot Saba (staticfloat) または Alex Arslan (ararslan) に連絡してください。各プラットフォームのコード署名は、そのプラットフォーム上で実行する必要があることに注意してください(例:Windowsの署名はWindows上で行う必要があります)。

Linux

コード署名はLinuxで手動で行う必要がありますが、非常に簡単です。まず、juliasecure AWSバケットのCodeSigningフォルダーからファイルjulia.keyを取得します。次に、以下のコマンドを使用してこれをGnuPGキーチェーンに追加します。

gpg --import julia.key

この操作には、ElliotまたはAlexから取得する必要があるパスワードの入力が必要です。次に、キーの信頼レベルを最大に設定します。まず、gpgセッションに入ります:

gpg --edit-key julia

プロンプトで trust と入力し、信頼レベルを尋ねられたら、利用可能な最大値(おそらく5)を提供します。GnuPGを終了します。

今、ビルドボットでビルドされた各Linuxターボールについて、入力してください。

gpg -u julia --armor --detach-sig julia-x.y.z-linux-<arch>.tar.gz

これにより、各tarballに対応する.ascファイルが生成されます。それだけです!

macOS

コード署名は、macOSビルドボットで自動的に行われるべきです。しかし、それが成功したことを確認することが重要です。macOSを実行しているシステムまたは仮想マシンで、ビルドボットでビルドされた.dmgファイルをダウンロードします。例として、.dmgファイルの名前がjulia-x.y.z-osx.dmgだとしましょう。次のコマンドを実行します。

mkdir ./jlmnt
hdiutil mount -readonly -mountpoint ./jlmnt julia-x.y.z-osx.dmg
codesign -v jlmnt/Julia-x.y.app

マウント時に表示されるマウントされたディスクの名前を必ずメモしてください!例として、これが disk3 であると仮定します。コード署名の検証が成功した場合、codesign ステップからの出力はありません。実際に成功した場合は、.dmg を今すぐ取り外すことができます:

hdiutil eject /dev/disk3
rm -rf ./jlmnt

メッセージのようなものを受け取った場合

Julia-x.y.app: コードオブジェクトは全く署名されていません

その場合は手動で署名する必要があります。

手動で署名するには、まずAWSのjuliasecureバケット内のCodeSigningフォルダーからOS X証明書を取得します。Keychain.appを使用して.p12ファイルをキーチェーンに追加します。キーのパスワードについては、Elliot Saba(staticfloat)またはAlex Arslan(ararslan)に問い合わせてください。次に、実行します。

hdiutil convert julia-x.y.z-osx.dmg -format UDRW -o julia-x.y.z-osx_writable.dmg
mkdir ./jlmnt
hdiutil mount -mountpoint julia-x.y.z-osx_writable.dmg
codesign -s "AFB379C0B4CBD9DB9A762797FC2AB5460A2B0DBE" --deep jlmnt/Julia-x.y.app

これは「のようなメッセージで失敗する可能性があります」

Julia-x.y.app: リソースフォーク、Finder情報、または同様の不要物は許可されていません

その場合、余分な属性を削除する必要があります:

xattr -cr jlmnt/Julia-x.y.app

その後、コード署名を再試行してください。それでエラーが発生しない場合は、検証を再試行してください。すべてが正常であれば、書き込み可能な.dmgをアンマウントし、再び読み取り専用に変換してください:

hdiutil eject /dev/disk3
rm -rf ./jlmnt
hdiutil convert julia-x.y.z-osx_writable.dmg -format UDZO -o julia-x.y.z-osx_fixed.dmg

結果の.dmgが実際に修正されていることをダブルクリックして確認してください。すべてが問題なければ、イジェクトしてから名前から_fixedサフィックスを削除します。それで終わりです!

Windows

署名はWindows上で手動で行う必要があります。まず、Microsoftのウェブサイトから必要な署名ユーティリティを含むWindows 10 SDKを取得します。SignToolユーティリティが必要で、これはC:\Program Files (x86)\Windows Kits\10\App Certification Kitのような場所にインストールされているはずです。juliasecureのCodeSigningからWindows証明書ファイルを取得し、実行可能ファイルと同じディレクトリに置きます。Windows CMDウィンドウを開き、すべてのファイルがある場所にcdし、次のコマンドを実行します。

set PATH=%PATH%;C:\Program Files (x86)\Windows Kits\10\App Certification Kit;
signtool sign /f julia-windows-code-sign_2017.p12 /p "PASSWORD" ^
   /t http://timestamp.verisign.com/scripts/timstamp.dll ^
   /v julia-x.y.z-win32.exe

^ は Windows CMD における行継続文字であり、PASSWORD はこの証明書のパスワードのプレースホルダーです。いつものように、パスワードについてはエリオットまたはアレックスに連絡してください。エラーがなければ、すべて問題ありません!

Uploading binaries

すべての署名が完了したので、バイナリをAWSにアップロードする必要があります。Cyberduckのようなプログラムやawsコマンドラインユーティリティを使用できます。バイナリは適切なフォルダーにjulialang2バケットに配置する必要があります。たとえば、Linux x86-64はjulialang2/bin/linux/x.yに配置します。現在のjulia-x.y-latest-linux-<arch>.tar.gzファイルを削除し、julia-x.y.z-linux-<arch>.tar.gzの複製に置き換えることを忘れないでください。

私たちは、ビルドしたすべてのもの、ソースのtarballやすべてのリリースバイナリを含むチェックサムをアップロードする必要があります。これは簡単です:

shasum -a 256 julia-x.y.z* | grep -v -e sha256 -e md5 -e asc > julia-x.y.z.sha256
md5sum julia-x.y.z* | grep -v -e sha256 -e md5 -e asc > julia-x.y.z.md5

macOSでこれらのコマンドを実行している場合、出力がわずかに異なることに注意してください。既存のファイルを参照することで再フォーマットできます。Macユーザーはmd5sumの代わりにmd5 -rを使用する必要があります。.md5および.sha256ファイルをAWSのjulialang2/bin/checksumsにアップロードしてください。

AWSにアップロードされたすべてのファイルの権限が「全員: 読み取り」に設定されていることを確認してください。

アップロードした各ファイルについて、ウェブサイトのリンクが更新されたファイルを指すように、Fastlyキャッシュを削除する必要があります。例として:

curl -X PURGE https://julialang-s3.julialang.org/bin/checksums/julia-x.y.z.sha256

時々これは必要ではありませんが、やっておくのは良いことです。