4. Nix를 사용하여 패키지 빌드
Nix는 다양한 기능을 제공하지만, 패키지 관리는 아마도 가장 잘 알려진 기능일 것입니다. 이 튜토리얼에서는 설치된 Nix CLI를 사용하여 Nixpkgs에 포함된 Nix [패키지]를 빌드하고 실행해 보겠습니다. 이 가이드의 후반부에서는 로컬 flake에 정의된 Nix 패키지를 빌드하고 실행해 보겠습니다.
Nixpkgs에서 패키지 빌드
먼저 bat을 빌드해 보겠습니다. bat은 Rust로 작성된 cat의 구문 강조 버전이며, Nixpkgs에 정의된 Nix 패키지가 포함되어 있습니다. 빈 디렉터리에 빌드합니다(쓰기 권한이 있는 디렉터리에서 실행해야 합니다).
mkdir build-nix-package && cd build-nix-packagenix build "https://flakehub.com/f/NixOS/nixpkgs/*#bat"여기서 nixpkgs는 GitHub의 NixOS/nixpkgs 저장소에 대한 [플레이크 참조][참조]이고, #bat는 Nixpkgs 플레이크에서 bat 출력을 빌드하고 있음을 나타냅니다.
빌드가 완료되면 ls .를 실행하면 현재 디렉터리에 result라는 파일이 표시됩니다. result는 실제로 Nix store에 있는 빌드된 패키지에 대한 [심볼릭 링크]이며, 다음에서 확인할 수 있습니다.
readlink result다음과 같은 경로가 표시되어야 합니다(사용자의 컴퓨터에서는 약간 다를 수 있음).
/nix/store/ 1. Nix store prefixsglc12hc6pc68w5ppn2k56n6jcpaci16 2. Hash part-bat-0.22.1 3. Package name
여기서 발생한 문제는 Nix CLI가 다음과 같은 작업을 수행했기 때문입니다.
- Nixpkgs에서 Nix 코드를 다운로드했습니다.
bat이라는 이름의 패키지 정의를 찾았습니다(코드는 여기 참조).bat빌드 지침을 사용하여 [패키지][패키지]를 빌드했습니다.- Nix의 해시 기반 경로 시스템을 사용하여 [Nix 저장소][저장소]에 결과를 저장했습니다.
- TODO: 여기에 대체 코드를 추가하고 향후 캐싱 문서에 대한 링크를 추가하세요. */}
이제 bat을 실행할 수 있습니다.
./result/bin/bat --help🚀 성공! Nix를 사용하여 패키지를 빌드하고 실행했습니다.
$LANGUAGE로 작성된 도구용 패키지 빌드
Nix의 가장 큰 장점 중 하나는 패키지 빌드가 매우 유연하여 거의 모든 프로그래밍 언어로 작성된 패키지에 대한 패키지를 만들 수 있다는 것입니다. 이 섹션에서는 다양한 언어로 작성된 도구용 패키지를 빌드하고 실행하여 이를 살펴보겠습니다. 아래에서 하나를 선택하여 몇 가지 예를 확인해 보세요.
Select your language
Let’s build and run CMake:
nix build "nixpkgs#cmake"./result/bin/cmake --helpLet’s build and run Pandoc:
nix build "nixpkgs#pandoc"./result/bin/pandoc --versionLet’s build and run npm:
nix build "nixpkgs#nodePackages.npm"./result/bin/npm --helpls result/bin을 실행하면 패키지에 npx도 포함되어 있는 것을 알 수 있습니다.
Let’s build and run pip:
nix build "nixpkgs#python3Packages.pip"./result/bin/pip --helpLet’s build and run kubectl:
nix build "nixpkgs#kubectl"./result/bin/kubectl --helpLet’s build and run ripgrep:
nix build "nixpkgs#ripgrep"./result/bin/rg --helpLet’s build and run scalafmt:
nix build "nixpkgs#scalafmt"./result/bin/scalafmt --versionNixpkgs를 넘어
Nixpkgs는 알려진 우주에서 가장 큰 Nix 패키지 저장소이지만, 모든 Nix flake는 패키지 outputs를 포함할 수 있습니다. 다른 저장소에서 패키지를 빌드해 보겠습니다. 이번에는 홈 환경 구성에 널리 사용되는 Nix 도구인 Home Manager용 패키지를 빌드해 보겠습니다.
nix build "https://flakehub.com/f/nix-community/home-manager/*"Here, https://flakehub.com/f/nix-community/home-manager/* is a flake reference to the nix-community/home-manager repo on FlakeHub.
To run Home Manager:
./result/bin/home-manager --help패키지를 Nixpkgs로 업스트림하는 것은 항상 가능한 옵션이지만, Nix를 사용하면 flake.nix를 사용하여 모든 공개 Git 저장소를 통해 패키지를 배포할 수 있다는 점을 기억하는 것이 좋습니다.
로컬 플레이크에서 패키지 빌드
이 가이드의 앞서에서는 프로세스의 메커니즘을 파악하기 위해 Nixpkgs에 정의된 Nix 패키지를 빌드했습니다. 이 가이드에서는 좀 더 자세히 살펴보고 로컬 Nix 플레이크에 정의된 Nix 패키지를 빌드해 보겠습니다.
위와 같이 원하는 언어를 선택하세요.
Select your language
To get started in your project, create an empty directory and initialize a flake template:
mkdir nix-cpp-pkg && cd nix-cpp-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#cpp-pkg"mkdir nix-haskell-pkg && cd nix-haskell-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#haskell-pkg"mkdir nix-javascript-pkg && cd nix-javascript-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#javascript-pkg"mkdir nix-python-pkg && cd nix-python-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#python-pkg"mkdir nix-go-pkg && cd nix-go-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#go-pkg"mkdir nix-rust-pkg && cd nix-rust-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#rust-pkg"mkdir nix-scala-pkg && cd nix-scala-pkgnix flake init --template "github:DeterminateSystems/zero-to-nix#scala-pkg"Whichever language you’ve selected, you can build the Nix package defined in the local flake by running:
nix buildThis command determines that the local flake has a package output that defines how the package is built.
In this particular flake there’s a default package, which enables us to run nix build without specifying an output, but if the package were output as packages.mypkg, for example, we’d need to run nix build .#mypkg to build it.
Here’s the package definition that builds our C++ package:
{ packages = forAllSystems ({ pkgs }: { default = let binName = "zero-to-nix-cpp"; cppDependencies = with pkgs; [ boost gcc poco ]; in pkgs.stdenv.mkDerivation { name = "zero-to-nix-cpp"; src = self; buildInputs = cppDependencies; buildPhase = "c++ -std=c++17 -o ${binName} ${./main.cpp} -lPocoFoundation -lboost_system"; installPhase = '' mkdir -p $out/bin cp ${binName} $out/bin/ ''; }; });}For the full flake, see flake.nix on GitHub or run cat flake.nix.
What you see here is a derivation that defines how to build the package, more specifically the mkDerivation function provided by Nix’s standard environment.
The package that results when you run nix build is a CLI tool that outputs a message.
To run that tool:
./result/bin/zero-to-nix-cppYou should see this output:
Hello from Nix + C++!Here’s the package definition that builds our Haskell package:
{ packages = forAllSystems ({ pkgs }: { default = pkgs.haskellPackages.mkDerivation { pname = "zero-to-nix-haskell"; version = "0.1.0"; src = self; license = pkgs.lib.licenses.cc-by-sa-40; executableHaskellDepends = with pkgs.haskellPackages; [ base ]; }; });}For the full flake, see flake.nix on GitHub or run cat flake.nix.
What you see here is a derivation that defines how to build the package, more specifically the haskellPackages.developPackage function provided by Nixpkgs.
The package that results when you run nix build is a CLI tool that outputs a message.
To run that tool:
./result/bin/zero-to-nix-haskellYou should see this output:
Hello from inside a Haskell program built with Nix!Here’s the package definition that builds our JavaScript package:
{ packages = forAllSystems ({ pkgs }: { default = pkgs.buildNpmPackage { name = "zero-to-nix-javascript";
buildInputs = with pkgs; [ nodejs_latest ];
src = self;
npmDeps = pkgs.importNpmLock { npmRoot = ./.; };
npmConfigHook = pkgs.importNpmLock.npmConfigHook;
installPhase = '' mkdir $out cp dist/index.html $out ''; }; });}For the full flake, see flake.nix on GitHub or run cat flake.nix.
What you see here is a derivation that defines how to build the package, more specifically the buildNpmPackage function, which is a wrapper around Nix’s built-in derivation function.
The package that results when you run nix build is a website built using the [Vite] framework.
To view that website, open the HTML file at result/index.html.
Python 패키지를 빌드할 수 있는 패키지 정의는 다음과 같습니다.
{ packages = forAllSystems ({ pkgs }: { default = let python = pkgs.python39; in python.pkgs.buildPythonApplication { name = "zero-to-nix-python";
buildInputs = with python.pkgs; [ pip ];
src = ./.; }; });}전체 플레이크는 GitHub에서 flake.nix를 참조하거나 cat flake.nix를 실행하세요.
여기 보이는 것은 패키지 빌드 방법을 정의하는 derivation입니다. 더 구체적으로는 Nix의 내장 derivation 함수를 감싸는 buildPythonApplication 함수입니다.
결과 패키지는 터미널에 출력하는 실행 파일입니다. 패키지를 실행하려면 다음을 수행하세요.
./result/bin/zero-to-nix-python다음과 같은 터미널 출력이 표시됩니다.
Hello from inside a Python program built with Nix!다음은 Go 패키지를 빌드할 수 있게 해주는 패키지 정의입니다.
{ packages = forAllSystems ({ pkgs }: { default = pkgs.buildGoModule { name = "zero-to-nix-go"; src = self; vendorHash = "sha256-Ay1/QqbO2MyYgqJZKxrt1FZzLSgXbhSK3ceFPUlFujw="; goSum = ./go.sum; subPackages = [ "cmd/zero-to-nix-go" ]; }; });}전체 플레이크는 GitHub에서 flake.nix를 참조하거나 cat flake.nix를 실행하세요.
여기 보이는 것은 패키지 빌드 방법을 정의하는 derivation입니다. 더 구체적으로는 Nix의 내장 derivation 함수를 감싸는 buildGoModule 함수입니다.
nix build를 실행하면 Gin 프레임워크를 사용하여 빌드된 웹 서버 패키지가 생성됩니다.
패키지를 실행하려면 다음을 수행하세요.
./result/bin/zero-to-nix-go다른 창에서 curl http://localhost:8080을 실행하여 서버로부터 메시지를 받습니다.
Rust 패키지를 빌드할 수 있게 해주는 패키지 정의는 다음과 같습니다.
{ packages = forAllSystems ({ pkgs }: { default = let rustPlatform = pkgs.makeRustPlatform { cargo = pkgs.rustToolchain; rustc = pkgs.rustToolchain; }; in rustPlatform.buildRustPackage { name = "zero-to-nix-rust"; src = ./.; cargoLock = { lockFile = ./Cargo.lock; }; }; });}전체 플레이크는 GitHub에서 flake.nix를 참조하거나 cat flake.nix를 실행하세요.
여기 보이는 것은 패키지 빌드 방법을 정의하는 derivation입니다. 더 구체적으로는 Nix의 내장 derivation 함수를 감싸는 buildRustPackage 함수입니다.
터미널에 출력되는 실행 파일인 결과 패키지를 실행하려면 다음을 실행하세요.
./result/bin/zero-to-nix-rustYou should see this terminal output:
Hello from Nix + Rust!거짓말은 하지 않겠습니다. Scala 패키징은 꽤 까다롭습니다.
다행히도 sbt-derivation이라는 서드파티 프로젝트가 있는데, 이 프로젝트는 Nix의 내장 derivation 함수를 감싸는 편리한 mkSbtDerivation 함수를 포함하여 유용한 도우미들을 제공합니다.
이 패키지의 전체 구성 요소는 GitHub에서 flake.nix를 참조하거나 cat flake.nix를 실행하세요.
터미널에 출력되는 실행 파일인 최종 패키지를 실행하려면 다음을 실행하세요.
./result/bin/zero-to-nix-scalaYou should see this terminal output:
Hello from Nix + Scala!여기서는 derivations 과 사용자 정의 패키지 생성에 대해 너무 깊이 다루지 않겠지만, 이 가이드를 통해 Nix 코드가 실제 빌드 출력으로 변환되는 과정을 살펴보겠습니다.