packaging - Tokyo-NixOS/Tokyo-NixOS-Meetup-Wiki GitHub Wiki

パッケヌゞ䜜成

Nixのパッケヌゞずは

パッケヌゞはNix Expressionで定矩されたす。
Nix Expressionはパッケヌゞを䜜るレシピずも考えられたす。
パッケヌゞをパッケヌゞレポゞトリnixpkgsか単独ファむルで管理できたす。

パッケヌゞの䟋

では早速パッケヌゞを定矩するNix Expressionを確認したしょう。

{ stdenv, fetchurl }:

stdenv.mkDerivation {
  name = "hello-2.10";

  src = fetchurl {
    url = "mirror://gnu/hello/hello-2.10.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };

  meta = {
    description = "A program that produces a familiar, friendly greeting";
    longDescription = ''
      GNU Hello is a program that prints "Hello, world!" when you run it.
      It is fully customizable.
    '';
    homepage = http://www.gnu.org/software/hello/manual/;
    license = stdenv.lib.licenses.gpl3Plus;
    maintainers = [ stdenv.lib.maintainers.eelco ];
    platforms = stdenv.lib.platforms.all;
  };
}

Nix蚀語に慣れおいないずかなりわかりにくいですね。 ここで倧事なポむントはパッケヌゞ定矩は関数であるこずです。

行ごずを確認したしょう、たずは

{ stdenv, fetchurl }:

Nix蚀語の関数の曞き方です、{ず}に囲たれたのは関数の匕数、:の埌は関数の本䜓ずなりたす。

䟋えば、{ a, b }: a + bはaずbを足す関数にありたす。

この関数の匕数はstdenvずfetchurlでありたす 。

  • stdenvはstandard environment(暙準環境)の略でありたす、パッケヌゞをビルドできる䞀般ツヌルを含めたす。
  • fetchurlはurlずハッシュで指したファむルをダりンロヌドできる関数、fetchurl以倖にはGitHubからファむルをダりンロヌドするfetchFromGitHubなどの関数もありたす。

では䞀行目はstdenvずfetchurl匕数をもった関数を定矩したす。

次の行は

stdenv.mkDerivation {

ずなりたす。

匕数で枡されたstdenvを利甚したす。
stdenvはセットでありたすセットは䞀般のキヌバリュヌデヌタ構造でありたす。
Nix蚀語ではs.kはsセットのkキヌのバリュヌを返したす。
セットは{}で定矩できたす、䟋:{ a = 1; x = "foo"; }。セットは関数の頭によく䌌おいたすが、別なものずなりたすので間違わないように泚意したしょう。

mkDerivationはstdenvで定矩された関数です。
mkDerivationの匕数は特定なキヌをもったセットで、結果はderivation(導出)でありたす。
導出は倚少わかりづらい抂念であるので、今のずころは簡単にパッケヌゞレシピずビルドされたパッケヌゞの䞭間的な物ず考えればよいです。
ちなみに、mkDerivationのmkはmakeの略であっお、mkDerivation「導出生成」ず意味したす。

料理の䟋えを続けたすずこんな感じになりたす

{ キッチン, 買い物かご }:

料理を䜜る {
  # いろいろ
}

ただ二行目ですが、説明はほが完了しおいたす。

のこりはmkDerivationの匕数の圢匏だけです。

mkDerivationの匕数セットに倚くのオプションがありたす。
すべおをわかる必芁はないですが、基本をわかるずパッケヌゞは䜜りやすい。

必須な項目は2぀だけです:

  • name: パッケヌゞの名前(バヌゞョンを含む)
  • src: パッケヌゞの゜ヌスファむル

䞀般的なmake系パッケヌゞであれば、この2぀を定矩するだけで自動的にパッケヌゞがビルドされたす

では䟋のパッケヌゞでこのキヌを確認したしょう:

  name = "hello-2.10";

※: Nix蚀語ではセット内の;はキヌバリュヌペアのセパレヌタヌずなりたす。

䜜るパッケヌゞの名前はhello-2.10であるず意味したす。
バヌゞョン番号ず名前を分ける曞き方もよく䜿われおいたす、hello-2.10の堎合はこのようになりたす。

  version = "2.10";
  name = "hello-${version}";

※: nameをversionの䞊に曞く堎合はrecキヌワヌドを䜿っお再垰セットず宣蚀する必芁がありたす: rec { name = "hello-${version}"; version = "2.10"; }

次はsrcキヌです。srcはパッケヌゞの゜ヌスファむルを定矩したす。
ロヌカルファむルを定矩する事もできたすが、倧抵の堎合はネットから゜ヌスを取埗したす。

  src = fetchurl {
    url = "mirror://gnu/hello/hello-2.10.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };

helloの堎合はsrcの倀はfetchurl関数ずその匕数ずなりたす。
fetchurl関数はurlずハッシュを利甚し、urlに該圓するファむルをダりンロヌドしお、ダりンロヌドしたファむルのハッシュを匕数のハッシュず比范したす。

゜ヌスがあれば、Nixは暙準方法でconfigureずmakeし、パッケヌゞをビルドずむンストヌルしたす。

䟋で残りのキヌはmetaずなりたす。
metaはセットであっお、パッケヌゞのメタ情報を宣蚀したす。
メタ情報はビルドに圱響をほずんどしないで、䞻に倖郚ツヌルず連携に䜿われおいたす。
ではhelloで蚭定されおいるmetaのキヌを確認したしょう:

  • description: パッケヌゞの䞀行玹介
  • longDescription: パッケヌゞの詳现玹介
  • homepage: パッケヌゞのホヌムペヌゞ
  • license: パッケヌゞのラむセンス
  • maintainers: パッケヌゞのメンテナ
  • platforms: パッケヌゞが察応するプラットフォヌム

では最埌にのう䞀床helloのNix Expressionを確認したしょう

# stdenvずfetchurl匕数の関数を定矩
{ stdenv, fetchurl }:

# stdenv.mkDerivation関すを呌び出し、セットを匕数で枡したす
stdenv.mkDerivation rec {

  # パッケヌゞ名ずバヌゞョン
  name = "hello-2.10";

  # ゜ヌスファむルをfetchurl関数で取埗
  src = fetchurl {
    # rec で再垰セットを䜿うためにnameキヌを参照できたす
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };

  # パッケヌゞのメタ情報
  meta = {
    description = "A program that produces a familiar, friendly greeting";
    longDescription = ''
      GNU Hello is a program that prints "Hello, world!" when you run it.
      It is fully customizable.
    '';
    homepage = http://www.gnu.org/software/hello/manual/;
    license = stdenv.lib.licenses.gpl3Plus;
    maintainers = [ stdenv.lib.maintainers.eelco ];
    platforms = stdenv.lib.platforms.all;
  };
}

mkDerivation

helloはずおも単玔なパッケヌゞであっお、暙準ビルドにすべおおたかせしおもビルドできたすがそう簡単に行かないパッケヌゞも倚くありたす。
そのためmkDerivationに枡すセットにはたくさんなオプションがありたす。(ドキュメンテヌション)

すべおのオプションを説明するず逆に混乱するので、たずは基本の仕組みを玹介したす。

ビルドはフェヌズで別れおいたす。曞くフェヌスはビルドの䞀぀の段階を管理したす。

暙準フェヌズは:

  • 解凍フェヌス(unpackPhase): ゜ヌスファむルを解凍するフェヌズ
  • パッチフェヌズ(patchPhase): ゜ヌスファむルをパッチするフェヌズ
  • 蚭定フェヌズ(configurePhase): ゜ヌスファむルをビルド準備したす、デフォルトでは./configureを実行したす。
  • ビルドフェヌズ(buildPhase): ゜ヌスファむルをコンパむルしたす、デフォルトではmakeを実行したす。
  • チェックフェヌズ(checkPhase): doCheckキヌがtrueの堎合はビルドをチェックしたす、デフォルトでは実行されないフェヌズ。
  • むンストヌルフェヌズ(installPhase): Nixストアにパッケヌゞをむンストヌルするフェヌズ、デフォルトではmake installを実行したす。
  • フィックスフェヌズ(fixupPhase): パッケヌゞにNix専甚の修正をしたす。
  • 配垃フェヌズ(distributionPhase): doDistキヌがtrueの堎合に配垃甚のファむルを䜜成するフェヌスです、デフォルトでは実行されたせん。

すべおのフェヌズはフェヌズ熟考前ずフェヌズ実行埌のフックがありたす、䟋えばunpackPhaseの堎合はpreUnpackずpostUnpackが利甚できたす。

各フェヌズには専甚なキヌもありたす、その䞭でよく䜿うものは

  • patchPhase:

    • patches: 圓おるパッチの配列です、ロヌカルファむルずネットワヌクからダりロヌドするファむルを利甚できたす

      ```
      patches = [ ./my-patch.patch (fetchpatch { name = ...; url = ...; sha256= ...; }) ];
      ```
      
  • buildPhase:

    • makeFlags: makeに枡すフラグ

      ```
      makeFlags = [ "-DBUILD_icons=TRUE" "-DBUILD_plasma=TRUE" ];
      ```
      

䟝存関係

䟝存関係はbuildInputsキヌで管理したす。
䟋えばパッケヌゞにgtk䟝存を远加する堎合は関数頭ずbuildInputsにgtkを远加すればいいです。(meta省略)

{ stdenv, fetchurl, gtk }:

stdenv.mkDerivation rec {
  name = "hello-2.10";

  src = fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };

  buildInputs = [ gtk ];

}

Tips

デヌタファむルを利甚する

たたに゜ヌス以倖にデヌタファむルを必芁ずするパッケヌゞがありたす。その堎合ではletを利甚し、そのデヌタファむル情報をmkDerivationのスコヌプにもっおいき、該圓フェヌズで利甚したす。

fcitx-mozcパッケヌゞからの䟋:

{ clangStdenv, fetchFromGitHub, fetchurl, fetchpatch, fetchsvn, gyp, which, ninja, 
  python, pkgconfig, protobuf, gtk, zinnia, qt4, libxcb, tegaki-zinnia-japanese,
  fcitx, gettext }:
let
  japanese_usage_dictionary = fetchsvn {
    url    = "http://japanese-usage-dictionary.googlecode.com/svn/trunk";
    rev    = "10";
    sha256 = "0pyrpz9c8nxccwpgyr36w314mi8h132cis8ijvlqmmhqxwsi30hm";
  };
  icons = fetchurl {
    url    = "http://download.fcitx-im.org/fcitx-mozc/fcitx-mozc-icon.tar.gz";
    sha256 = "10bdjn481jsh32vll7r756l392anz44h6207vjqwby3rplk31np1";
  };
in clangStdenv.mkDerivation rec {
  name    = "fcitx-mozc-${version}";
  version = "2.17.2313.102";

  src = fetchFromGitHub {
    owner  = "google";
    repo   = "mozc";
    rev    = "3306d3314499a54a4064b8b80bbc1bce3f6cfac4";
    sha256 = "0l7mjlnbm6i1ipni8pg9ym5bjg3rzkaxi9xwmsz2lddv348sqii2";
  };

  nativeBuildInputs = [ gyp which ninja python pkgconfig ];
  buildInputs = [ protobuf gtk zinnia qt4 libxcb fcitx gettext ];

  postUnpack = ''
    rmdir $sourceRoot/src/third_party/japanese_usage_dictionary/
    ln -s ${japanese_usage_dictionary} $sourceRoot/src/third_party/japanese_usage_dictionary
    tar -xzf ${icons} -C $sourceRoot
  '';

japanese_usage_dictionaryずiconsはsrcず別圧瞮ファむルずなりたすが、パッケヌゞビルドには必芁です。
srcを解凍した埌に、postUnpackでjapanese_usage_dictionaryをビルドフォルダヌにリンクし、アむコンあっすくファむルをビルドフォルダヌに解凍したす。

パッケヌゞ䜜成の手順

パッケヌゞを䜜成する前にはパッケヌゞがnixpkgsで存圚しないのを確認したしょう。

䜜成には2぀の方法がありたす

  • ロヌカルnixpkgsクロヌンを利甚: レポゞトリの準備の手間がありたすが、プヌルリク゚ストしやすいです
  • 単独パッケヌゞ: 簡単に䜜れたすが、PRをする際にレポゞトリのクロヌンの関すの頭の修正が必芁ずなりたす

初心者に取っお䞀番な単独パッケヌゞの方法から玹介したす。

利点ずしおは

  • 関数頭がシンプルで枈む
  • Nix expressionだけでパッケヌゞをビルドできたす

単独パッケヌゞ

helloパッケヌゞの単独バヌゞョンを芋たしょう

{ pkgs ? import <nixpkgs> {} }: 
with pkgs;

stdenv.mkDerivation rec {
  name = "hello-2.10";

  src = fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };
}

※ 単独パッケヌゞは倖郚ツヌルのの連携はないので、metaキヌは必芁内です。

このNix expressionをhello.nixに保存しお、nix-build hello.nixを実行すれば、パッケヌゞをビルドできたす。
ビルドされた結果はnix-buildが実行されたフォルダヌにresultず蚀ったNixストアパッケヌゞぞのリンクを䜜りたす。
実行可胜プログラムは./result/bin/以䞋に入っおいたすので、実行を詊したしょう。

nixpkgsでのパッケヌゞの曞き方ず比べお、関数頭しか倉わらないです。
では分析したしょう:

{ pkgs ? import <nixpkgs> {} }: 

倚少わかりにくいので、括匧を぀けたしょう

{ pkgs ? ((import <nixpkgs>) {}) }: 

この短い蚘述でいろいろをやっおいたす。
たずは{ pkgs }:はpkgsを匕数を利甚する関数頭です関数頭はセットず異なっお:が぀いおいたす
関数頭で{ var ? "value" }:はvar匕数に"value"デフォルト倀を蚭定したす、蚀い方を倉えお、varが枡されおいない堎合にvarを"value"にしたす。
今回の䟋ではpkgs匕数のデフォルトバリュヌをimport <nixpkgs> {}にしたす。

import <nixpkgs> {}に優先を衚す括匧を぀けるず((import <nixpkgs>) {})になりたす。
importはNixのビルトむン関数でありたす、importでNix Expressionを文字通りにむンポヌトできたす。
<nixpkgs>は特別省略であり、NIX_PATH環境倉数で定矩されたnixpkgsを指したす。

<nixpkgs>のパスは次のコマンドで確認できたす:

# echo $NIX_PATH

でimport関数はパスをフォルダヌを枡された時にdefault.nixを読み蟌みたすので、NIX_PATHのdefault.nixをむンポヌトしたす。

最埌のパヌツは((import <nixpkgs>) {})の{}です、むンポヌトされるdefault.nixは関数であるために匕数を枡さないず結果が垰っおこないです。
特別な匕数を枡す必芁は内ので、空セット{}を枡したす。

説明が倧分長くなりたしたが、䞀蚀でたずめるず{ pkgs ? import <nixpkgs> {} }:はpkgs匕数にnixpkgsを読み蟌たせたす。

次の行に出おくるwith pkgs;はpkgsのキヌを次のexpressionのスコヌプに共有したす。
簡単にいいたすずstdenvずfetchurlがpkgsに含たれおいるので、withのおかげでpkgs.stdenv.mkDerivationやpkgs.fetchurlを曞く必芁がなく、pkgsを省略できたす。

単独パッケヌゞ -> nixpkgs

単独パッケヌゞの䜜成が終わったら、nixpkgsに登録する事はできたす。

たずはロヌカルにnixpkgsのクロヌンを䜜りたす:

# git clone https://github.com/NixOS/nixpkgs.git
# cd nixpkgs

nixpkgsにはNixで利甚すべおのパッケヌゞずNixOS関連の゜ヌスコヌドが管理されおいたす。

トップレベルフォルダヌは

  • doc: nixpkgsのドキュメンテヌション
  • lib: Nix蚀語のラむブラリ関数
  • maintainers: メンテナ甚のスクリプト等
  • nixos: NixOS関連コヌド
  • pkgs: パッケヌゞ

パッケヌゞはpkgフォルダヌの䞋に入りたす、pkg以䞋はカテゎリ毎にフォルダヌがありたす。
パッケヌゞをどのフォルダヌに眮くにルヌルが曖昧で、䞀番カンタンのは䌌たパッケヌゞを探し、そのパッケヌゞず同じカテゎリに眮けば良いです。

䟋ずしおは先皋の単独パッケヌゞを利甚したす。
helloはすでにnixpkgsに存圚したすので、パッケヌゞ名をmy-helloに倉曎したす。

my-hello.nix:

{ pkgs ? import <nixpkgs> {} }: 
with pkgs;

stdenv.mkDerivation rec {
  name = "my-hello-2.10";

  src = fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
  };
}

プヌルリク゚ストのためにパッケヌゞ専甚ブランチを䜜りたしょう:

# git checkout -b pkg/my-hello

helloはpkgs/applications/misc/の䞋にありたすので、my-helloも同様にpkgs/applications/misc/に眮きたしょう。 たずはフォルダヌを䜜りたす。

# mkdir pkgs/applications/misc/my-hello/

nixpkgsではパッケヌゞのNix expression名をdefault.nixにする決たりがありたす。

# cp my-hello.nix pkgs/applications/misc/my-hello/default.nix

次のステップはmy-helloをパッケヌゞリストに登録したす、nixpkgsのパッケヌゞリストはpkgs/top-level/all-packages.nixにありたす。

パッケヌゞリストは瀬戞であり、曞くパッケヌゞはキヌでありたす。 曞き方は:

  キヌ = callPackage パス 匕数;

callPackageはimportの様にNix expressionをむンポヌトし、他のパッケヌゞを読み蟌んだNix expressionのスコヌプに共有したす。

helloパッケヌゞの蚘述を確認したしょう

  hello = callPackage ../applications/misc/hello { };

my-helloのパッケヌゞ定矩

  my-hello = callPackage ../applications/misc/my-hello { };

残りはmy-helloのNix expressionの関数頭の修正ずmetaキヌの远加。

単独パッケヌゞの関数頭は

{ pkgs ? import <nixpkgs> {} }: 
with pkgs;

callPackageのおかげでpkgsのすべおのキヌは関数頭で利甚できたす。
そのためNix Expressionに利甚するパッケヌゞを関数頭に入れればいいです。
my-helloはstdenvずfetchurlを利甚したすので、次のように関数頭を修正したす。

{ stdenv, fetchurl }: 

※ with pkgs;は䞍芁ずなりたすので、行ごずを削陀したす。

埌はmkDerivationのmetaを远加すれば完成したす。

helloパッケヌゞのmetaセットを確認したしょう

  meta = {
    # パッケヌゞの抂芁、䞀行内で「.」を぀けないです
    description = "A program that produces a familiar, friendly greeting";
    # パッケヌゞの玹介
    longDescription = ''
      GNU Hello is a program that prints "Hello, world!" when you run it.
      It is fully customizable.
    '';
    # パッケヌゞのホヌムペヌゞ
    homepage = http://www.gnu.org/software/hello/manual/;
    # パッケヌゞのラむセンス
    license = stdenv.lib.licenses.gpl3Plus;
    # パッケヌゞのメンテナ
    maintainers = [ stdenv.lib.maintainers.eelco ];
    # パッケヌゞの察応プラットフォヌム
    platforms = stdenv.lib.platforms.all;
  };

licenseに蚭定するはstdenv.lib.licensesセットのキヌずなりたす、ラむセンス䞀芧はlib/licenses.nixで確認できたす。

maintainersはパッケヌゞメンテナのリストずなりたす、自分をメンテナに蚭定する堎合はlib/maintainers.nixに自分の情報を远加する必芁がありたす。

platformsはパッケヌゞが察応するプラットフォヌムになりたす、プラットフォヌム䞀芧はlib/platforms.nixで確認できたす。

パッケヌゞが完成したしたら、nix-buildコマンドでビルドできたす。 nixpkgsのルヌトフォルダヌに

# nix-build -A my-hello
⚠ **GitHub.com Fallback** ⚠