[NixOS] bashの更新
巷でbashの脆弱性が騒がれていますね.
Nixも早々に対応されていました(github). ただ,Nixpkgs本家には更新がまだ降ってきていなかったので,いったんgitで取ってきてインストールすることに.
$ cd ~/nixpkgs $ git pull $ sudo nix-env -f . -i bash
ローカルのリポジトリにあるパッケージのインストールは-f [path]オプションで指定します.
ほかに手っ取り早い方法ないもんですかね.
NASA
One Nice Bug Per Day

No title available

blake kathryn
🪼

Discoholic 🪩
AnasAbdin

❣ Chile in a Photography ❣
$LAYYYTER
taylor price

pixel skylines
Aqua Utopia|海の底で記憶を紡ぐ
noise dept.
Jules of Nature
Game of Thrones Daily

JBB: An Artblog!

No title available
dirt enthusiast

祝日 / Permanent Vacation

Origami Around

seen from Canada

seen from Malaysia
seen from United States
seen from United States

seen from Canada

seen from Türkiye
seen from Spain
seen from United Kingdom

seen from Malaysia

seen from Malaysia
seen from Malaysia
seen from Czechia
seen from United States

seen from Malaysia

seen from Russia

seen from Malaysia
seen from Sri Lanka
seen from Malaysia
seen from Israel

seen from United States
@xwillr
[NixOS] bashの更新
巷でbashの脆弱性が騒がれていますね.
Nixも早々に対応されていました(github). ただ,Nixpkgs本家には更新がまだ降ってきていなかったので,いったんgitで取ってきてインストールすることに.
$ cd ~/nixpkgs $ git pull $ sudo nix-env -f . -i bash
ローカルのリポジトリにあるパッケージのインストールは-f [path]オプションで指定します.
ほかに手っ取り早い方法ないもんですかね.
[iOS, Swift] StringとCFString
先日,研究室の入退室管理アプリのコードをObjective-CからSwiftに移行していたのですが,そこで引っかかった点があったので書いておきます.
事の発端
URLエンコードをするために使用していた関数CFURLCreateStringByAddingPercentEscapesはSwiftのほうだと
func CFURLCreateStringByAddingPercentEscapes (allocator: CFAllocator!, originalString: CFString!, charactersToLeaveUnescaped: CFString!, legalURLCharactersToBeEscaped: CFString!, encoding: CFStringEncoding) -> CFString!
と定義されています.
ところで,NSURLのコンストラクタは
convenience init(string URLString: String!)
なので,SwiftでのURLエンコーディングは
... { ... let user = "..." let token = "..." let status = "..." ... let str = "http://hogefuga.hoge/update/info?user=\(user)&token=\(token)&info=\(info)" let encodedURL: NSURL = NSURL(string: urlEncoding(str)) ... } func urlEncoding(string: String) -> String { let escapedString = CFURLCreateStringByAddingPercentEscapes( kCFAllocatorDefault, string as CFString, "", "!*'();:@&=+$,/?%#[]~", .UTF8) as String return escapedString }
こんな感じでいいだろう,と. だめでした.
string as CFStringのところで
`Cannot convert the expression's type 'String' to type 'CFString!'`
とエラーが出ます.つらい.
解決策
で,試行錯誤の末たどり着いた結果がこちら.
func urlEncoding(string: String!) -> String! { let utf8enc: CFStringEncoding = 0x08000100 let cfstring = string as NSString let escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, cfstring as CFString, "" as CFString, "!*'();:@&=+$,/?%#[]~", utf8enc) as String return escapedStr }
リファレンスを見る限り最後の引数encoding: CFStringEncodingは.UTF8で良さそうなのですが,Xcodeが「そんなものは知らん」と言ってくるのでしかたなく直に値を渡してやることに.
これで無事コンパイルが通り,動作確認もできました.
結論
CFStringからStringへのキャストは一発で可能ですが, 逆は直接キャストするのが無理なようで,いったんNSStringにキャストしてやる必要があるようです.
Nixpkgsとの戯れ
先日,Nix expressionについてまとめたので,実際になにか書いてみようと思います.
準備
Nixのシステムを直接いじろうとしてもRead-only file systemだぞと怒られて勝手に書き換えが出来ないので, Nixpkgs ManualのChapter 2. Quick Start to Adding a Packageにある通り,いじるための環境をつくってやります.
$ cd ~ $ git clone git://github.com/NixOS/nixpkgs.git $ cd nixpkgs
適当な場所にディレクトリをつくります.
$ mkdir pkgs/development/libraries/libhoge $ cd pkgs/development/libraries/libhoge
そしてlibhoge直下にパッケージをインストールするためのNix expressionを書いたファイルdefault.nixを置きます. 今はとりあえずGnu Helloあたりからコピーしておきましょう.
$ cp ~/nixpkgs/pkgs/applications/misc/hello/ex-2/default.nix ./
Nix expression languageでFizzBuzz!
さあ準備完了です. 今回はNix expression languageのおさらいということで,ためしにFizzBuzzを書いてみました.
コードはこんな感じ.
let mod = x: y: builtins.sub x (builtins.mul y (builtins.div x y)); fb = x: if mod x 15 == 0 then "FizzBuzz" else if mod x 3 == 0 then "Fizz" else if mod x 5 == 0 then "Buzz" else toString x; mklist = x: if builtins.lessThan x 1 then [] else (mklist (builtins.sub x 1)) ++ [x]; in n: if builtins.lessThan n 1 then [] else map fb (mklist n)
最初にLet式で3つの関数を定義しています.
modが余り(x mod y)を計算する関数
fbが整数を受け取って文字列(“Fizz”, “Buzz”, “FizzBuzz”もしくは数字を文字列に変換したもの)を返す関数
mklistは整数xを受け取り1からxまでのリストを返す関数
関数本体としては,整数nを受け取り,n < 1なら空リストを返し,n >= 1なら1からnまでのリスト[1 2 ... n]の各要素にmapを使ってfb関数を適用します.
modの定義中に出てくるbuiltins.sub, builtins.mul, builtins.divは組込み関数で,それぞれ減算,乗算,除算を表します(ちなみに加算はbuiltins.add). また,mklistと関数本体に出てくるbuiltins.lessThanは2つの引数を比較し,第1引数が第2引数より小さいときtrue,それ以外のときfalseを返します.
さて,これをdefault.nixと同じディレクトリにfizzbuzz.nixとして保存しておき,default.nixにちょっと手を加えます.
# 追加 let fzbz = import ./fizzbuzz.nix 15; in { stdenv, fetchurl }: # 追加 if fzbz != null then throw (toString fzbz) else stdenv.mkDerivation { ...
上のほうに追加した行でfizzbuzz.nix 15を実行し,その結果をfzbzに束縛しています. 下のほうに追加した行では,fzbzがnullでなければfzbzを文字列に変換し,これをエラーメッセージとして投げています.
それから,~/nixpkgs/pkgs/top-level/all-packages.nixのhelloの下あたりにlibhogeの記述を付け加えます.
... hello = ...; # 追加 libhoge = callPackages ../development/libraries/libhoge { }; ...
これで,パッケージビルドのテストを走らせてみます.
$ cd ~/nixpkgs $ nix-build -A libhoge error: 1 2 Fizz 4 Buzz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
はいっ! ちゃんとエラーメッセージに15までのFizzBuzzの結果が表示されました!!
これだけです
というわけで,なんの実用性もありませんがNix expressionでFizzBuzzくらいなら簡単に書けちゃうことが確認できました. ていうかぶっちゃけ好きなようにラムダ式書けちゃうので,やろうとおもえばなんでも出来ますね!!!
ん? パッケージ追加の実用的な例???
……はい,真面目にやります
Nix expressionのおべんきょ
Nix User's Guide (Nix manual)のChapter 5 Writing Nix Expressionsあたりをぼちぼち読んで書き方を勉強してます. これはその備忘録.
Nix expressionというのは,パッケージのビルドに必要な情報(依存関係とか)をNixに教えてあげるための言語です. もし,インストールしたいパッケージがNix Packages collectionに入っていないときは自分で書いてやる必要があります.
簡単なNix expressionの例
User's GuideではGNU Hello packageを例に説明されています. まず,Nix Packages collectionにパッケージを追加するために必要なのが次の3つ.
Nix expressionの記述
builderの記述
pkgs/top-level/all-packages.nixにパッケージを追加
1. Nix expressionの記述
上でもごく簡単に書きましたが,Nix expressionはパッケージの依存関係やソースなど,ビルドに必要な情報の記述するためのものです.
GNU Helloだと以下のようになります.
{ stdenv, fetchurl, perl }: /* ビルドに必要な引数 */ stdenv.mkDerivation { name = "hello-2.1.1"; /* symbolic name + version */ builder = ./builder.sh; /* builder(標準のものを使うときは省略可) */ src = fetchurl { /* fetchurlの結果をsrcに束縛 */ url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz; md5 = "70c9ccf9fac07f762c24f2df2290784d"; }; inherit perl; /* perl = perl; の略記 */ }
2. builderの記述
builderは実際にパッケージをビルドするためのシェルスクリプト. 標準のものを使う場合には自分で書く必要はありません. あと,generic builderとかいうのもあるようですが今は割愛します.
# 環境の初期化 source $stdenv/setup # PerlのインタプリタがあるディレクトリをPATHに追加 PATH=$perl=/bin:$PATH # ソースのunpacking tar xvfz $src cd hello-* # あとはconfigureしてmake && make install ./configure --prefix=$out make make install
3. pkgs/top-level/all-packages.nixにパッケージを追加
ビルドに必要なパッケージも全て追加します. helloの例だと,hello, stdenv, fetchurl, perlの4つ.
rec { /* 属性の帰納的(=相互再帰可能な)集合 */ hello = import ../applications/misc/hello/ex-1 { /* 指定したディレクトリから関数をインポートして呼び出す */ inherit fetchurl stdenv perl; }; perl = import ../development/interpreters/perl { inherit fetchurl stdenv; }; fetchurl = import ../build-support/fetchurl { inherit stdenv; ... }; stdenv = ...; }
と,まあ例だけ見てもよくわからない(本当はもう少しくわしく言葉で説明されていますが)ので,ここでは大まかにその雰囲気をつかむことにして,まずはNix expressionの文法から見ていくことにします.
The Nix expression language
The Nix expression language is a pure, lazy, functional language. ...(中略)... The language is not a full-featured, general purpose language. Its main job is to describe packages, compositions of packages, and the variability within packages.
ということで,Nix expression languageはパッケージの記述に特化した純粋関数型言語だそうです.
Nix expressionで扱う値
シンプルな値
基本的なデータ型として,
文字列
整数
パス
ブール値
ヌル値
があります.
文字列
文字列は“hoge”のようにダブルクォートで囲みます. ", \と${は特殊文字なので文字として扱いたい場合にはバックスラッシュ(\)でエスケープします. また,
`` hogehoge fugafuga piyopiyo ``
のようにしてインデント付けされた文字列を書くこともできます.これは
"hogehoge\n fugafuga\n piyopiyo\n"
と等価です. インデント付けされた文字列の場合は,エスケープ文字として"を使います(例: "${, "\nなど).
文字列の連結は+演算子を用います.
"hoge" + "fuga"
は"hogefuga"と評価されます.
それから,${...}という記法を使ってantiquatationが可能です. たとえば,
"--with-freetype2-library=" + freetype + "/lib"
の代わりに,次のように書けます.
"--with-freetype2-library=${freetype}/lib"
また,URLは特別にダブルクォーテートを省略できます. つまり, "http://example.org/foo.tar.bz2"をhttp://example.org/foo.tar.bz2と書けます.
整数
123とか1024とか,これに関して特に言うことはないかとおもいます.
パス
/bin/sh, ./builder.shなど. パスは少なくとも1つの/を含まなければなりません.
ブール値
trueとfalseの2値.これもいいでしょう. 演算として,
否定 !b
論理積 b1 && b2
論理和 b1 || b2
論理包含 b1 -> b2 (「b1ならばb2」というやつ.!b1 || b2と等価)
が用意されています.
ヌル値
nullです. ある式eの評価した結果がヌル値かどうかを判定したいときは
isNull e
と書きましょう. e == nullという記述は非推奨です.
リスト
リスト表記は
[123 ./foo.nix "abc" (f { x = y; })]
のように,[ ]の間に空白区切りで値を並べます. ここで,(f { x = y; })は関数呼び出しの結果を表します. 括弧は省略できません.
[123 ./foo.nix "abc" f { x = y; }]
と書いた場合には{ x = y; }は集合になります.
リストの連結には++演算子を使います.
[ 123 "foo" ] ++ [ 456 "bar" ]
は[ 123 "foo" 456 "bar" ]と評価されます.
集合
集合は複数のname/valueのペア(属性と呼ぶ)からなります. 例えば,
{ x = 123; text = "Hello"; y = f { bla = 456; }; }
という集合は,x, text, yという属性をもち,その値はそれぞれ123, "Hello", f { bla = 456; }となります. 属性を記述する順番に決まりはありませんが,属性の名前は1つにつき1回しか使えません.
.演算子を用いることで,属性の選択(取り出し)が出来ます. 例えば,
{ a = "Foo"; b = "Bar"; }.a
は"Foo"と評価されます. また,orキーワードで属性選択のデフォルト値を与えることができます.
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
という式は集合内にcという属性がないので"Xyzzy"と評価されます.
属性の名前には文字列を使うこともできます.
{ "foo ${bar}" = 123; "nix-1.0" = 456; }."foo ${bar}"
この式は123と評価されます.
属性の名前がantiquatation単体のときはダブルクォートを省けます.
{ foo = 123; }.${bar} or 456
これは,barが"foo"に評価されるとき123と評価され,barがその他の文字列に評価される場合には456と評価されます.
また,特殊なケースとして,属性名がnullに評価されてしまうような場合,その属性は集合に加えられません. つまり,
{ ${if foo then "bar" else null} = true; }
という式は,fooがfalseと評価されるとき{}と評価されます.
集合sに属性が含まれるかどうか調べるには,その属性名をattrpathとして
s ? attrpath
と書きます.sがattrpathを含むときtrue,それ以外はfalseを返します.
//演算子を用いて,2つの集合の共通部分をとることができます.
s1 // s2
は集合s1とs2の両方に含まれる属性からなる集合を返します.
帰納的集合
帰納的集合は属性の相互参照を許すような集合です. 書き方は普通の集合とほとんど変わりません. ただ先頭にrecをつければokです.
例えば,
rec { x = y; y = 123; }.x
は123と評価されます. ただし,循環参照には気をつけましょう.
rec { x = y; y = x; }.x
は,評価が停止しません(実際はエラーが出て止まるらしい).
言語構成要素
Let式
みなさんご存知(?)Let式 束縛変数をx1..xN,式をe1..eN及びeとして
let x1 = e1; ... xN = eN; in eの形式で定義.
例えば,
let x = "foo"; y = "bar"; in x + y
これは"foobar"と評価されます.
属性の継承
集合を定義する際,同構文スコープ内の変数をコピーしたいということがよくあります. そういうときはinheritキーワードを使います. これを属性の継承と呼びます.
例えば
let x = 123; in { inherit x; y = 456; }
は{ x = 123; y = 456; }と評価されます. ここで,xがlet式で構文スコープに追加されていることに注意してください.
他の集合から属性を継承することもできます. all-packages.nixを覗いてみると,
graphviz = (import ../tools/graphics/graphviz) { inherit stdenv libpng libjpeg expat x11 yacc; inherit (xlibs) libXaw; }; xlibs = { libX11 = ...; libXaw = ...; ... } libpng = ...; libjpg = ...; ...
という記述があります. graphvizの関数呼び出しの中にあるinherit (xlibs) libXaw;は, その下にある集合xlibsのlibXawを継承することを表しています.
関数
今までもちょいちょい出てましたが,関数は以下のように定義されます.
pattern: body
patternには引数のパターン,bodyに関数本体を書きます.
パターンの書き方は3種類あります.
単一識別子
パターンが単一の識別子の場合,その関数は任意の引数にマッチします.
例)
let negate = x: !x; concat = x: y: x + y; in if negate true then concat "foo" "bar" else ""
concatは1つの引数をとり,「また別の引数をとる関数」を返すような関数です. (Haskellの\x -> \y -> x ++ yと似てる?)
もちろん部分適用も出来ます.
map (concat "foo") [ "bar" "blar" "abc" ]
という式は[ "foobar" "fooblar" "fooabc" ]と評価されます. map関数は組込み関数として用意されています.
集合パターン
集合パターンは,{ name1, name2, ... ,nameN }の形式で複数の属性をまとめて書けます.このとき,その関数はこれらの属性を含む集合とマッチします.
例えば,
{ x, y, z }: z + y + x
は,x, y, zを含み,かつその他の属性を含まない集合とマッチします. もし,他の引数を認めたい場合には
{ x, y, z, ... }: z + y + x
と記述します.
それから,属性のデフォルト値を設定することも可能で,
{ x, y ? "foo", z ? "bar" }: z + y + x
のように記述することで, y, zをオプションにすることが出来ます.
@-パターン
Haskellのasパターンみたいなやつです.
args@{ x, y, z, ... }: x + y + z + args.a
といった具合に,パターン{ x, y, z, ... }をargsに束縛して関数本体でもこれを使用できるようにしたものです.
関数に名前をつけたいときは,属性として束縛してやります.
let concat = { x, y }: x + y; in concat { x = "foo"; y = "bar"; }
条件文
条件文はさっきからちょいちょい出てました. e1, e2, e3を式として,以下のように記述します.
if e1 then e2 else e3
ただし,e1はブール値に評価される式でなければなりません.
アサーション
アサーションは,ビルドするパッケージが要求や依存関係を満たしているかどうかをチェックするために使用されます. e1, e2を式として,
assert e1; e2
と書きます. 条件文と同様,e1はブール値に評価される必要があります.
このアサーションは,e1が trueと評価されたときe2を返し,その他の場合には式の評価を中断し,バックトレースを表示します.
With式
With式はe1を集合(に評価される式), e2を式として,
withe e1; e2
と記述され,e1をe2の構文スコープに加えることを意味します. 例えば,
let as = { x = "foo"; y = "bar"; }; in with as; x + y
は,"foobar"と評価されます.
コメント
一行コメントは#で始めます. インライン(複数行)なら/* ... */.
演算子
Nix expression languageの演算子のまとめ. ざっくり.
文法 結合規則 説明 e.attrpath [ or def ] 無 属性選択 e1 e2 左 関数呼び出し e ? attrpath 無 属性の包含判定 e1 ++ e2 右 リストの連結 e1 + e2 左 文字列/パスの連結 ! e 左 論理否定 e1 // e2 右 集合の共通部分 e1 == e2 無 等価性 e1 != e2 無 非等価性 e1 && e2 左 論理積 e1 || e2 左 論理和 e1 -> e2 無 論理包含
Derivations
Nix expression langageで最も重要な組込み関数がderivationで,ビルドの動作(どのプラットフォームでビルドするか,どんな引数を与えるか,などのビルドの構成)を記述するのに使用されます(この「ビルドの動作」をderivationと呼んでいるようです.たぶんきっとおそらく). この関数は引数に集合をとり,その属性にしたがってビルドの入力が指定されます. ビルドに必要な情報を渡したら,よきにはからって設定してくれる便利なやつです.
では,derivationに渡す集合の属性にはどんなものがあるのか見ていきます.
system(必須)
Nixのプラットフォームを表す文字列."i686-linux"とか"powerpc-darwin"とか.
name(必須)
パッケージ名を表す文字列.nix-envでパッケージの識別名とか,derivationの出力のパスに使用されます.
builder(必須)
ビルドを実行するプログラムを指定するための属性.derivationもしくはパス(./builder.shのようにローカルファイルの参照)を指定します.
args(オプション)
builderに渡すコマンドライン引数を指定する属性.これはリストで指定します.
outputs(オプション)
パスのリストを指定します.標準では1つのパスに出力しますが,derivationは複数のパスに出力することができます. 例えば,ダイナミックライブラリとヘッダファイル,ドキュメントを提供するライブラリパッケージがあったとしましょう.そのライブラリにリンクしたプログラムの実行時に,ヘッダファイルやドキュメントは不要です.同様に,ビルド時にもドキュメントは不要です. このような場合にはoutputsを次のように指定します.
outputs = [ "lib" "headers" "doc" ];
すると,Nixは環境変数lib, headers, docを各出力が格納されるパスを含めてbuilderに渡します. builderは,例えばAutconf-styleのパッケージだと
./configure --libdir=$lib/lib --includedir=$headers/include --docdir=$doc/share/doc
みたいな感じで実行します.
属性選択によってderivationの出力を参照することもできます.パッケージをpkgとすると,
buildInputs = [ pkg.lib pkg.headers ];
といった具合です. デフォルトの出力はoutputの最初の要素になっているので,省略して
buildInputs = [ pkg pkg.headers ];
とも書けます.
全ての属性は環境変数としてbuilderに渡されるのですが, これらの属性の値は以下のようにして環境変数に変換しているらしいです.
文字列や整数はそのまま.
パスの場合,参照されているファイルをstoreにコピーするので,そのstore内にコピーされた場所を環境変数に追加.
derivationの場合,そのderivationを現在のderivationより優先してビルドするので,その標準出力を環境変数に追加.
リストはスペース区切りで連結.
trueは文字列"1"として,falseとnullは空文字として渡されます.
mkDerivation関数は標準環境におけるderivationのWrapperです. helloのNix expressionの例で出てきていましたね. mkDerivationはsystemにデフォルト値を与え,Bashをbuilderとして使用します. 与えられたbuilderは,コマンドライン引数としてmkDerivationに渡されます.
builderは以下のように実行されます.
TMPDIRで指定されたディレクトリ下に一時ディレクトリが生成され,カレントディレクトリがその一時ディレクトリに変更されます.
環境がクリアされ,derivationの属性が設定されます.
以下のように変数が設定されます.
NIX_BUILD_TOP: 一時ディレクトリのパス.
TMPDIR, TEMPDIR, TMP, TEMP: これらも一時ディレクトリの位置が設定されます.他の一時ファイルを書き換えてしまうのを防ぐため.
PATH: shellがもともと設定されていた値を初期化してしまわないように/path-not-setが設定されます.
HOME: プログラムが/etc/passwdもしくはユーザのホームディレクトリがわかるようなものをうっかり使わないように,/homeless-shelterが設定されます.
NIX_STORE: Nix storeディレクトリのトップレベルのパス(だいたいの場合/nix/storeのはず)が設定されます.
outputsで宣言された各出力について,対応する環境変数にNix store内の出力パスを設定します.
出力パスにファイルがすでに存在する場合,それを削除.また,ビルド中の同時アクセスを防ぐためファイルをロックします.
標準出力およびエラーのログを/nix/var/log/nixに書き込みます.
builderがargs属性により指定された引数とともに実行されます.exit codeが0で終了したらビルド成功.
一時ディレクトリを削除します(-Kオプションが指定されていなければ).
ビルドが成功した場合,Nixは各出力のパスに対して,入力パスのハッシュ部を探すことで,入力パスの参照を求めます.実行時の依存関係があれば,それらを出力パスの依存関係として登録します.
ビルド後,Nixは最終更新時のタイムスタンプをビルドされた全てのファイルに設定し,グループをデフォルトグループに,ファイルのモード(パーミッション)を0444か0555に設定します.
その他の属性
derivationには他にもいろいろ属性を指定できますが,ここでは割愛します.
くわしくはUser's Guide p.31参照.
組込み関数
ちょこっと紹介したmapやisNull以外にもたくさん組込み関数が用意されています. くわしくはUser's Guide p.33参照.
よく使用する関数としては,import関数があります. これはパスを引数にとり,そのファイルをロード,パースしてNix expressionを返します. パスがディレクトリを指している場合には,そのディレクトリ下のdefault.nixがロードされます. また,ファイルが存在しないか,パースが失敗した場合は評価を中断します.
ロードされるNix expressionは,自由変数を含んではいけません. 例えば,
rec { x = 123; y = import ./foo.nix }
のとき,以下のようなfoo.nixだとエラーになります.
x + 456
これはxがfoo.nixのスコープに含まれていないためです. そういうことがしたいときは,
rec { x = 123; y = import ./foo.nix x }
として,引数を渡してやり, foo.nixは
x: x + 456
と書きます.
ここまでで文法を一通りなぞりました. さて,それではGNU Helloのdefault.nixの記述例をもう一度見てみましょう.
{ stdenv, fetchurl, perl }: stdenv.mkDerivation { name = "hello-2.1.1"; builder = ./builder.sh; src = fetchurl { url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz; md5 = "70c9ccf9fac07f762c24f2df2290784d"; }; inherit perl; }
ちなみに,コメントは省きました.
おわかりいただけるでしょうか. ぐっと睨んでやると,
{ a, b, c }: f { ... }
という形式になっていますね. これは引数として集合パターン{ stdenv, fetchurl, perl }をとり,stdenv.mkDerivationを実行した結果を返す関数の宣言です.
mkDerivationを使っているので,指定する属性はnameのみが必須で,他はオプションということになります.
このNix expressionが意味するところは, 「hello-2.1.1というパッケージを./builder.shにあるbuilderを使ってビルドします.builderに渡す引数はsrc = fetchurlでダウンロードしたソースファイル;とperl = perl;です」といった感じでしょうか.
それから,all-packages.nixのほうは,
rec { hello = import ../applications/misc/hello/ex-1 { inherit fetchurl stdenv perl; }; perl = import ../development/interpreters/perl { inherit fetchurl stdenv; }; fetchurl = import ../build-support/fetchurl { inherit stdenv; ... }; stdenv = ...; }
これは帰納的集合そのものですね. 各属性は,importでロードした関数を実行した結果(各パッケージをビルドするderivation)を束縛しています. つまり,all-packages.nixにはderivationの集合を書いておくわけですね.
以上,ただUser's Guideをざっくり訳しただけになってしまいましたが,Nix expressionの書き方でした. (実は,ぼくもまだあんまりNixいじってないので,具体的な例は追々書いていくことにします.)