이 사이트는 의 를 yeokja로 기계 번역한 비공식 한국어판입니다. 정확한 내용은 원문을 확인하세요.

4. Nix로 패키지 빌드하기

빠른 시작/Nix로 패키지 빌드하기
가이드 4 / 8
이 가이드에서

→Nixpkgs에 정의된 Nix 패키지 빌드하기

→로컬 디렉터리에서 패키지 실행하기

→원하는 프로그래밍 언어로 플레이크 템플릿 초기화하기

→템플릿의 flake.nix에서 Nix 패키지 빌드하기

Nix는 여러 가지 일을 할 수 있지만, 아마도 가장 잘 알려진 것은 패키지 관리일 것입니다. 이 튜토리얼에서는 설치한 Nix CLI를 사용해 Nixpkgs에 포함된 몇 가지 Nix 패키지를 빌드하고 실행해 보겠습니다. 가이드 후반부에서는 로컬 플레이크에 정의된 Nix 패키지를 빌드하고 실행해 보겠습니다.

Nixpkgs에서 패키지 빌드하기

먼저 빈 디렉터리에서 bat을 빌드해 봅시다. bat은 Rust로 작성된 cat의 구문 강조 버전이며, Nixpkgs에 Nix 패키지가 정의되어 있습니다(반드시 쓰기 권한이 있는 디렉터리에서 실행하십시오):

Build the bat package locally
mkdir build-nix-package && cd build-nix-package
nix build "https://flakehub.com/f/NixOS/nixpkgs/*#bat"

여기서 nixpkgs는 GitHub의 NixOS/nixpkgs 저장소를 가리키는 플레이크 참조이고, #bat은 Nixpkgs 플레이크의 bat 출력을 빌드한다는 뜻입니다.

빌드가 끝나면 ls .을 실행하십시오. 현재 디렉터리에 result라는 항목이 보일 것입니다. result는 사실 Nix 스토어에 있는 빌드된 패키지를 가리키는 심볼릭 링크이며, 다음과 같이 확인할 수 있습니다:

Display the Nix store path for the build result
readlink result

다음과 같은 경로가 보일 것입니다(사용하는 컴퓨터에서는 조금 다를 수 있습니다):

        
/nix/store/ 1. Nix 스토어 접두사
sglc12hc6pc68w5ppn2k56n6jcpaci16 2. 해시 부분
-
bat-0.22.1 3. 패키지 이름

여기서 Nix CLI가 수행한 작업은 다음과 같습니다:

  • Nixpkgs의 Nix 코드를 다운로드했습니다
  • 이름이 bat인 패키지 정의를 찾았습니다(코드는 이 저장소에 있습니다)
  • bat의 빌드 지침을 사용해 패키지를 빌드했습니다
  • Nix의 해시 기반 경로 시스템을 사용해 결과를 Nix 스토어에 저장했습니다

이제 bat을 실행할 수 있습니다:

Run bat from the local build result
./result/bin/bat --help

🚀 성공입니다! Nix로 패키지를 빌드하고 실행했습니다.

$LANGUAGE로 작성된 도구의 패키지 빌드하기

Nix의 큰 장점 중 하나는 패키지 빌드가 매우 유연하다는 점이며, 덕분에 거의 모든 프로그래밍 언어로 작성된 대상의 패키지를 만들 수 있습니다. 이 섹션에서는 다양한 언어로 작성된 도구의 패키지를 빌드하고 실행하면서 이를 살펴보겠습니다. 아래에서 하나를 선택해 몇 가지 예시를 확인하십시오:

언어를 선택하세요

CMake를 빌드하고 실행해 봅시다:

Build and then run CMake
nix build "nixpkgs#cmake"
./result/bin/cmake --help

Pandoc을 빌드하고 실행해 봅시다:

Build and then run Pandoc
nix build "nixpkgs#pandoc"
./result/bin/pandoc --version

npm을 빌드하고 실행해 봅시다:

Build and then run npm
nix build "nixpkgs#nodePackages.npm"
./result/bin/npm --help

ls result/bin을 실행하면 패키지에 npx도 포함되어 있음을 알 수 있습니다.

pip을 빌드하고 실행해 봅시다:

Build and then run pip
nix build "nixpkgs#python3Packages.pip"
./result/bin/pip --help

kubectl을 빌드하고 실행해 봅시다:

Build and then run kubectl
nix build "nixpkgs#kubectl"
./result/bin/kubectl --help

ripgrep을 빌드하고 실행해 봅시다:

Build and then run ripgrep
nix build "nixpkgs#ripgrep"
./result/bin/rg --help

scalafmt를 빌드하고 실행해 봅시다:

Build and then run scalafmt
nix build "nixpkgs#scalafmt"
./result/bin/scalafmt --version

Nixpkgs 너머로

Nixpkgs는 알려진 우주에서 단연 가장 큰 Nix 패키지 저장소이지만, 어떤 Nix 플레이크든 패키지 출력을 포함할 수 있습니다. 이번에는 다른 저장소의 패키지를 빌드해 봅시다. 홈 환경을 설정하는 데 널리 쓰이는 Nix 도구인 Home Manager의 패키지입니다:

Build Home Manager
nix build "https://flakehub.com/f/nix-community/home-manager/*"

여기서 https://flakehub.com/f/nix-community/home-manager/*는 FlakeHub에 있는 nix-community/home-manager 저장소를 가리키는 플레이크 참조입니다. Home Manager를 실행하려면 다음과 같이 하십시오:

Run Home Manager from the build result
./result/bin/home-manager --help

패키지를 Nixpkgs 업스트림에 올리는 방법도 언제든 선택할 수 있지만, Nix를 사용하면 flake.nix가 있는 공개 Git 저장소라면 어디서든 패키지를 배포할 수 있다는 점을 기억해 두면 좋습니다.

로컬 플레이크에서 패키지 빌드하기

이 가이드의 앞부분에서는 Nixpkgs에 정의된 Nix 패키지를 빌드하면서 그 과정이 어떻게 작동하는지 대략 살펴보았습니다. 이 가이드에서는 조금 더 깊이 들어가 로컬 Nix 플레이크에 정의된 Nix 패키지를 빌드해 보겠습니다.

앞에서와 같이 원하는 언어를 선택하십시오:

언어를 선택하세요

프로젝트를 시작하려면 빈 디렉터리를 만들고 플레이크 템플릿을 초기화하십시오:

Initialize a flake template for C++
mkdir nix-cpp-pkg && cd nix-cpp-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#cpp-pkg"
Initialize a flake template for Haskell
mkdir nix-haskell-pkg && cd nix-haskell-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#haskell-pkg"
Initialize a flake template for JavaScript
mkdir nix-javascript-pkg && cd nix-javascript-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#javascript-pkg"
Initialize a flake template for Python
mkdir nix-python-pkg && cd nix-python-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#python-pkg"
Initialize a flake template for Go
mkdir nix-go-pkg && cd nix-go-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#go-pkg"
Initialize a flake template for Rust
mkdir nix-rust-pkg && cd nix-rust-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#rust-pkg"
Initialize a flake template for Scala
mkdir nix-scala-pkg && cd nix-scala-pkg
nix flake init --template "github:DeterminateSystems/zero-to-nix#scala-pkg"

어떤 언어를 선택했든 다음 명령을 실행하면 로컬 플레이크에 정의된 Nix 패키지를 빌드할 수 있습니다:

Build a Nix package in the local flake
nix build

이 명령은 로컬 플레이크에 패키지를 빌드하는 방법을 정의한 패키지 출력이 있는지 확인합니다. 이 플레이크에는 default 패키지가 있으므로 출력을 지정하지 않고도 nix build를 실행할 수 있지만, 예를 들어 패키지가 packages.mypkg로 출력된다면 이를 빌드하기 위해 nix build .#mypkg를 실행해야 합니다.

C++ 패키지를 빌드하는 패키지 정의는 다음과 같습니다:

flake.nix
{
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/share"
cp -R dist/. "$out/share"/
'';
};
});
}

전체 플레이크는 GitHub의 flake.nix를 참고하거나 cat flake.nix를 실행해 확인하십시오. 여기에 보이는 것은 패키지를 빌드하는 방법을 정의하는 derivation이며, 더 구체적으로는 Nix의 표준 환경이 제공하는 mkDerivation 함수입니다.

nix build를 실행해 만들어지는 패키지는 메시지를 출력하는 CLI 도구입니다. 이 도구를 실행하려면 다음과 같이 하십시오:

Run the compiled binary
./result/bin/zero-to-nix-cpp

다음과 같은 출력이 나타나야 합니다:

Expected output
Hello from Nix + C++!

Haskell 패키지를 빌드하는 패키지 정의는 다음과 같습니다:

flake.nix
{
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
];
};
});
}

전체 플레이크는 GitHub의 flake.nix를 참고하거나 cat flake.nix를 실행해 확인하십시오. 여기에 보이는 것은 패키지를 빌드하는 방법을 정의하는 derivation이며, 더 구체적으로는 Nixpkgs가 제공하는 haskellPackages.developPackage 함수입니다.

nix build를 실행해 만들어지는 패키지는 메시지를 출력하는 CLI 도구입니다. 이 도구를 실행하려면 다음과 같이 하십시오:

Run the compiled binary
./result/bin/zero-to-nix-haskell

다음과 같은 출력이 나타나야 합니다:

Expected output
Hello from inside a Haskell program built with Nix!

JavaScript 패키지를 빌드하는 패키지 정의는 다음과 같습니다:

flake.nix
{
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
'';
};
});
}

전체 플레이크는 GitHub의 flake.nix를 참고하거나 cat flake.nix를 실행해 확인하십시오. 여기에 보이는 것은 패키지를 빌드하는 방법을 정의하는 derivation이며, 더 구체적으로는 Nix에 내장된 derivation 함수를 감싸는 래퍼인 buildNpmPackage 함수입니다.

nix build를 실행해 만들어지는 패키지는 [Vite] 프레임워크로 빌드한 웹사이트입니다. 이 웹사이트를 보려면 result/share/index.html에 있는 HTML 파일을 여십시오.

다음은 Python 패키지를 빌드할 수 있게 해 주는 패키지 정의입니다:

flake.nix
{
packages = forAllSystems ({ pkgs }: {
default =
let
python = pkgs.python3;
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 함수입니다.

이렇게 만들어진 패키지는 터미널에 출력하는 실행 파일입니다. 패키지를 실행하려면 다음과 같이 하십시오:

Run the built executable
./result/bin/zero-to-nix-python

다음과 같은 터미널 출력이 표시되어야 합니다:

Hello from inside a Python program built with Nix!

다음은 이 Go 패키지를 빌드할 수 있게 해 주는 패키지 정의입니다:

flake.nix
{
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 프레임워크로 만든 웹 서버입니다. 패키지를 실행하려면 다음과 같이 하십시오:

Run the compiled binary
./result/bin/zero-to-nix-go

다른 창에서 curl http://localhost:8080을 실행하면 서버로부터 메시지를 받을 수 있습니다.

다음은 이 Rust 패키지를 빌드할 수 있게 해 주는 패키지 정의입니다:

flake.nix
{
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 함수입니다.

터미널에 출력하는 실행 파일인 결과 패키지를 실행하려면 다음과 같이 하십시오:

Run the compiled binary
./result/bin/zero-to-nix-rust

다음과 같은 터미널 출력이 표시되어야 합니다:

Hello from Nix + Rust!

솔직히 말씀드리면 Scala를 패키징하는 것은 꽤 까다롭습니다. 다행히 sbt-derivation이라는 서드파티 프로젝트가 몇 가지 유용한 헬퍼를 제공하며, 그중에는 Nix의 내장 함수인 derivation을 감싼 래퍼인 mkSbtDerivation이라는 편리한 함수도 있습니다.

이 패키지의 전체 플레이크는 GitHub의 flake.nix를 참고하거나 cat flake.nix를 실행하십시오. 터미널에 출력하는 실행 파일인 결과 패키지를 실행하려면 다음과 같이 하십시오:

Run the built executable
./result/bin/zero-to-nix-scala

다음과 같은 터미널 출력이 표시되어야 합니다:

Hello from Nix + Scala!

여기에서는 derivation과 직접 패키지를 만드는 방법을 더 깊이 다루지 않겠지만, 이 가이드를 통해 Nix 코드가 실제 빌드 출력으로 바뀌는 과정을 이해하셨기를 바랍니다.