経緯
なぜNixに移行するのか?
part 1になる前回の投稿日は2025年の3月の末だったので、投稿からほぼ1年も経過してしまっています。
進捗としては、gnuplotのビルドまでと本当に序盤を触れただけです。
さらに、その間に普段一番触っているラップトップマシンをArch LinuxからNixOSに移行したことで、環境がガラリと変りました。
これまで通りにやるならば、システムにグローバルにツール群をインストールしてビルドしてしまうのも一つの手ではあります。
しかし、せっかくNixOSをflakeによって運用しているならば、flakeでローカルに環境を作りビルドした方が"Nixらしい"と思ったので移行してみることにしました。
移行作業は?
“地獄"とまではいきませんが、目的のビルド成果物を思い通りに動くようにできるまでは少々大変ではありました。
とりあえずビルドができるところまでは、案外すんなりいったのですがGUIでplotの画面が開かない問題が中々解決できませんでした。
環境構築 by flake.nix
今回構築した環境では、以下のことを要件としました。
- 再現性のある環境を構築すること
- ソースコードを変更&ビルドを手軽に繰り返すことが可能なこと。
- gdb(デバッガ)を使ってステップ実行ができるようにすること。
- clangd(Language Server)を使ってコードを読む時に定義ジャンプ等が使えるようにすること
以下では、各要件を満す環境をどう構築したかについて説明します。
要件1,2(ビルド環境)について
要件1,2は、一旦nix buildでビルドが可能な環境を作ってから、それに要したパッケージ等の設定をmakeShell関数にも設定することで実現しました。
というのも、ビルドが可能なnix-shell環境できたつもりでもグローバルにインストールされているツールに依存していわゆる"暗黙の依存"を作ってしまう可能性があります。
暗黙の依存作ってしまうと、せっかくのNixの再現性が台無しです。
まずは、特に依存パッケージ等を考えずに、普通のgccをコンパイラツールチェーンとして指定して以下の環境でnix buildを実行してビルドを行いました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
{
description = "flake for Seach of LS software";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs =
{ self, nixpkgs }:
let
platform = "x86_64-linux";
pkgs = nixpkgs.legacyPackages."${platform}";
nParallels = "11";
gnuplot_debug = pkgs.stdenv.mkDerivation rec {
pname = "gnuplot";
version = "5.0.1";
src = pkgs.fetchurl {
url = "https://sourceforge.net/projects/gnuplot/files/gnuplot/${version}/gnuplot-${version}.tar.gz";
hash = "sha256-fLxVfnHfWB6lIBI/tDnepfBzrcyQEKKIXcgNTtKLPEc=";
};
nativeBuildInputs = with pkgs; [
gcc
gnumake
];
buildInputs = with pkgs; [ ];
dontConfigure = true;
buildPhase = ''
CFLAGS="-O0 -g" ./configure --prefix=$out
make -j${nParallels}
'';
installPhase = ''
make install
'';
};
in
{
packages.${platform}.default = gnuplot_debug;
};
}
|
しかし、ビルドには失敗して、以下のようなエラーメッセージが表示されました。
どうやら、buildPhaseのmakeの実行でコケているようです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
nix build
error: Cannot build '/nix/store/xy2d25qg4ip4aa7jyssazrr6f2fscdm0-gnuplot-5.0.1.drv'.
Reason: builder failed with exit code 2.
Output paths:
/nix/store/kcizqzm8hmm7fzq1bhch7mfc1dq5isr6-gnuplot-5.0.1
Last 25 log lines:
> from stdfn.h:49,
> from dynarray.h:41,
> from dynarray.c:43:
> /nix/store/dj43clc5ff7jjnfmhbaj6q4q0h8kpfpm-glibc-2.40-66-dev/include/features.h: At top level:
> /nix/store/dj43clc5ff7jjnfmhbaj6q4q0h8kpfpm-glibc-2.40-66-dev/include/features.h:422:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp]
> 422 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O)
> | ^~~~~~~
> make[4]: *** [Makefile:896: breaders.o] Error 1
> make[4]: *** Waiting for unfinished jobs....
> make[4]: *** [Makefile:896: eval.o] Error 1
> make[4]: *** [Makefile:896: alloc.o] Error 1
> make[4]: *** [Makefile:896: dynarray.o] Error 1
> make[4]: *** [Makefile:896: command.o] Error 1
> make[4]: *** [Makefile:896: datafile.o] Error 1
> make[4]: *** [Makefile:896: color.o] Error 1
> make[4]: *** [Makefile:896: contour.o] Error 1
> make[4]: *** [Makefile:896: axis.o] Error 1
> make[4]: Leaving directory '/build/gnuplot-5.0.1/src'
> make[3]: *** [Makefile:955: all-recursive] Error 1
> make[3]: Leaving directory '/build/gnuplot-5.0.1/src'
> make[2]: *** [Makefile:630: all] Error 2
> make[2]: Leaving directory '/build/gnuplot-5.0.1/src'
> make[1]: *** [Makefile:417: all-recursive] Error 1
> make[1]: Leaving directory '/build/gnuplot-5.0.1'
> make: *** [Makefile:355: all] Error 2
For full logs, run:
nix log /nix/store/xy2d25qg4ip4aa7jyssazrr6f2fscdm0-gnuplot-5.0.1.drv
|
makeの中ではどの処理でコケているのかを知るために、このエラーメッセージの末尾に表示された
1
|
nix log /nix/store/xy2d25qg4ip4aa7jyssazrr6f2fscdm0-gnuplot-5.0.1.drv
|
を実行することで得られる詳細なエラーメッセージを見てみました(とても長いので、以下にリンクを置いておきます)。
build_error.log
この詳細なエラーメッセージからは、非常に多くのソースコード上で共通して以下の部分でコケていることが分りました。
1
2
3
|
#ifndef lint
static char *RCSid() { return RCSid("$Id: datafile.c,v 1.290.2.9 2015/04/22 22:25:26 sfeam Exp $"); }
#endif
|
この時点では、これをCのバージョンの問題だと思いbuildPhaseにてCFLAGSにstd=c11,std=c99等を追加して試しましたがダメでした。
そこで、gcc自体のバージョンの問題では?と考えgccの代りに
gcc14,gcc13を試したところ、gcc13を指定した場合で正常にビルドができるようになりました。
記事の執筆中に調べて分ったことなのですが、先程のコードスニペットは、最近のC23で廃止されたK&Rスタイルの関数のコードなので、恐らくそれをコンパイルできないコンパイラ&コンパイルオプションでビルドしようとしたことが原因と考えられます。
さて、ここまででビルドに成功したので、以下のような簡単なgnuplotのコマンドを実行してみました。
しかし、GUIのplot画面が表示されませんでした。
最初は、GUI関係だろうと考えて、xorg 関係のパッケージ(xorg.libX11など)の追加も試しましたが、ダメでした。
そこで、nixpkgsではもちろんgnuplotは提供されているので、nixpkgsでのビルドの設定を見てみました。
なんとなく、pangoというパッケージが関係しそうに思えたのでこれをbuildInputsに追加してビルドを実行してみたところ、GUIのplot表示が可能になりました。
要件3,4(コードを読む環境)について
ここまで来れば後は簡単です。
gdbはgdbパッケージを追加すれば良いし、clangdはclang-toolsに含まれるのでそれを追加するだけです。
少しだけややこしいのは、clangdでソースを解析するに必要なcompile_commands.jsonです。
CMakeでビルドされるプロジェクトでは、CMakeの機能で生成が可能なのですが、gnuplotはCMakeではない方法でビルドされるプロジェクトなのでこの方法が使えません。
そこで、bearというツールを使ってビルドを
で実行して、ビルドプロセスを解析することでcompile_commands.jsonを生成しました。
完成したflake.nix
最終的に完成したflake.nixは以下のようになりました
このflakeでは、nix buildによる全行程が自動で実行されるビルドもnix-shellに入って手動で行うビルドも両方とも可能です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
{
description = "flake for Seach of LS software";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs =
{ self, nixpkgs }:
let
platform = "x86_64-linux";
pkgs = nixpkgs.legacyPackages."${platform}";
nParallels = "11";
gnuplot_debug = pkgs.stdenv.mkDerivation rec {
pname = "gnuplot";
version = "5.0.1";
src = pkgs.fetchurl {
url = "https://sourceforge.net/projects/gnuplot/files/gnuplot/${version}/gnuplot-${version}.tar.gz";
hash = "sha256-fLxVfnHfWB6lIBI/tDnepfBzrcyQEKKIXcgNTtKLPEc=";
};
nativeBuildInputs = with pkgs; [
gcc13
gnumake
pango
];
buildInputs = with pkgs; [ ];
dontConfigure = true;
buildPhase = ''
CFLAGS="-O0 -g" ./configure --prefix=$out
make -j${nParallels}
'';
installPhase = ''
make install
'';
};
in
{
packages.${platform}.default = gnuplot_debug;
devShells.${platform}.default = pkgs.mkShell {
packages = with pkgs; [
# for build
gcc13
gnumake
pango
# for code reading
bear
## for clangd
clang-tools
# debugger
gdb
];
};
};
}
|
最後にビルド&実行方法を載せておきます。
1
2
3
|
nix build # ビルド
./result/bin/gnuplot # 実行
|
- ソースの変更&ビルドの繰り返しで使用する手動の方法
1
2
3
4
5
6
7
8
9
10
|
wget https://sourceforge.net/projects/gnuplot/files/gnuplot/5.0.1/gnuplot-5.0.1.tar.gz
tar -xzvf gnuplot-5.0.1.tar.gz
mkdir build && cd build
# インストール先はお好みで、筆者は `<project root>/build/install`にインストールした.
CFLAGS="-O0 -g" ../gnuplot-5.0.1/configure --prefix="$PWD/install"
bear -- make -j11 # to generate compile_commands.json
make install
./build/install/bin/gnuplot # 実行
|