![당신의 첫 번째 파생](https://linux55.com/image/210691/%EB%8B%B9%EC%8B%A0%EC%9D%98%20%EC%B2%AB%20%EB%B2%88%EC%A7%B8%20%ED%8C%8C%EC%83%9D.png)
nix 프로그램을 패키징하기 위한 간단한 파생물을 작성하고 이를 nixpkgs에 포함하기 위한 PR을 생성하려면 어떻게 해야 합니까?
(간단한 설명이 없어서 이렇게 글을 남깁니다.)
답변1
참고: 이 답변은 완전하지는 않지만 이미 좋은 출발점이 됩니다. 나중에 더 많은 언어별 콘텐츠를 추가할 계획입니다(또는 각 언어에 대한 질문을 만들고 이 답변도..."합리적으로"""짧게 유지할 수도 있습니다).
다음은 몇 가지 참고 자료입니다.
- 매뉴얼의 빠른 시작: 자세한 내용은 여기에서 다루겠습니다.
- 닉스 알약(특히 섹션 6): 훌륭하지만 상향식 접근 방식을 취합니다. 먼저 제가 혼란스러워하는 nix의 모든 내부를 설명합니다. 아마도 첫 번째 파생물을 작성하기 위해 모든 것을 배울 필요는 없을 것입니다. 여기서는 하향식 접근 방식을 취하여 대부분의 사용자가 직접 사용하고 싶어하는 기능을 제공하고 이후 작동 방식을 설명합니다.
- 선적 서류 비치표준 환경이것은 매우 훌륭하지만 정보가 많고 (불완전한) 예제가 거의 포함되어 있지 않습니다.
- 다른내 대답, 그러나 미리 컴파일된 바이너리를 빌드하는 데만 해당됩니다.
당신의 첫 번째 파생
일반인의 관점에서 보면 파생은 프로그램 구축의 비결입니다. 요리할 때 재료를 케이크로 결합하려면 몇 가지 재료(nix의 소스 및 종속성이라고도 함)와 몇 가지 단계(절차라고도 함)가 필요합니다.
간단한 C 프로그램
제가 상상할 수 있는 가장 간단한 C 프로그램인 간단한 예부터 시작해 보겠습니다. program.c
원하는 폴더의 파일 에 쓸 수 있습니다 (이 예에서는).
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
유도
그런 다음 nix에게 이 프로그램을 컴파일하는 방법을 알려주어야 합니다. 따라서 파일을 만듭니다 derivation.nix
.
{ stdenv }:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
src = ./.;
nativeBuildInputs = [ ];
buildInputs = [ ];
buildPhase = ''
gcc program.c -o myprogram
'';
installPhase = ''
mkdir -p $out/bin
cp myprogram $out/bin
'';
}
이는 입력이 종속성(케이크의 "성분", stdenv
여기서는 유용한 유틸리티)이고 다음 덕분에 파생물을 출력하는 기능을 설명합니다 stdenv.mkDerivation
.이 프로세스가 모든 컴파일된 파일을 포함하는 폴더를 출력한다고 상상할 수 있습니다.. 나는 mkDerivation
몇 가지 정보를 제공했습니다:
- 소스: 여기의 소스는 현재 폴더에 있지만 나중에 살펴보겠지만 네트워크에서 소스를 가져올 수도 있습니다.
nativeBuildInputs
프로그램을 컴파일하는 데 필요한 종속성(gcc
기본적으로 항상 포함되므로 여기서는 아무것도 지정할 필요가 없습니다)buildInputs
프로그램을 실행하는 데 필요한 종속성(일반적으로 여기에 라이브러리를 넣습니다)buildPhase
프로그램 구축 지침(bash 스크립트) 이 단계가 시작되면 소스 코드가 포함된 폴더에 드롭됩니다.installPhase
프로그램을 "설치"하는 방법을 설명하는 지침(아래 참조)
실제로 더 많은 단계(소스 압축 풀기, 패치, 구성...)가 있지만 이 예에서는 필요하지 않습니다.
뭐 하세요 installPhase
?
설치 단계에서는 최종 실행 파일/라이브러리/자산/...이 어디에 위치해야 하는지 알려줍니다. 일반적인 Linux 환경에서 바이너리는 일반적으로 /bin
, /usr/bin
또는 /usr/local/bin
, 라이브러리 또는 /lib
, /lib64
자산 에 복사됩니다 /share
. 모든 프로그램이 해당 항목을 같은 위치에 배치하면 금방 엉망이 될 수 있습니다.
Nix에서 모든 프로그램은 비슷한 경로(이 경로의 값은 /nix/store/someUniqueHash-programName-version
로 설정됨)에 자체 폴더를 갖고 있으며, 바이너리는 일반적인 Linux 폴더 계층 구조를 재현하여 라이브러리로, 자산으로 이동합니다. 따라서 파일을 어디에 넣어야 할지 확실하지 않다면 일반 Linux 배포판에서 파일을 어디에 넣어야 하는지 확인하고 경로 앞에 추가해야 합니다(몇 가지 예외는 있지만 더 이상 이유가 없기 때문에 대신 사용함). 폴더). 많은 빌드 시스템(cmake...)에는 프로그램을 설치할 위치를 나타내는 변수가 있습니다. : 일반적으로 이는 또는 등의 바이너리를 설치하는 것일 수 있습니다. 이 경우 일반적으로 일반적인 컴파일 명령을 간단히 설정하고 실행할 수 있습니다. 프로그램을 설치하면 Nix는 설치된 소프트웨어 파일에 대한 링크를 올바르게 생성합니다. 예를 들어 NixO에서는 전역적으로 설치된 바이너리가 링크됩니다.$out
installPhase
$out/bin
$out/lib
$out/share
$out/
$out/bin
$out/usr/local/bin
local
PREFIX
PREFIX
/
/usr/local
PREFIX/bin
PREFIX=$out
/run/current-system/sw/bin
$ ls /run/current-system/sw/bin -al | grep firefox
lrwxrwxrwx 1 root root 70 janv. 1 1970 firefox -> /nix/store/152drilm2qhjimzfx8mch0hmqvr27p29-firefox-99.0.1/bin/firefox
따라서 이 예에서는 설치 단계에서 폴더를 만들고 $out/bin
복사 단계에서 얻은 바이너리를 복사하기만 하면 됩니다. 이것이 바로 우리가 하는 일입니다!
어떻게 시도해 볼 수 있나요?
이를 시도하려면 종속성을 어디서 가져올지 지정해야 합니다(마찬가지로 케이크를 요리할 때 먼저 좋아하는 농부를 방문하여 계란을 구입해야 합니다). 따라서 다음을 포함하는 다른 파일을 만듭니다 ( 해당 파일이 먼저 검색되므로 default.nix
여기서 이름이 중요합니다 ).nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
여기에서는 기본적으로 nix에게 채널을 사용하여 <nixpkgs>
종속성을 가져오라고 지시하면 callPackage
올바르게 채워질 것입니다 derivation.nix
.
그럼, 그냥 실행
$ nix-build
마지막으로 파생 폴더 result
에 연결된 새 폴더가 있어야 합니다 .$out
$ ls -al | grep result
lrwxrwxrwx 1 leo users 55 sept. 13 20:59 result -> /nix/store/xi0hx472hzykl6xjw0hnmh0zjyp6sc52-program-1.0
그런 다음 다음을 사용하여 바이너리를 실행할 수 있습니다.
$ ./result/bin/myprogram
Hello, World!
축하합니다. 첫 번째 파생을 완료했습니다!
아래에서는 보다 복잡한 애플리케이션을 패키징하는 방법을 살펴보겠습니다. 하지만 그 전에 패키지를 설치하고 nixpkgs에 기여하는 방법을 살펴보겠습니다.
내 시스템에 설치할 수 있나요?
물론 이 포크를 설치할 수도 있습니다. 파일을 복사하고( default.nix
필요하지 않은 경우) /etc/nixos
설치된 패키지 목록을 다음으로 변경합니다.
environment.systemPackages = with pkgs; [
(callPackage ./derivation.nix {})
]
여기요!
명령형을 사용하여 모든 시스템에 설치할 수도 있습니다.
$ nix-env -i -f default.nix
내 파생물을 nixpkgs에 어떻게 제출합니까?
nixpkgs 프로젝트의 모든 패키지 표현식은 다음 위치에 있습니다.https://github.com/NixOS/nixpkgs거기에 자신만의 패키지를 추가할 수 있습니다! 이렇게 하려면 먼저 포크(풀 요청 수행)하고 리포지토리를 복제합니다. 그런 다음 복사하여 derivation.nix
프로그램 의 이름인 프로그램의 적용 범위 pkgs/CATEGORY/PACKAGE/default.nix
에 따라 적절하게 선택하십시오.CATEGORY
PACKAGE
물론 nixpkgs 저장소에는 프로그램의 소스 코드가 포함되어 있지 않으므로 외부 소스를 가리키도록 소스 속성을 변경해야 합니다(아래 참조).
그런 다음 nixpkgs에서 사용 가능한 모든 프로그램 목록을 찾았으므로 pkgs/top-level/all-packages.nix
다음 줄을 추가해야 합니다.
myprogram = callPackage ../CATEGORY/PACKAGE { };
이 파일에서(프로그램은 알파벳순으로 정렬됩니다). 테스트하려면 저장소의 루트로 이동하여 다음을 호출하세요.
$ nix-build -A myprogram
result
프로그램을 컴파일하고 이전처럼 테스트할 폴더를 만들어야 합니다.
작업이 완료되면 작업을 커밋하고 끌어오기 요청으로 제출하세요!
git을 처음 사용하거나 더 자세한 내용을 알고 싶다면 이 게시물을 좋아할 것입니다.https://discourse.nixos.org/t/how-to-find-needed-librarys-for-lined-source-bin-applications/39118/43?u=tobiasbora
출처가 온라인이라면 어떨까요?
대부분의 경우 온라인에 호스팅된 소스를 다운로드하려고 합니다. 문제 없습니다. src
예를 들어 github에서 다운로드하는 경우 속성을 변경하면 됩니다(getter 목록 참조).여기):
{ stdenv, lib, fetchFromGitHub }:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
# For https://github.com/myuser/myexample
src = fetchFromGitHub {
owner = "myuser";
repo = "myexample";
rev = "v${version}"; # If there is a release like v1.0, otherwise put the commit directly
sha256 = ""; # <-- dummy hash: after the first compilation this line will give an error and the correct hash. Replace lib.fakeSha256 with "givenhash". Or use nix-prefetch-git. On older nix, this might fail, use sha256 = lib.fakeSha256; instead.
};
buildPhase = ''
gcc program.c -o myprogram
'';
installPhase = ''
mkdir -p $out/bin
cp myprogram $out/bin
'';
}
이 줄을 자신의 해시로 변경 해야 합니다 sha256
(다운로드한 파일이 올바른지 확인해야 함). lib.fakeSha256
는 더미 해시이므로 처음 컴파일하면 해시가 잘못되었다는 오류가 발생합니다 truehash
. 따라서 해시를 이 값으로 바꾸십시오(비슷한 도구가 있지만 nix-prefetch-git
사용하지 않는다는 점을 인정해야 합니다). 경고: 이미 캐시에 있는 다른 프로그램의 해시를 사용하면 오류가 발생하지 않지만 다른 패키지의 소스가 크게 스파이크됩니다!
또한 nix는 자동으로 소스 코드에 대해 올바른 작업을 수행하려고 시도하며, 특히 다운로드한 zip 파일의 압축을 자동으로 푼다는 점에 유의하세요.
src = fetchurl {
url = "http://example.org/libfoo-source-${version}.tar.bz2";
sha256 = "0x2g1jqygyr5wiwg4ma1nd7w4ydpy82z9gkcv8vh2v8dn3y58v5m";
};
도서관 이용방법
이제 라이브러리(이 예에서는 ncurses)를 사용하여 프로그램을 좀 더 복잡하게 만들어 보겠습니다. 우리는 ncurses
hello-world 프로그램을 사용할 것입니다 :
#include <ncurses.h>
int main(int argc, char ** argv)
{
initscr(); // init screen and sets up screen
printw("Hello World"); // print to screen
refresh(); // refreshes the screen
getch(); // pause the screen output
endwin(); // deallocates memory and ends ncurses
return 0;
}
위와 같이 이 프로그램을 직접 컴파일하면 오류가 발생합니다.
program.c:1:10: fatal error: ncurses.h: No such file or directory
이는 ncurses를 종속성으로 추가하지 않았기 때문에 예상되는 현상입니다. 이렇게 하려면 공백으로 구분된 목록에 buildInputs
라이브러리를 추가합니다 ncurses
(입력 종속성의 첫 번째 줄에도 추가해야 함). 이렇게 하면 buildInputs
컴파일러가 프로그램의 바이너리에서 헤더 파일을 검색하게 됩니다. 사용 가능한 하위 디렉터리 include
...그리고 컴파일 명령을 업데이트합니다 -lncurses
.
{ stdenv, ncurses }:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
src = ./.;
buildInputs = [
ncurses
];
buildPhase = ''
gcc -lncurses program.c -o myprogram
'';
installPhase = ''
mkdir -p $out/bin
cp myprogram $out/bin
'';
}
이전과 같이 프로그램을 컴파일하고 실행하면 끝입니다!
프로그램 디버깅, 1부:nix-shell
nix-build
nix-build
컴파일을 캐시하지 않기 때문에 as를 사용하여 프로그램을 디버깅하는 것은 때때로 성가신 일이 될 수 있습니다 . 실패할 때마다 다음 번에 처음부터 컴파일을 시작합니다(이는 재현성을 보장하기 위해 필요합니다). 그러나 실제로 이것은 약간 성가실 수 있습니다... nix-shell
이 문제를 해결하기 위해 만들어졌습니다. 위 파일을 컴파일하기 위해 명령을 실행하면 gcc
gcc 및 ncurses 라이브러리가 전역적으로 설치되지 않기 때문에 직접 실패합니다(예를 들어 여러 프로젝트에서 동일한 라이브러리의 서로 다른 버전을 사용할 수 있도록 허용하는 기능입니다). 이 프로그램을 설치하는 셸을 만들려면 다음을 실행 nix-shell
하면 자동으로 프로그램의 종속성을 확인합니다.
$ nix-shell
$ gcc -lncurses program.c -o myprogram
$ ./myprogram
나중에 좀 더 고급 사용법을 살펴보겠습니다 nix-shell
.
기본 단계 및 후크를 사용하여 시간 절약
많은 프로그램이 다음을 사용하여 간단하게 컴파일되므로 프로그램을 컴파일하는 방법은 일반적으로 동일합니다.
$ ./configure --prefix=$out
$ make
$ make install
따라서 nix는 기본적으로 위의 명령을 시도합니다(패치, 테스트 등을 더 많이 시도합니다). 이것이 바로 nixpkgs의 많은 프로그램이 실제로 작성하는 데 어떤 단계도 필요하지 않은 이유입니다.
대부분의 단계는 실제로 구성 가능합니다. 예를 들어 단계의 특정 부분을 활성화/비활성화하고, makeFlags = [ "PREFIX=$(out)" ];
makefile에 플래그를 추가하는 등 일부 매개변수를 제공할 수 있습니다. 이러한 단계에 대한 전체 문서가 제공됩니다.설명서에, 더 구체적으로이 구역. 실제로 실행 중인 내용을 확인하려면 genericBuild
파일의 기능을 확인하세요.pkgs/stdenv/generic/setup.sh파일에 위에 기록된 기본 단계는 파생으로 재정의되지 않는 한 호출됩니다. nix-shell
나중에 살펴보겠지만, 사용된 코드를 직접 읽을 수도 있습니다 .
이러한 기본 단계는 종속성에 의해 재정의될 수도 있습니다. 예를 들어 프로그램이 cmake를 사용하는 경우 cmake
추가하면 cmake를 사용하도록 구성 단계가 자동으로 조정됩니다 nativeBuildInputs = [ cmake ];
(이는 설명서에 따라 구성할 수도 있음).여기). scons, ninja, meson에서도 유사한 동작이 발생합니다. 보다 일반적으로 nix는 빌드 프로세스를 수정하기 위해 특정 단계 전후에 실행될 여러 "후크"를 정의합니다. 그것들을 포함시키는 것만 nativeBuildInputs
으로도 충분합니다. 대부분의 후크가 문서화되어 있습니다.여기, 현재 위치:
autoPatchelfHook
nix에서 사용할 수 있도록 (일반적으로 독점) 바이너리를 자동으로 패치합니다(다른 답변도 참조하세요)여기)
예를 들어, 다음과 같이 (ncurse) 프로그램에서 CMake를 사용할 수 있습니다. CMakeLists.txt
프로그램을 컴파일하기 위한 일반적인 cmake 규칙이 포함된 파일을 만듭니다.
cmake_minimum_required(VERSION 3.10)
# set the project name
project(myprogram)
# Configure curses as a dependency
find_package(Curses REQUIRED)
include_directories(${CURSES_INCLUDE_DIR})
# add the executable
add_executable(myprogram program.c)
# Link the curses library
target_link_libraries(myprogram ${CURSES_LIBRARIES})
# Explains how to install the program
install(TARGETS myprogram DESTINATION bin)
이제 다음을 크게 단순화할 수 있습니다 derivation.nix
.
{ stdenv, ncurses, cmake }:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
src = ./.;
buildInputs = [
ncurses
cmake
];
}
nix-shell 및 nix 내부를 사용하여 프로그램 디버깅: 2부
참고: 이 섹션은 나머지 부분을 이해하는 데 필요하지 않으므로 건너뛰어도 됩니다.
nix-shell
위에서 캐싱을 활용하여 컴파일 시간을 절약하기 위해 필요한 모든 종속성을 갖춘 셸에 넣는 방법을 살펴보았습니다 . 물론 이 셸에서는 일반적인 명령을 실행하여 이전처럼 프로그램을 컴파일할 수 있지만 때로는 nix 빌더가 실행하는 것과 똑같은 명령을 실행하는 것이 더 나을 때도 있습니다.
이것은 또한 nix 내부에 대해 더 많이 배울 수 있는 기회이기도 합니다.닉스 알약자세한 내용을 알아보고위키피디아로 이동). 포크를 작성하면 nix는 .drv
패키지 빌드 방법을 간단한 json 형식으로 설명하는 파일을 포크합니다.
파일을 보려면 다음을 실행할 수 있습니다.
$ nix-shell
# (or "nix-shell -A myprogram" if you run it from nixpkgs)
$ nix show-derivation $(nix-instantiate | sed 's/!.*//')
{
"/nix/store/4ja3vvab4wswalczr7k0lw17dxb69nf7-program-1.0.drv": {
"outputs": {
"out": {
"path": "/nix/store/qv8s0lm7w0az90xjc90dy7rvjqmic9zz-program-1.0"
}
},
"inputSrcs": [
"/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh",
"/nix/store/zrpp5wmrq39ylqy73pbk3plvw5sx59vh-example"
],
"inputDrvs": {
"/nix/store/1av43alhcb8a894sz2cnnf9aldfdyb0h-stdenv-linux.drv": [
"out"
],
"/nix/store/6pj63b323pn53gpw3l5kdh1rly55aj15-bash-5.1-p16.drv": [
"out"
],
"/nix/store/p6y4zvhi9vjg8h7hli0ix9jxkl225ahk-ncurses-6.3-p20220507.drv": [
"dev"
],
"/nix/store/w6jf92i16rghx0jr4ix33snq4d237l8i-cmake-3.24.0.drv": [
"out"
]
},
"system": "x86_64-linux",
"builder": "/nix/store/1b9p07z77phvv2hf6gm9f28syp39f1ag-bash-5.1-p16/bin/bash",
"args": [
"-e",
"/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"
],
"env": {
"buildInputs": "/nix/store/kn8gbpi8bfxkzg6slyskz4y0d2pkl0xk-ncurses-6.3-p20220507-dev /nix/store/xjg2fzw513iig1cghd4mvcq5fh2cyv4y-cmake-3.24.0",
"builder": "/nix/store/1b9p07z77phvv2hf6gm9f28syp39f1ag-bash-5.1-p16/bin/bash",
"cmakeFlags": "",
"configureFlags": "",
"depsBuildBuild": "",
"depsBuildBuildPropagated": "",
"depsBuildTarget": "",
"depsBuildTargetPropagated": "",
"depsHostHost": "",
"depsHostHostPropagated": "",
"depsTargetTarget": "",
"depsTargetTargetPropagated": "",
"doCheck": "",
"doInstallCheck": "",
"mesonFlags": "",
"name": "program-1.0",
"nativeBuildInputs": "",
"out": "/nix/store/qv8s0lm7w0az90xjc90dy7rvjqmic9zz-program-1.0",
"outputs": "out",
"patches": "",
"propagatedBuildInputs": "",
"propagatedNativeBuildInputs": "",
"src": "/nix/store/zrpp5wmrq39ylqy73pbk3plvw5sx59vh-example",
"stdenv": "/nix/store/bj5n3k01mq8bysw0rcdm7jxvhc620pd3-stdenv-linux",
"strictDeps": "",
"system": "x86_64-linux",
"version": "1.0"
}
}
}
"out": …
정확한 출력 은 중요하지 않지만 몇 가지 중요한 부분이 있습니다. 먼저 포크는 출력 폴더, 소스 및 종속성, 빌드 중에 사용 가능한 일부 환경 변수 및 nix-shell 자동 채우기를 지정합니다. 다음과 같은 이유로 올바르게 구성했습니다 nix-shell
.
$ echo $out
/nix/store/qv8s0lm7w0az90xjc90dy7rvjqmic9zz-program-1.0
더 중요한 것은 다음과 같습니다.
"builder": "/nix/store/1b9p07z77phvv2hf6gm9f28syp39f1ag-bash-5.1-p16/bin/bash",
"args": [
"-e",
"/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"
],
이는 출력을 생성하기 위해 nix가 단순히 인수를 사용하여 빌더를 실행한다는 것을 의미합니다 /nix/store/…/bin/bash
(여기서는 bash 인터프리터일 뿐입니다).-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh
이 파일은 매우 간단합니다.
$ cat /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh
source $stdenv/setup
genericBuild
당신이 입력하면
$ cat $stdenv/setup
당신은 그것이 정확히 같다는 것을 알게 될 것입니다pkgs/stdenv/generic/setup.sh기본 단계에 대한 파일을 구성하십시오!
따라서 nix-shell
다음과 같은 방법을 사용하여 모든 단계를 한 번에 실행할 수 있습니다(다른 $out
폴더를 생성하면 읽기 전용 모드로 쓸 수 없습니다 /nix/store
).
cd empty_directory # important to make sure "source" folder is not existing, otherwise you get an error like "unpacker appears to have produced no directories". Sources will be unpacked in a subdirectory, and it must be removed every time you restart the download process (otherwise we get the above error).
export out=/tmp/out # Create a temporary folder to put the output of the derivation
set -x # Optional: to display all the command lines, useful to debug sometimes
source $stdenv/setup # In order to load the default phase of the derivation
set +e # Do not quit the shell on error/Ctrl-C ($stdenv/setup adds a "set -e")
genericBuild # start the build process.
마지막 줄을 다음으로 바꿔서 실행할 여러 단계를 지정할 수도 있습니다.
phases="buildPhase" genericBuild
단계 목록을 얻으려면 다음을 수행할 수 있습니다.
echo "$phases"
비어 있으면 기본값입니다.
$ typeset -f genericBuild | grep 'phases='
phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} configurePhase ${preBuildPhases:-} buildPhase checkPhase ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase ${preDistPhases:-} distPhase ${postPhases:-}"
다른 언어를 캡슐화
위에 제공된 지침은 확실히 많은 언어와 상황에 적용되지만 일부 언어는 환경 변수 및 종속성 측면에서 자체 요구 사항을 처리하기 위한 몇 가지 추가 도구를 제공합니다(예를 들어 pip
Python 종속성을 설치하는 데 실제로 사용할 수는 없습니다) ). 이 페이지에 기존 언어를 모두 나열하는 것은 어려울 수 있으므로 따라야 할 몇 가지 일반적인 제안 사항은 다음과 같습니다.
- 이것nixpkgs 매뉴얼기본적으로 각 언어에 대한 섹션이 있으므로 일반적으로 좋은 출발점이 됩니다.
- 이것닉스 위키때로는 특정 언어에 대한 추가 정보가 포함되어 있습니다. 도움이 되는지 확인해보세요
- 이것nixpkgs 저장소수천 개의 프로그램이 포함되어 있습니다. 이전에 패키지하려고 했던 것과 같은 프로그램을 누군가가 패키지했을 것입니다. 영감을 얻으려면 온라인 검색(때때로 일부 항목이 누락된 것 같음)을 사용하거나
rg
로컬 복사본에서 검색(더 나은 방법은 grep)을 사용하여 사용하려는 도구가 포함된 포크를 찾으세요.
그러나 간단하게 설명하기 위해 자주 발생할 수 있는 몇 가지 상황을 아래에 나열하겠습니다.
(종종 독점) 바이너리를 패키징하는 방법
나는 꽤 광범위한 답변을했습니다여기. 물론 솔루션 4(autoPatchElf) 또는 5-6(buildFHSUserEnv)에 관심이 있습니다... 기본적으로 바이너리를 복사하고 운 이 $out/bin
좋으면 추가하는 것만 으로도 충분합니다(프로그램에 자산이 있는 경우 복사할 수도 있습니다). 그것을 프로그램을 호출하는 링크나 스크립트 에 넣으세요 .autoPatchelfHook
nativeBuildInputs
$out/opt
$out/bin
$out/opt
쉘 스크립트를 패키징하는 방법
이 파일을 고려해 봅시다 myshellscript.sh
:
#!/usr/bin/bash
echo "Hello, world"
그냥 사용
{ stdenv }:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
src = ./.;
installPhase = ''
mkdir -p $out/bin
cp myshellscript.sh $out/bin
chmod +x $out/bin/myshellscript.sh # not needed if the file is already executable
'';
}
patchShebangsAuto
bash 스크립트는 후크에 의해 자동으로 패치됩니다.기본적으로 수리 단계에 나타납니다..
간단한 빌더를 사용하여 이 파생물을 더욱 작게 만드는 방법에 대해 자세히 알아보세요!
래퍼 또는 실행 파일을 추가하는 방법
예를 들어 패키지가 작동하려면 일부 실행 파일이 필요하다고 가정해 보겠습니다 cowsay
. 왜냐하면 nix는 아름답게 설명된 것처럼 충돌을 제한하기 위해 패키지 간에 "스텔스"(순도라고도 함)를 유지하려고 하기 때문입니다.여기(아마도 프로그램마다 다른 버전이 필요할 수 있습니다 .) 환경 변수 에 "사용 가능" cowsay
하다고 가정할 수 없습니다 . 따라서 프로그램을 호출하기 전에 이 변수를 추가 해야 합니다 . 이는 실제 프로그램을 호출하기 전에 (필요한 경우 더 많은 환경 변수도 포함) 설정 되는 소위 "래퍼"로 원래 프로그램을 대체함으로써 수행됩니다 .cowsay
$PATH
cowsay
$PATH
간단한 bash 스크립트에 대해 이 단계를 더 쉽게 만들 수 있는 도구를 나중에 살펴보겠지만 래퍼는 많은 상황에서 유용하며 지금 사용 방법을 배우는 것은 확실히 시간 낭비가 아닐 것입니다.
이제 이 스크립트를 패키징해 보겠습니다 myshellscript.sh
.
#!/usr/bin/bash
cowsay "My first wrapper!"
이것을 사용하십시오 derivation.nix
:
{ lib, stdenv, cowsay, makeBinaryWrapper}:
stdenv.mkDerivation rec {
name = "program-${version}";
version = "1.0";
src = ./.;
nativeBuildInputs = [
makeBinaryWrapper # You can also use makeWrapper to use a bash wrapper, but this won't be compatible with MacOs that expects binary loaders
];
buildInputs = [
cowsay
];
installPhase = ''
mkdir -p $out/bin
cp myshellscript.sh $out/bin
chmod +x $out/bin/myshellscript.sh
wrapProgram $out/bin/myshellscript.sh \
--prefix PATH : ${lib.makeBinPath [ cowsay ]}
'';
}
입력을 추가한 방법 cowsay
과 다음을 사용하여 래퍼를 만든 방법을 확인하세요.
wrapProgram $out/bin/myshellscript.sh \
--prefix PATH : ${lib.makeBinPath [ cowsay ]}
'';
cowsay
경로에 추가합니다 . 이제 nix-build
(일반적인 파일을 잊지 말고 ) 이제 이진 파일임을 default.nix
알 수 있습니다 (어쨌든 읽을 수 있음 )... 이 파일이 정확히 무엇을 하는지 확인하기 어렵기 때문에 대신 사용하고 싶을 수도 있습니다. 사용 중이지만 "보안" 이유로 MacO에서는 작동하지 않습니다. 여기에서 다음과 같은 내용을 읽을 수 있습니다../result/bin/myshellscript.sh
less
makeWrapper
makeBinWrapper
$ cat result/bin/myshellscript.sh
#! /nix/store/1b9p07z77phvv2hf6gm9f28syp39f1ag-bash-5.1-p16/bin/bash -e
PATH=${PATH:+':'$PATH':'}
PATH=${PATH/':''/nix/store/mrl0n0kphz0xwvv8qbk2xyz2x1pr2f76-cowsay-3.04/bin'':'/':'}
PATH='/nix/store/mrl0n0kphz0xwvv8qbk2xyz2x1pr2f76-cowsay-3.04/bin'$PATH
PATH=${PATH#':'}
PATH=${PATH%':'}
export PATH
exec -a "$0" "/nix/store/xrz4cv51nd8n1bawfw5i6vd4yizzmajb-program-1.0/bin/.myshellscript.sh-wrapped" "$@"
이 코드는 약간 복잡하지만 기본적으로 Cowsay의 바이너리를 경로 시작 부분에 추가한 다음 도구가 이동된 셸 파일을 실행하는 것 $out/bin/.myshellscript.sh-wrapped
입니다 wrapProgram
.
이제 테스트해 볼 시간입니다.
$ ./result/bin/myshellscript.sh
___________________
< My first wrapper! >
-------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
좋아요! 래퍼 수정을 위한 다양한 옵션을 찾을 수 있습니다.여기.
간단한 빌더 덕분에 파생이 더 짧아졌습니다.
때로는 설정 단계, 래퍼 등을 작성하는 것이 약간 성가실 수 있습니다 . 따라서 간단한 빌더는 더 간단한 기능으로 stdenv.mkDerivation
래핑되도록 만들어졌습니다 . stdenv.mkDerivation
그들은 문서화되어 있습니다설명서에. 우리는 이들 모두를 다루지는 않을 것입니다(그 중 일부는 새 파일, 스크립트, 병합 포크를 생성하는 데 사용됩니다...). 하지만 이를 사용하여 코드 실행을 단순화할 것입니다 cowsay
.
이런 식으로 우리는 간단히 이 파생을 사용할 수 있습니다:
{ lib, stdenv, cowsay, writeShellApplication }:
writeShellApplication {
name = "mycowsay";
runtimeInputs = [ cowsay ];
text = ''
cowsay "My first wrapper!"
'';
}
$out/bin/mycowsay
적절한 $PATH
base 를 사용하여 bash 스크립트를 생성합니다 runtimeInputs
. 이전과 같이 외부 파일에 스크립트를 작성하려는 경우 다음을 수행할 수 있습니다.
text = builtins.readFile ./myshellscript.sh;
Python 스크립트를 패키징하는 방법
TODO, 관련 주제 보기:
- 단일 스크립트의 경우 다음을 사용할 수 있습니다.https://stackoverflow.com/questions/43837691/how-to-package-a-single-python-script-with-nix
buildPythonPackage
전체 Python 응용 프로그램 및/또는 모듈의 경우 물론 사용하고 (mkDerivation
추가 비용이 거의 없음) 적절한 파일을 작성하고 싶을 것입니다.setup.py
내가 추가한 항목을 참조하세요.위키피디아에서.- Python을 호출할 수 있는 bash 스크립트도 패키징하는 경우 다음과 같이 래핑하는 것이 좋습니다.
postFixup = ''
wrapProgram "$out/bin/mssql-cli" \
--prefix PYTHONPATH : "$PYTHONPATH"
'';
내부, 바이너리 buildPythonPackage
(스크립트는 아님)~해야 한다(테스트) 자동 포장. (별로 마음에 들지는 않지만 wrapPythonPrograms
바이너리에서만 작동할 것이라고 생각해서 만들었습니다.이 문제)
GTK 애플리케이션을 패키징하는 방법
해
QT 애플리케이션을 패키징하는 방법
해