article1_0 - webispy/aln GitHub Wiki

Ubuntu Linux에 deb νŒ¨ν‚€μ§€λ‘œ λ°°ν¬ν•˜κΈ° (상)

μ˜€ν”ˆ μ†ŒμŠ€ μ„Έκ³„μ—μ„œ UbuntuλŠ” κ°€μž₯ 인기 μžˆλŠ” Linux 배포판 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€. CI/CD에 많이 μ‚¬μš©λ˜λŠ” Github Action runnerμ—μ„œλ„ κΈ°λ³Έ Linux μ΄λ―Έμ§€λ‘œ Ubuntuλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μš°λ¦¬κ°€ λ§Œλ“  라이브러리λ₯Ό Ubuntu μ‚¬μš©μžλ“€μ΄ μ‰½κ²Œ μ„€μΉ˜ν•˜κ³  μ‚¬μš©ν•  수 있게 ν•˜λŠ” 것은 μ€‘μš”ν•˜λ©°, 이λ₯Ό μœ„ν•œ κ°€μž₯ 효과적인 방법 쀑 ν•˜λ‚˜κ°€ λ°”λ‘œ deb νŒ¨ν‚€μ§€λ₯Ό ν†΅ν•œ λ°°ν¬μž…λ‹ˆλ‹€.

deb νŒ¨ν‚€μ§€λŠ” Debian 계열 Linux 배포판(Ubuntu 포함)μ—μ„œ μ‚¬μš©λ˜λŠ” μ†Œν”„νŠΈμ›¨μ–΄ νŒ¨ν‚€μ§€ ν˜•μ‹μž…λ‹ˆλ‹€. 이 ν˜•μ‹μ„ μ‚¬μš©ν•˜λ©΄ μ‚¬μš©μžλ“€μ΄ apt λ˜λŠ” dpkg λͺ…λ Ήμ–΄λ₯Ό 톡해 μ‰½κ²Œ μ†Œν”„νŠΈμ›¨μ–΄λ₯Ό μ„€μΉ˜, μ—…κ·Έλ ˆμ΄λ“œ, μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ˜μ‘΄μ„± 관리, μ„€μΉ˜ ν›„ 슀크립트 μ‹€ν–‰ λ“± λ‹€μ–‘ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜μ—¬ μ†Œν”„νŠΈμ›¨μ–΄ 배포λ₯Ό λ”μš± 효율적으둜 λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

이번 κΈ€μ—μ„œλŠ” 이전에 μ†Œκ°œν•œ ALN(Amazing Lucky Numbers) 라이브러리λ₯Ό Ubuntu Linux용 deb νŒ¨ν‚€μ§€λ‘œ λ§Œλ“œλŠ” 과정을 λ‹€λ£¨κ² μŠ΅λ‹ˆλ‹€. νŒ¨ν‚€μ§€ 생성에 ν•„μš”ν•œ 파일 ꡬ쑰, μ œμ–΄ 파일 μž‘μ„±, λΉŒλ“œ κ³Όμ •, 그리고 μ΅œμ’…μ μœΌλ‘œ νŒ¨ν‚€μ§€λ₯Ό μƒμ„±ν•˜κ³  λ°°ν¬ν•˜λŠ” 방법에 λŒ€ν•΄ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€.

νŒ¨ν‚€μ§€ 파일

Ubuntuμ—μ„œ νŒ¨ν‚€μ§€ μ„€μΉ˜ μ‹œ μ‚¬μš©λ˜λŠ” νŒŒμΌμ€ .deb ν™•μž₯자λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. μ•„λž˜μ—μ„œ 이 파일의 ν˜•μ‹κ³Ό ꡬ성에 λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

deb 파일 ꡬ성

.deb νŒŒμΌμ€ 기본적으둜 ar μ•„μΉ΄μ΄λΈŒ 포맷을 μ‚¬μš©ν•˜λŠ” μ••μΆ• νŒŒμΌμž…λ‹ˆλ‹€. 압좕을 ν•΄μ œν•˜λ©΄ λ‹€μŒκ³Ό 같은 νŒŒμΌλ“€μ΄ μƒμ„±λ©λ‹ˆλ‹€:

  1. debian-binary
    • νŒ¨ν‚€μ§€ ν˜•μ‹μ˜ 버전을 λ‚˜νƒ€λ‚΄λŠ” ν…μŠ€νŠΈ νŒŒμΌμž…λ‹ˆλ‹€. ν˜„μž¬ λŒ€λΆ€λΆ„ 경우 버전은 2.0μž…λ‹ˆλ‹€.
  2. control.tar.gz (λ˜λŠ” control.tar.zst)
    • νŒ¨ν‚€μ§€μ˜ 메타데이터λ₯Ό ν¬ν•¨ν•˜λŠ” μ••μΆ• 파일
  3. data.tar.gz (λ˜λŠ” data.tar.zst)
    • μ‹€μ œ μ„€μΉ˜λ  νŒŒμΌλ“€μ„ ν¬ν•¨ν•˜λŠ” μ••μΆ• νŒŒμΌμž…λ‹ˆλ‹€. 이 νŒŒμΌμ—λŠ” μ‹€μ œλ‘œ μ‹œμŠ€ν…œμ— μ„€μΉ˜λ  νŒŒμΌλ“€μ΄ λ“€μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 파일 κ΅¬μ‘°λŠ” μ‹€μ œ μ„€μΉ˜λ  디렉토리 ꡬ쑰λ₯Ό κ·ΈλŒ€λ‘œ λ°˜μ˜ν•©λ‹ˆλ‹€.

control.tar.gz μ••μΆ• νŒŒμΌμ— ν¬ν•¨λœ λ©”νƒ€λ°μ΄ν„°μ˜ μ£Όμš” νŒŒμΌλ“€μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

  • control: νŒ¨ν‚€μ§€ 이름, 버전, μ˜μ‘΄μ„± λ“±μ˜ 정보
  • md5sums: 데이터 νŒŒμΌλ“€μ˜ MD5 체크섬
  • preinst, postinst, prerm, postrm: μ„€μΉ˜/제거 전후에 μ‹€ν–‰λ˜λŠ” μŠ€ν¬λ¦½νŠΈλ“€

deb 파일 λ‚΄μš© 확인 방법

λ¨Όμ € apt 도ꡬλ₯Ό μ΄μš©ν•΄ μž„μ˜μ˜ νŒ¨ν‚€μ§€λ₯Ό ν•˜λ‚˜ λ‹€μš΄λ‘œλ“œ λ°›μŠ΅λ‹ˆλ‹€. apt download λͺ…λ ΉμœΌλ‘œ deb νŒ¨ν‚€μ§€ νŒŒμΌμ„ 직접 λ‹€μš΄λ‘œλ“œ 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

$ apt download libglib2.0-0
$ ls
libglib2.0-0_2.72.4-0ubuntu2.3_arm64.deb

이제 ar λͺ…령을 톡해 압좕을 ν•΄μ œν•©λ‹ˆλ‹€. μœ„μ—μ„œ μ„€λͺ…ν–ˆλ˜ κ²ƒμ²˜λŸΌ debian-binary, control.tar.zst 그리고 data.tar.zst 파일이 μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

$ ar x libglib2.0-0_2.72.4-0ubuntu2.3_arm64.deb
$ ls
control.tar.zst  data.tar.zst  debian-binary  libglib2.0-0_2.72.4-0ubuntu2.3_arm64.deb

메타데이터λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•΄ νŒ¨ν‚€μ§€μ— λŒ€ν•œ 정보가 λ“€μ–΄μžˆλŠ” control.tar.zst 파일의 압좕을 ν•΄μ œν•©λ‹ˆλ‹€.

$ tar xvf control.tar.zst
./
./control
./md5sums
./postinst
./postrm
./shlibs
./symbols
./triggers

μ••μΆ• ν•΄μ œ ν›„ μƒμ„±λœ νŒŒμΌλ“€ 쀑 control 파일의 λ‚΄μš©μ„ 확인해보면 이 νŒ¨ν‚€μ§€μ— λŒ€ν•œ 이름, μ„€λͺ…, 버전, λ©”μΈν…Œμ΄λ„ˆ 및 μ˜μ‘΄μ„± 정보λ₯Ό λͺ¨λ‘ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

$ cat control
Package: libglib2.0-0
Source: glib2.0
Version: 2.72.4-0ubuntu2.3
Architecture: arm64
Maintainer: Ubuntu Developers <[email protected]>
Installed-Size: 4137
Depends: libc6 (>= 2.34), libffi8 (>= 3.4), libmount1 (>= 2.35.2-7~), libpcre3, libselinux1 (>= 3.1~), zlib1g (>= 1:1.2.2)
Recommends: libglib2.0-data, shared-mime-info, xdg-user-dirs
Breaks: gimp (<< 2.10.14-3~), glib-networking-tests (<< 2.70.0~), gnome-keyring (<< 40.0-3~), gnome-shell (<< 42.9-0ubuntu2.1~), libgirepository-1.0-1 (<< 1.62.0-4~), libgladeui-2-6 (<< 3.22.2), libsoup2.4-tests (<< 2.72.0-3~)
Section: libs
Priority: optional
Multi-Arch: same
Homepage: https://wiki.gnome.org/Projects/GLib
Description: GLib library of C routines
 GLib is a library containing many useful C routines for things such
 as trees, hashes, lists, and strings.  It is a useful general-purpose
 C library used by projects such as GTK+, GIMP, and GNOME.
 .
 This package contains the shared libraries.
Original-Maintainer: Debian GNOME Maintainers <[email protected]>

이제 μ‹€μ œ μ„€μΉ˜λ  νŒŒμΌλ“€μ„ λ‹΄κ³  μžˆλŠ” data.tar.zst νŒŒμΌλ„ 압좕을 ν•΄μ œν•©λ‹ˆλ‹€.

$ tar xvf data.tar.zst
...
./usr/lib/aarch64-linux-gnu/gio/modules/
...
./usr/lib/aarch64-linux-gnu/libgio-2.0.so.0.7200.4
./usr/lib/aarch64-linux-gnu/libglib-2.0.so.0.7200.4
./usr/lib/aarch64-linux-gnu/libgmodule-2.0.so.0.7200.4
./usr/lib/aarch64-linux-gnu/libgobject-2.0.so.0.7200.4
./usr/lib/aarch64-linux-gnu/libgthread-2.0.so.0.7200.4
...
./usr/share/doc/libglib2.0-0/copyright
...
./usr/lib/aarch64-linux-gnu/libgio-2.0.so.0
./usr/lib/aarch64-linux-gnu/libglib-2.0.so.0
./usr/lib/aarch64-linux-gnu/libgmodule-2.0.so.0
./usr/lib/aarch64-linux-gnu/libgobject-2.0.so.0
./usr/lib/aarch64-linux-gnu/libgthread-2.0.so.0

μ΄λ ‡κ²Œ ν•΄μ„œ νŒ¨ν‚€μ§€κ°€ ν¬ν•¨ν•˜κ³  μžˆλŠ” λͺ¨λ“  νŒŒμΌλ“€μ„ 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

νŒ¨ν‚€μ§€ 이름 κ·œμΉ™

νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€ λ•Œ 이름과 버전을 μ •ν•΄μ•Ό ν•˜λŠ”λ°, deb νŒ¨ν‚€μ§€μ—μ„œ 일반적으둜 μ‚¬μš©ν•˜λŠ” κ·œμΉ™μ΄ μžˆμŠ΅λ‹ˆλ‹€.

  1. νŒ¨ν‚€μ§€ 이름
    • μ†Œλ¬Έμž(λŒ€λ¬ΈμžλŠ” μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.), 숫자, 기호(+, -, ., ~)
    • 라이브러리의 경우 일반적으둜 μ•žμ— libλ₯Ό λΆ™μž…λ‹ˆλ‹€.
    • 라이브러리의 major 버전 번호λ₯Ό 뒀에 λΆ™μž…λ‹ˆλ‹€. 예: libxxx0, libxxx1
    • 라이브러리의 헀더 νŒŒμΌλ“±μ„ ν¬ν•¨ν•˜κ³  μžˆλŠ” 개발(λΉŒλ“œ)용 νŒ¨ν‚€μ§€μ˜ 경우 일반적으둜 뒀에 -devλ₯Ό λΆ™μž…λ‹ˆλ‹€.
  2. 버전
    • 일반적으둜 major.minor.patch ν˜•μ‹μ„ μ‚¬μš©ν•©λ‹ˆλ‹€. 예: 1.2.0
    • 같은 버전인데 νŒ¨ν‚€μ§€ λ©”μΈν…Œμ΄λ„ˆμ— μ˜ν•΄ νŒ¨ν‚€μ§€κ°€ μˆ˜μ •λ  경우 리비전을 λΆ™μž…λ‹ˆλ‹€. 예: 1.2.0-1
      • 보톡 λ°°ν¬νŒμ— 맞게 νŒ¨ν‚€μ§•ν•˜λŠ” κ³Όμ •μ—μ„œ μˆ˜μ •μ΄ ν•„μš”ν•œ 경우 리비전이 μ˜¬λΌκ°‘λ‹ˆλ‹€.
    • Ubuntu νŒ¨ν‚€μ§•μ„ μœ„ν•΄ κΈ°μ‘΄ Debian νŒ¨ν‚€μ§€λ₯Ό 기반으둜 μˆ˜μ •ν–ˆμ„ 경우 ubuntu 이름과 ν•¨κ»˜ 리비전 λ²ˆν˜Έκ°€ μΆ”κ°€λ©λ‹ˆλ‹€.
      • 1.2.0-2ubuntu1: Debian에 맞게 νŒ¨ν‚€μ§•λœ 리비전 2λ₯Ό 기반으둜 Ubuntu에 맞게 μΆ”κ°€λ‘œ μˆ˜μ •ν•œ νŒ¨ν‚€μ§€ 리비전 1을 μ˜λ―Έν•©λ‹ˆλ‹€.

μœ„μ—μ„œ apt downloadλ₯Ό ν†΅ν•œ λ‹€μš΄λ‘œλ“œ 받은 deb νŒ¨ν‚€μ§€ 이름을 μœ„μ˜ κ·œμΉ™μœΌλ‘œ 뢄석해 보면 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • 파일λͺ…: libglib2.0-0_2.72.4-0ubuntu2.3_arm64.deb
  • νŒ¨ν‚€μ§€ 이름: libglib2.0-0 (-0은 ν•˜μœ„ 버전 λ˜λŠ” νŒ¨ν‚€μ§€ 버전을 λ‚˜νƒ€λƒ„)
  • 버전
    • glib 라이브러리 버전: 2.72.4
    • 리비전: 0ubuntu2.3 (0: Debian 리비전, 2.3: Ubuntu 리비전)
  • μ’…λ₯˜: 라이브러리 (lib prefix)
  • μ•„ν‚€ν…μ²˜: arm64

라이브러리 νŒ¨ν‚€μ§€μ— λŒ€ν•΄ libxxx와 libxxx-dev둜 λΆ„λ¦¬λ˜μ–΄ μžˆλŠ”λ°, κ·Έ μ΄μœ λŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‹€ν–‰ν•˜λŠ”λ° ν•„μš”ν•œ μ˜μ‘΄μ„± 라이브러리
    • 라이브러리 νŒ¨ν‚€μ§€μ—μ„œ μ œκ³΅ν•˜λŠ” shared library(.so.N) 파일만 있으면 λ©λ‹ˆλ‹€.
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 개발 및 λΉŒλ“œλ₯Ό μœ„ν•΄ ν•„μš”ν•œ μ˜μ‘΄μ„± 라이브러리
    • 라이브러리 νŒ¨ν‚€μ§€μ—μ„œ 헀더 파일, pkg-config 파일 그리고 shared libraryλ₯Ό 같이 μ œκ³΅ν•΄μ€˜μ•Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ •μƒμ μœΌλ‘œ λΉŒλ“œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

νŒ¨ν‚€μ§€ μ •μ˜ν•˜κΈ°

deb νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ ν•„μš”ν•œ ν•­λͺ©λ“€μ„ 확인해보고 예제 라이브러리인 ALN κΈ°μ€€μœΌλ‘œ μ‹€μ œλ‘œ μž‘μ„±ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

λ¨Όμ € νŒ¨ν‚€μ§•μ„ μœ„ν•œ νŒŒμΌλ“€μ€ debian 디렉토리 밑에 μœ„μΉ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

.
β”œβ”€β”€ CMakeLists.txt
β”œβ”€β”€ debian
β”‚   β”œβ”€β”€ aln.install
β”‚   β”œβ”€β”€ changelog
β”‚   β”œβ”€β”€ compat
β”‚   β”œβ”€β”€ control
β”‚   β”œβ”€β”€ copyright
β”‚   β”œβ”€β”€ libaln-dev.install
β”‚   β”œβ”€β”€ libaln0.install
β”‚   β”œβ”€β”€ rules
β”‚   └── source
β”‚       └── format
β”œβ”€β”€ include
β”‚   └── aln.h
└── src
    β”œβ”€β”€ CMakeLists.txt
    └── aln.c

νŒŒμΌλ“€μ„ ν•˜λ‚˜μ”© 확인해 보면 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • changelog - νŒ¨ν‚€μ§€λ₯Ό λ°œν–‰ν•  λ•Œλ§ˆλ‹€ 버전과 변경사항듀을 이 νŒŒμΌμ— 적어야 ν•©λ‹ˆλ‹€.
  • compat - νŒ¨ν‚€μ§€λ₯Ό λΉŒλ“œν•  λ•Œ debhelper 도ꡬλ₯Ό μ‚¬μš©ν•˜λŠ”λ°, 이 λ„κ΅¬μ˜ ν˜Έν™˜μ„± μˆ˜μ€€μ„ μ§€μ •ν•©λ‹ˆλ‹€. 22.04 (Jammy) κΈ°μ€€μœΌλ‘œ 13이 μ‚¬μš©λ©λ‹ˆλ‹€.
  • control - νŒ¨ν‚€μ§€μ— λŒ€ν•œ 이름, μ„€λͺ…, μ˜μ‘΄μ„±, 생성할 νŒ¨ν‚€μ§€ λͺ©λ‘λ“±μ„ μ •μ˜ν•©λ‹ˆλ‹€.
  • copyright - λΌμ΄μ„ΌμŠ€ 정보
  • rules - νŒ¨ν‚€μ§€ λΉŒλ“œ κ³Όμ •μ—μ„œ μˆ˜ν–‰ν•΄μ•Ό ν•  슀크립트λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.
  • source/format - μ†ŒμŠ€ νŒ¨ν‚€μ§€ 포맷을 μ •μ˜ν•©λ‹ˆλ‹€. 전톡적인 포맷은 1.0이 μ‚¬μš©λ˜κ³  μ΅œμ‹  포맷은 3.0 (quilt) λ˜λŠ” 3.0 (native)κ°€ μ‚¬μš©λ©λ‹ˆλ‹€.
  • *.install - 각 νŒ¨ν‚€μ§€λ³„λ‘œ μ„€μΉ˜ν•  파일 λͺ©λ‘μ„ μ •μ˜ν•©λ‹ˆλ‹€.

changelog

changelog νŒŒμΌμ€ νŒ¨ν‚€μ§€μ˜ λ³€κ²½ 사항을 κΈ°λ‘ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. 이 νŒŒμΌμ€ νŒ¨ν‚€μ§€μ˜ 각 λ¦΄λ¦¬μ¦ˆλ§ˆλ‹€ μ–΄λ–€ 변경이 μžˆμ—ˆλŠ”μ§€, λˆ„κ°€ 변경을 ν–ˆλŠ”μ§€, μ–Έμ œ 변경이 μ΄λ£¨μ–΄μ‘ŒλŠ”μ§€ λ“±μ˜ 정보λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€. changelog νŒŒμΌμ€ νŒ¨ν‚€μ§€λ₯Ό μœ μ§€λ³΄μˆ˜ν•˜κ³  κ΄€λ¦¬ν•˜λŠ” 데 μ€‘μš”ν•œ 역할을 ν•˜λ©°, ν˜•μ‹μ€ μ—„κ²©ν•˜κ²Œ μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

package (version) distribution; urgency=urgency

  * change details

 -- maintainer-name <maintainer-email>  date

ALN 예제둜 μž‘μ„±ν•˜λ©΄ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

aln (0.1.0~jammy) jammy; urgency=medium

  * Initial release.

 -- Inho Oh <[email protected]>  Tue, 02 Jul 2024 00:00:00 +0900

μƒˆλ‘œμš΄ 버전을 λ°°ν¬ν•˜κ±°λ‚˜ 리비전을 올릴 경우 기쑴파일의 μœ—λΆ€λΆ„μ— λ‚΄μš©μ„ μΆ”κ°€ν•˜λ©΄ λ©λ‹ˆλ‹€. vi와 같은 νŽΈμ§‘κΈ°λ‘œ 직접 μˆ˜μ •μ„ ν•˜κ±°λ‚˜ dch와 같은 changelog μž‘μ„± 도ꡬλ₯Ό μ΄μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

aln (0.1.0-1~jammy) jammy; urgency=medium

  * Fix typo in debian/control

 -- Inho Oh <[email protected]>  Tue, 02 Jul 2024 09:00:00 +0900

aln (0.1.0~jammy) jammy; urgency=medium

  * Initial release.

 -- Inho Oh <[email protected]>  Tue, 02 Jul 2024 00:00:00 +0900

버전λͺ…에 ~jammy와 같이 배포판 이름을 μΆ”κ°€ν•˜λŠ” μ΄μœ λŠ” PPA(Personal Package Archive)에 각 배포판(focal, jammy, noble λ“±)용 νŒ¨ν‚€μ§€λ₯Ό μΆ”κ°€λ‘œ μ—…λ‘œλ“œν•  λ•Œ μ†ŒμŠ€ μ••μΆ•νŒŒμΌμ˜ 이름(예: aln_0.1.0.tar.gz)이 λ™μΌν•˜μ—¬ λ°œμƒν•  수 μžˆλŠ” μ—…λ‘œλ“œ μ‹€νŒ¨(Reject)λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œμž…λ‹ˆλ‹€. PPAλ₯Ό 톡해 배포할 κ³„νšμ΄ μ—†λ‹€λ©΄ μΆ”κ°€ν•˜μ§€ μ•Šμ•„λ„ λ©λ‹ˆλ‹€.

control

control νŒŒμΌμ€ νŒ¨ν‚€μ§€μ˜ 메타데이터λ₯Ό μ •μ˜ν•˜λŠ” 파일둜, νŒ¨ν‚€μ§€μ˜ 속성, μ˜μ‘΄μ„±, λ©”μΈν…Œμ΄λ„ˆ 정보 등을 ν¬ν•¨ν•©λ‹ˆλ‹€. control νŒŒμΌμ€ Source μ„Ήμ…˜κ³Ό Package μ„Ήμ…˜λ“€λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.

Source:

Source: package-name
Section: section
Priority: required, important, standard or optional
Maintainer: full name <email>
Build-Depends: dependency1, dependency2
Standards-Version: standards-version
Homepage: homepage-url
  • Source: νŒ¨ν‚€μ§€ 이름
  • Section: νŒ¨ν‚€μ§€κ°€ μ†ν•˜λŠ” μ„Ήμ…˜μœΌλ‘œ net, libs 등을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 전체 λͺ©λ‘μ€ https://packages.ubuntu.com/jammy/μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • Priority: νŒ¨ν‚€μ§€μ˜ μ€‘μš”λ„λ₯Ό μ˜λ―Έν•˜λŠ”λ°, Ubuntu의 system νŒ¨ν‚€μ§€κ°€ μ•„λ‹Œ 이상 λŒ€λΆ€λΆ„ optional을 μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.
  • Maintainer: νŒ¨ν‚€μ§€λ₯Ό κ΄€λ¦¬ν•˜λŠ” μ‚¬λžŒμ˜ 이름과 이메일
  • Build-Depends: 이 νŒ¨ν‚€μ§€λ₯Ό λΉŒλ“œν•˜λŠ”λ° ν•„μš”ν•œ μ˜μ‘΄μ„± νŒ¨ν‚€μ§€λ“€μ„ λ‚˜μ—΄ν•©λ‹ˆλ‹€.
  • Standards-Version: νŒ¨ν‚€μ§€κ°€ μ€€μˆ˜ν•˜λŠ” Debian μ •μ±… λ²„μ „μœΌλ‘œ https://www.debian.org/doc/debian-policy/upgrading-checklist.htmlμ—μ„œ 버전별 변경점을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • Homepage: νŒ¨ν‚€μ§€μ˜ ν™ˆνŽ˜μ΄μ§€ URL

Package:

Package: package-name
Architecture: any or all
Section: section
Depends: dependency1, dependency2
Description: short description
 long description
 .
 blah blah
  • Package: νŒ¨ν‚€μ§€ 이름
  • Architecture: νŒ¨ν‚€μ§€κ°€ μ§€μ›ν•˜λŠ” μ•„ν‚€ν…μ²˜λ‘œ νŠΉμ • μ•„ν‚€ν…μ²˜μ—μ„œλ§Œ 싀행될 경우 any, μ•„ν‚€ν…μ²˜μ™€ 상관없이 μ‚¬μš© κ°€λŠ₯ν•œ μŠ€ν¬λ¦½νŠΈλ‚˜ λ¦¬μ†ŒμŠ€ 같은 νŒ¨ν‚€μ§€μΌ 경우 all을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • Section: νŒ¨ν‚€μ§€κ°€ μ†ν•˜λŠ” μ„Ήμ…˜. Sourceμ—μ„œ μ •ν•œ Sectionκ³Ό λ‹€λ₯΄κ²Œ μ„€μ •ν•  수 있고, Packageλ“€ μ‚¬μ΄μ—μ„œλ„ λ‹€λ₯΄κ²Œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • Depends: 이 νŒ¨ν‚€μ§€κ°€ μ‹€ν–‰λ˜λŠ”λ° ν•„μš”ν•œ μ˜μ‘΄μ„± νŒ¨ν‚€μ§€λ“€μ„ λ‚˜μ—΄ν•©λ‹ˆλ‹€.
  • Description: νŒ¨ν‚€μ§€μ— λŒ€ν•œ μ„€λͺ…μœΌλ‘œ 첫 쀄은 μš”μ•½λœ 짧은 μ„€λͺ…이고, κ·Έλ‹€μŒ 쀄뢀터 λ©€ν‹°λΌμΈμœΌλ‘œ κΈ΄ μ„€λͺ…을 적을 수 μžˆμŠ΅λ‹ˆλ‹€. κΈ΄ μ„€λͺ…을 μž‘μ„±ν•  λ•Œ μ•žμ— ν•œ μΉΈμ”© 곡백이 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ§Œμ•½ 곡백 라인이 ν•„μš”ν•  κ²½μš°μ—λŠ” ν•œ μΉΈ 곡백 뒀에 .을 μž…λ ₯ν•˜λ©΄ λ©λ‹ˆλ‹€.

μ•„λž˜λŠ” ALNμ—μ„œ μ‹€μ œλ‘œ μ‚¬μš©ν•˜λŠ” control 파일 μ˜ˆμ œμž…λ‹ˆλ‹€. aln μ†ŒμŠ€μ™€ libaln0, libaln-dev, libaln0-dbg, aln, aln-dbg λ°”μ΄λ„ˆλ¦¬ νŒ¨ν‚€μ§€λ₯Ό μ •μ˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

Source: aln
Section: libs
Priority: optional
Maintainer: Inho Oh <[email protected]>
Build-Depends: debhelper (>= 13), cmake, libglib2.0-dev, doxygen
Standards-Version: 4.1.4
Homepage: https://github.com/webispy/aln

Package: libaln0
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libglib2.0-0
Description: Amazing Lucky Numbers Library
 A library for generating amazing lucky numbers.

Package: libaln-dev
Architecture: any
Section: libdevel
Depends: ${shlibs:Depends}, ${misc:Depends}, libaln0 (= ${binary:Version}), libglib2.0-dev
Description: Amazing Lucky Numbers Library (development files)
 A library for generating amazing lucky numbers.

Package: libaln0-dbg
Section: debug
Priority: optional
Architecture: any
Depends: libaln0 (= ${binary:Version}), aln (= ${binary:Version}), ${misc:Depends}
Description: Debugging symbols for libaln0
 This package contains the debugging symbols for the aln library.

Package: aln
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libaln0, libglib2.0-0
Description: Amazing Lucky Numbers Tool
 Command line tool for generating and using amazing lucky numbers.
 This package contains the aln command line tool that utilizes the aln library.

Package: aln-dbg
Section: debug
Priority: optional
Architecture: any
Depends: aln (= ${binary:Version}), ${misc:Depends}
Description: Debugging symbols for aln
 This package contains the debugging symbols for the aln tool.

rules

rules νŒŒμΌμ€ νŒ¨ν‚€μ§€λ₯Ό λΉŒλ“œν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜λŠ” Makefile ν˜•μ‹μ˜ 슀크립트 νŒŒμΌμž…λ‹ˆλ‹€. 이 νŒŒμΌμ€ νŒ¨ν‚€μ§€μ˜ λΉŒλ“œ κ³Όμ •μ—μ„œ μ–΄λ–€ μž‘μ—…μ„ μˆ˜ν–‰ν•΄μ•Ό ν•˜λŠ”μ§€ μ •μ˜ν•˜λ©°, νŒ¨ν‚€μ§€ λΉŒλ“œμ˜ 핡심 뢀뢄을 λ‹΄λ‹Ήν•©λ‹ˆλ‹€.

각 νŒ¨ν‚€μ§€λ§ˆλ‹€ κ³ μœ ν•œ λΉŒλ“œ μŠ€ν¬λ¦½νŠΈκ°€ ν•„μš”ν•œλ°, 이λ₯Ό κ°œλ³„μ μœΌλ‘œ rules νŒŒμΌμ— μž‘μ„±ν•˜λ©΄ λ³΅μž‘μ„±μ΄ μ¦κ°€ν•˜κ³  μœ μ§€λ³΄μˆ˜μ™€ 검증이 μ–΄λ €μ›Œμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ debhelperλΌλŠ” 도ꡬ가 μ œκ³΅λ©λ‹ˆλ‹€. debhelperλŠ” ν‘œμ€€ν™”λœ ν…œν”Œλ¦Ώμ„ μ‚¬μš©ν•˜μ—¬ λΉŒλ“œ 및 μ„€μΉ˜ 과정을 κ°„μ†Œν™”ν•˜κ³ , 일관성 μžˆλŠ” νŒ¨ν‚€μ§•μ„ κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

λŒ€λΆ€λΆ„μ˜ νŒ¨ν‚€μ§€λŠ” μ•„λž˜μ™€ 같이 λͺ‡ 쀄 μ•ˆλ˜λŠ” μ½”λ“œλ‘œ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. dhλŠ” debhelperλ₯Ό μ˜λ―Έν•˜κ³ , %λŠ” κΈ°λ³Έ νƒ€κ²Ÿμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

rules:

#!/usr/bin/make -f

%:
	dh $@

μ„ΈλΆ€μ μœΌλ‘œλŠ” configure, build, install, clean λ“± λ³΅μž‘ν•œ μ—¬λŸ¬ 단계가 μ‚¬μš©λ˜μ§€λ§Œ 각 λ‹¨κ³„λ§ˆλ‹€ dhκ°€ μžλ™μœΌλ‘œ 단계에 맞게 μ²˜λ¦¬ν•©λ‹ˆλ‹€. νŠΉμ • λ‹¨κ³„μ—μ„œ κΈ°λ³Έκ³Ό λ‹€λ₯΄κ²Œ μ²˜λ¦¬ν•˜κ³ μž ν•  경우 override_ prefixλ₯Ό μ΄μš©ν•΄μ„œ 직접 μ›ν•˜λŠ” λͺ…령을 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•„λž˜λŠ” ALNμ—μ„œ μ‚¬μš©ν•˜λŠ” rules 파일 λ‚΄μš©μž…λ‹ˆλ‹€.

#!/usr/bin/make -f

%:
	dh $@

override_dh_auto_configure:
	dh_auto_configure -- \
		-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo

override_dh_install:
	doxygen
	find doc/man/man3 -type f ! -name 'aln*' -exec rm -f {} \;
	install -d $(CURDIR)/debian/tmp/usr/share/man/man3
	install -m 644 doc/man/man3/* $(CURDIR)/debian/tmp/usr/share/man/man3/
	dh_install

override_dh_strip:
	dh_strip -plibaln0 --dbg-package=libaln0-dbg
	dh_strip -paln --dbg-package=aln-dbg

override_dh_auto_configure:

  • configure λ‹¨κ³„μ—μ„œ dhκ°€ CMakeλ₯Ό μžλ™μœΌλ‘œ μΈμ‹ν•΄μ„œ μ²˜λ¦¬ν•˜λŠ”λ°, 여기에 μ›ν•˜λŠ” μ˜΅μ…˜μ„ μΆ”κ°€λ‘œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • CMake 뿐만 μ•„λ‹ˆλΌ Autotools, meson λ“± 유λͺ…ν•œ λŒ€λΆ€λΆ„μ˜ λΉŒλ“œ μ‹œμŠ€ν…œμ„ μ§€μ›ν•©λ‹ˆλ‹€.

override_dh_install:

  • install λ‹¨κ³„μ—μ„œ μ›ν•˜λŠ” λͺ…령을 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ œλŠ” μ‹€μ œλ‘œ μ„€μΉ˜ν•˜κΈ° 전에 doxygen λͺ…λ ΉμœΌλ‘œ manpageλ₯Ό λ§Œλ“€μ–΄μ„œ λŒ€μƒ 디렉토리에 ν•„μš”ν•œ νŒŒμΌμ„ μ„€μΉ˜ν•œ ν›„ dh_install을 μˆ˜ν–‰ν•˜μ—¬ λ‚˜λ¨Έμ§€ install 단계λ₯Ό μˆ˜ν–‰μ‹œν‚΅λ‹ˆλ‹€.

override_dh_strip:

  • λΉŒλ“œκ°€ λ‹€ λλ‚œ ν›„ μƒμ„±λœ νŒ¨ν‚€μ§€μ—λŠ” 디버깅 정보가 λͺ¨λ‘ 제거(strip)된 μƒνƒœλ‘œ λ³΅μ‚¬λ©λ‹ˆλ‹€.
  • 디버깅을 μœ„ν•΄ λ³„λ„μ˜ 디버깅 νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€κ³  싢을 경우 μœ„μ˜ 예제처럼 dh_strip λͺ…령에 μ˜΅μ…˜μœΌλ‘œ 디버깅 νŒ¨ν‚€μ§€λ₯Ό μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

*.install

*.install νŒŒμΌμ€ νŒ¨ν‚€μ§€μ— 포함될 νŒŒμΌλ“€κ³Ό μ„€μΉ˜ μœ„μΉ˜λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. control νŒŒμΌμ—μ„œ μ •μ˜λœ 각 νŒ¨ν‚€μ§€μ— λŒ€ν•΄ install νŒŒμΌλ“€μ„ μƒμ„±ν•˜μ–΄ ν•΄λ‹Ή νŒ¨ν‚€μ§€μ— 포함될 νŒŒμΌλ“€μ„ μ •μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€. 단, debug νŒ¨ν‚€μ§€λŠ” μžλ™μœΌλ‘œ μ²˜λ¦¬λ˜λ―€λ‘œ λ³„λ„μ˜ install 파일이 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λΉŒλ“œ κ³Όμ • 쀑 μƒμ„±λœ λͺ¨λ“  νŒŒμΌλ“€(예: make install λ“±μ˜ λͺ…λ ΉμœΌλ‘œ μ„€μΉ˜λœ νŒŒμΌλ“€)은 μž„μ‹œλ‘œ debian/tmp/ 디렉토리에 μ„€μΉ˜λ©λ‹ˆλ‹€. 이 νŒŒμΌλ“€μ„ 각 νŒ¨ν‚€μ§€μ— 적절히 λΆ„λ°°ν•˜λ €λ©΄ {package-name}.install νŒŒμΌμ„ λ§Œλ“€κ³ , κ·Έ μ•ˆμ— ν•΄λ‹Ή νŒ¨ν‚€μ§€μ— 포함할 νŒŒμΌλ“€μ„ λ‚˜μ—΄ν•˜λ©΄ λ©λ‹ˆλ‹€.

ALNμ—μ„œ μ„€μΉ˜ν•˜λŠ” νŒŒμΌλ“€μ„ 정리 해보면 이 과정을 더 μ‰½κ²Œ 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

배포할 파일 λͺ©λ‘:

.
└── usr
    β”œβ”€β”€ bin
    β”‚   └── aln
    β”œβ”€β”€ include
    β”‚   └── aln
    β”‚       └── aln.h
    β”œβ”€β”€ lib
    β”‚   └── x86_64-linux-gnu
    β”‚       β”œβ”€β”€ libaln.so -> libaln.so.0
    β”‚       β”œβ”€β”€ libaln.so.0 -> libaln.so.0.1.0
    β”‚       β”œβ”€β”€ libaln.so.0.1.0
    β”‚       └── pkgconfig
    β”‚           └── aln.pc
    └── share
        └── man
            β”œβ”€β”€ man1
            β”‚   └── aln.1
            └── man3
                β”œβ”€β”€ aln.h.3
                β”œβ”€β”€ aln_draw_all.3
                β”œβ”€β”€ aln_draw_number.3
                β”œβ”€β”€ aln_free.3
                β”œβ”€β”€ aln_get_number.3
                β”œβ”€β”€ aln_new.3
                └── aln_reset.3

aln νŒ¨ν‚€μ§€

포함할 파일:

usr/bin/aln
usr/share/man/man1/aln.1

install 파일: aln.install

debian/tmp/usr/bin/
debian/tmp/usr/share/man/man1/aln.1

libaln0 νŒ¨ν‚€μ§€

포함할 파일:

usr/lib/x86_64-linux-gnu/libaln.so.0 -> libaln.so.0.1.0
usr/lib/x86_64-linux-gnu/libaln.so.0.1.0

install 파일: libaln0.install

debian/tmp/usr/lib/*/*.so.*

libaln-dev νŒ¨ν‚€μ§€

포함할 파일:

usr/include/aln/aln.h
usr/lib/x86_64-linux-gnu/libaln.so
usr/lib/x86_64-linux-gnu/pkgconfig/aln.pc
usr/share/man/man3/*

install 파일: libaln-dev.install

debian/tmp/usr/lib/*/*.so
debian/tmp/usr/lib/*/pkgconfig/*
debian/tmp/usr/include/
debian/tmp/usr/share/man/man3/aln.h.3
debian/tmp/usr/share/man/man3/aln_*.3

μ—¬λŸ¬ 배포판 버전 λŒ€μ‘

UbuntuλŠ” μ—° 2회 μƒˆ 버전을 λ¦΄λ¦¬μ¦ˆν•˜λ©°, 2λ…„λ§ˆλ‹€ LTS(Long Term Support) 버전을 λ°°ν¬ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ λ‹€μ–‘ν•œ 버전을 단일 debian λ””λ ‰ν† λ¦¬λ‘œ κ΄€λ¦¬ν•˜λŠ” 것은 어렀움이 μžˆμŠ΅λ‹ˆλ‹€. 배포판 λ²„μ „λ³„λ‘œ νŒ¨ν‚€μ§•μ΄ λ‹€λ₯Ό 수 있고, changelog도 λ³„λ„λ‘œ 관리해야 ν•  ν•„μš”κ°€ 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ λ²„μ „λ³„λ‘œ λ‹€λ₯Έ 브랜치λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜, λ³„λ„μ˜ μ €μž₯μ†Œμ—μ„œ κ΄€λ¦¬ν•˜λ©΄μ„œ CI/CDλ₯Ό 톡해 μ œμ–΄ν•˜λŠ” λ“± λ‹€μ–‘ν•œ 방법듀이 등이 μžˆμ„ 수 μŠ΅λ‹ˆλ‹€.

ALN의 경우, packaging 디렉토리 μ•„λž˜μ— λ²„μ „λ³„λ‘œ debian 역할을 ν•˜λŠ” 디렉토리λ₯Ό λ§Œλ“€μ–΄ 두고, νŒ¨ν‚€μ§• μ‹œ μ›ν•˜λŠ” 버전을 debian 디렉토리에 λ³΅μ‚¬ν•˜λŠ” 방식을 μ±„νƒν–ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, ν–₯ν›„ μ„€λͺ…ν•  RPM νŒ¨ν‚€μ§• μŠ€ν¬λ¦½νŠΈλ„ κ΄€λ¦¬ν•˜κΈ° μœ„ν•΄ νŒ¨ν‚€μ§• κ΄€λ ¨ νŒŒμΌλ“€μ„ λͺ¨λ‘ packaging 디렉토리 μ•„λž˜μ— μœ„μΉ˜μ‹œμΌ°μŠ΅λ‹ˆλ‹€.

디렉토리 ꡬ성:

.
β”œβ”€β”€ include
β”œβ”€β”€ packaging
β”‚   β”œβ”€β”€ focal : control, rules, ...
β”‚   β”œβ”€β”€ jammy : control, rules, ...
β”‚   └── noble : control, rules, ...
└── src

νŒ¨ν‚€μ§• μž‘μ—…:

cp -a packaging/focal debian
...νŒ¨ν‚€μ§• λͺ…λ Ή...

νŒ¨ν‚€μ§€ 도ꡬ

Ubuntuμ—μ„œλŠ” deb νŒ¨ν‚€μ§€λ₯Ό 관리 ν•˜κ±°λ‚˜ λ§Œλ“€ 수 μžˆλŠ” μ—¬λŸ¬κ°€μ§€ 도ꡬ듀을 μ œκ³΅ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

  • dpkg - deb νŒ¨ν‚€μ§€ 관리
  • dpkg-buildpackage - deb νŒ¨ν‚€μ§€λ₯Ό μƒμ„±ν•˜λŠ” κΈ°λ³Έ λͺ…λ Ήμ–΄
  • gbp - gitκ³Ό μ—°κ³„ν•˜μ—¬ deb νŒ¨ν‚€μ§€ 생성
  • sbuild - chrootλ₯Ό 톡해 격리된 ν™˜κ²½μ—μ„œ νŒ¨ν‚€μ§€ 생성

dpkg

deb νŒ¨ν‚€μ§€λŠ” dpkg 도ꡬλ₯Ό μ΄μš©ν•΄ μ„€μΉ˜, 제거 및 νŒ¨ν‚€μ§€ λͺ©λ‘ 확인 등을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ•žλΆ€λΆ„μ—μ„œ μ‚¬μš©ν•œ apt install λͺ…λ ΉμœΌλ‘œ νŒ¨ν‚€μ§€ μ„€μΉ˜λ₯Ό μ§„ν–‰ν•  경우 경우, λ„€νŠΈμ›Œν¬λ₯Ό 톡해 ν•„μš”ν•œ νŒ¨ν‚€μ§€λ₯Ό λ¨Όμ € λ‹€μš΄λ‘œλ“œ 받은 ν›„ λ‚΄λΆ€μ μœΌλ‘œ dpkg λͺ…령을 톡해 μ‹€μ œλ‘œ νŒ¨ν‚€μ§€λ₯Ό μ„€μΉ˜ν•˜κ²Œ λ©λ‹ˆλ‹€.

dpkg -i package.deb : νŒ¨ν‚€μ§€ μ„€μΉ˜
dpkg -r package     : νŒ¨ν‚€μ§€ 제거
dpkg -l             : μ„€μΉ˜λœ 전체 νŒ¨ν‚€μ§€ λͺ©λ‘ 확인
dpkg -s package     : νŒ¨ν‚€μ§€ 정보 확인 (μ„€μΉ˜λœ νŒ¨ν‚€μ§€ 이름 기반)
dpkg -I package.deb : νŒ¨ν‚€μ§€ 정보 확인 (νŒ¨ν‚€μ§€ 파일λͺ… 기반)
dpkg -L package     : νŒ¨ν‚€μ§€μ— ν¬ν•¨λœ 파일 λͺ©λ‘ 확인 (μ„€μΉ˜λœ νŒ¨ν‚€μ§€ 이름 기반)
dpkg -c package.deb : νŒ¨ν‚€μ§€μ— ν¬ν•¨λœ 파일 λͺ©λ‘ 확인 (νŒ¨ν‚€μ§€ 파일λͺ… 기반)

dpkg-buildpackage

dpkg-buildpackageλŠ” deb νŒ¨ν‚€μ§€λ₯Ό λΉŒλ“œν•˜κΈ° μœ„ν•œ κΈ°λ³Έ λ„κ΅¬μž…λ‹ˆλ‹€. 주둜 개발 ν™˜κ²½μ—μ„œ 직접 λΉŒλ“œν•  λ•Œ 많이 μ‚¬μš©λ˜λŠ”λ°, ν˜„μž¬ μ‹œμŠ€ν…œ ν™˜κ²½μ—μ„œ λ°”λ‘œ νŒ¨ν‚€μ§€λ₯Ό λΉŒλ“œν•˜κΈ° λ•Œλ¬Έμ— λΉ λ₯΄κ²Œ νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ, λ‚΄ μ‹œμŠ€ν…œμ—μ„œλŠ” μ •μƒμ μœΌλ‘œ νŒ¨ν‚€μ§€ λΉŒλ“œμ— μ„±κ³΅ν–ˆμ–΄λ„ λ‹€λ₯Έ μ‚¬λžŒμ˜ μ‹œμŠ€ν…œ ν™˜κ²½μ—μ„œ λ˜‘κ°™μ΄ λΉŒλ“œκ°€ μ„±κ³΅ν•œλ‹€κ³  보μž₯ν•  수 μ—†μŠ΅λ‹ˆλ‹€. 각 μ‹œμŠ€ν…œλ§ˆλ‹€ μ„€μΉ˜λœ νŒ¨ν‚€μ§€λ“€μ΄ λ‹€λ₯΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. λ”°λΌμ„œ, μ •μ‹μœΌλ‘œ νŒ¨ν‚€μ§• μž‘μ—…μ„ μ§„ν–‰ν•˜κΈ° 전에 λΉ λ₯΄κ²Œ νŒ¨ν‚€μ§•μ„ ν…ŒμŠ€νŠΈν•  λͺ©μ μœΌλ‘œ μ‚¬μš©ν•˜κΈ°μ— μ ν•©ν•œ λ„κ΅¬μž…λ‹ˆλ‹€.

ALN κΈ°μ€€μœΌλ‘œ νŒ¨ν‚€μ§€ λΉŒλ“œν•˜λŠ” 방법은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

# μ†ŒμŠ€ λ‹€μš΄λ‘œλ“œ
git clone https://github.com/webispy/aln.git
cd aln

# debian νŒ¨ν‚€μ§€ 디렉토리 μ€€λΉ„ (from packaging/jammy, packaging/focal)
DIST_NAME=$(lsb_release -c | awk '{print $2}')
cp -a packaging/$DIST_NAME debian

# νŒ¨ν‚€μ§€ λΉŒλ“œ (μ„œλͺ… 없이 λΉŒλ“œ)
#  -uc: unsigned .buildinfo and .changes file.
#  -us: unsigned source package.
dpkg-buildpackage -uc -us

νŒ¨ν‚€μ§€λ“€μ€ dpkg-buildpackage λͺ…령을 μ‹€ν–‰ν•œ λ””λ ‰ν† λ¦¬μ˜ μƒμœ„ 디렉토리에 μƒμ„±λ©λ‹ˆλ‹€.

$ cd ..
$ ls
aln # -> μ†ŒμŠ€ 디렉토리
aln-dbg_0.1.0~jammy_arm64.deb
aln_0.1.0~jammy.dsc
aln_0.1.0~jammy.tar.gz
aln_0.1.0~jammy_arm64.buildinfo
aln_0.1.0~jammy_arm64.changes
aln_0.1.0~jammy_arm64.deb
libaln-dev_0.1.0~jammy_arm64.deb
libaln0-dbg_0.1.0~jammy_arm64.deb
libaln0_0.1.0~jammy_arm64.deb

이제 dpkg λͺ…λ ΉμœΌλ‘œ ALN νŒ¨ν‚€μ§€λ₯Ό μ‹œμŠ€ν…œμ— μ„€μΉ˜ 및 μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€. 단, dpkg λͺ…령은 μ˜μ‘΄μ„± νŒ¨ν‚€μ§€μ— λŒ€ν•΄ μžλ™μœΌλ‘œ ν•΄κ²°ν•΄μ£Όμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ„€μΉ˜ μ‹œ μ˜μ‘΄μ„± νŒ¨ν‚€μ§€ νŒŒμΌλ“€λ„ 같이 λ‚˜μ—΄ν•΄ μ£Όμ–΄μ•Ό μ •μƒμ μœΌλ‘œ μ„€μΉ˜λ©λ‹ˆλ‹€.

# μ„€μΉ˜
sudo dpkg -i aln_0.1.0~jammy_arm64.deb libaln0_0.1.0~jammy_arm64.deb

# μ‚­μ œ
sudo dpkg -r aln libaln0

gbp (git-buildpackage)

gbpλŠ” μ΄λ¦„μ—μ„œ μ•Œ 수 μžˆλ“―μ΄ dpkg-buildpackage와 Git 리포지토리λ₯Ό ν†΅ν•©ν•œ νŒ¨ν‚€μ§€ λΉŒλ“œ νˆ΄μž…λ‹ˆλ‹€. git tag, branch λ“±κ³Ό μ—°κ³„ν•΄μ„œ 더 κ°•λ ₯ν•˜κ²Œ νŒ¨ν‚€μ§• μž‘μ—…μ„ μ§„ν–‰ν•  수 있고, μ†ŒμŠ€ μˆ˜μ • ν›„ 컀밋을 λ§Œλ“€μ§€ μ•Šμ€ μƒνƒœμ—μ„œ gbp buildpackage λͺ…령을 μ‹€ν–‰ν•˜λ©΄ μˆ˜μ •λœ νŒŒμΌμ„ μ•Œλ €μ£Όλ©΄μ„œ λΉŒλ“œ μ—λŸ¬κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ‹€μˆ˜λ₯Ό 쀄여쀄 수 μžˆμŠ΅λ‹ˆλ‹€.

gbp μ„€μΉ˜λŠ” μ•„λž˜μ™€ 같이 apt λͺ…λ ΉμœΌλ‘œ κ°€λŠ₯ν•©λ‹ˆλ‹€.

sudo apt install git-buildpackage

λΉŒλ“œ μ˜΅μ…˜μ€ dpkg-buildpackage와 λ™μΌν•˜κΈ° λ•Œλ¬Έμ—, μ•„λž˜μ™€ 같이 λͺ…령을 μ‹€ν–‰ν•˜λ©΄ νŒ¨ν‚€μ§€λ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

gbp buildpackage -uc -us

μžμ„Έν•œ μ˜΅μ…˜ 및 μ‚¬μš©λ²•μ€ https://honk.sigxcpu.org/piki/projects/git-buildpackage/ ν™ˆνŽ˜μ΄μ§€λ₯Ό μ°Έκ³  λ°”λžλ‹ˆλ‹€.

sbuild

Debian λΉŒλ“œ μ‹œμŠ€ν…œμ—μ„œ μ‚¬μš©λ˜λŠ” κ°•λ ₯ν•œ λΉŒλ“œ λ„κ΅¬λ‘œ dpkg-buildpackage와 λ‹€λ₯΄κ²Œ ν˜„μž¬ μ‹œμŠ€ν…œ ν™˜κ²½μ„ μ΄μš©ν•˜μ§€ μ•Šκ³  chroot ν™˜κ²½(change root의 μ•½μžλ‘œ 격리된 파일 μ‹œμŠ€ν…œ ν™˜κ²½μ„ 제곡)μ—μ„œ λΉŒλ“œν•©λ‹ˆλ‹€.

Ubuntu의 ν•„μˆ˜ νŒ¨ν‚€μ§€λ§Œ μ„€μΉ˜λœ κΉ¨λ—ν•œ 가상 ν™˜κ²½μ—μ„œ λΉŒλ“œκ°€ μ§„ν–‰λ˜κΈ° λ•Œλ¬Έμ—, λΉŒλ“œν•˜λ €λŠ” νŒ¨ν‚€μ§€μ˜ μ˜μ‘΄μ„±μ„ ν™•μ‹€ν•˜κ²Œ 점검할 수 있고 격리된 ν™˜κ²½μ΄κΈ° λ•Œλ¬Έμ— ν˜„μž¬ μ‹œμŠ€ν…œμ— 영ν–₯을 μ£Όμ§€ μ•Šμ•„ μ•ˆμ „ν•˜κ²Œ νŒ¨ν‚€μ§• μž‘μ—…μ„ μ§„ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ, chrootλ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— ν˜„μž¬ μ‹œμŠ€ν…œμ— μ„€μΉ˜λœ Ubuntu 배포판 버전과 λ‹€λ₯Έ λ²„μ „μš© νŒ¨ν‚€μ§€λ₯Ό 생성할 수 있고 cross-compile ν™˜κ²½λ„ μ§€μ›ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ ν˜„μž¬ μ‹œμŠ€ν…œμ—λŠ” Ubuntu 22.04 (Jammy) amd64κ°€ μ„€μΉ˜λ˜μ–΄ μžˆλŠ”λ°, 20.04 (Focal)용 νŒ¨ν‚€μ§€λ₯Ό 생성할 수 있고, arm64/armhf 용 νŒ¨ν‚€μ§€λ„ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

sbuildλ₯Ό 톡해 νŒ¨ν‚€μ§•μ„ μˆ˜ν–‰ν•˜λ©΄ μ•„λž˜ 과정이 맀번 μˆ˜ν–‰λ©λ‹ˆλ‹€.

  • apt update
  • apt upgrade
  • debian/control에 λͺ…μ‹œν•œ μ˜μ‘΄μ„± νŒ¨ν‚€μ§€ μ„€μΉ˜
  • λΉŒλ“œ (dpkg-buildpackage)
  • lintian - νŒ¨ν‚€μ§€ 검사

이후 sbuildκ°€ λλ‚˜λ©΄ νŒ¨ν‚€μ§• κ³Όμ • 쀑 μ„€μΉ˜/μƒμ„±λœ λͺ¨λ“  νŒŒμΌλ“€μ΄ μ œκ±°λ©λ‹ˆλ‹€. λ”°λΌμ„œ, λ‹€μ‹œ νŒ¨ν‚€μ§•μ„ μˆ˜ν–‰ν•΄λ„ 맀번 κΉ¨λ—ν•œ ν™˜κ²½μ—μ„œ μœ„ 과정이 μƒˆλ‘œ μˆ˜ν–‰λ©λ‹ˆλ‹€. μ΄λŠ” sbuild λ‚΄λΆ€μ—μ„œ docker와 μœ μ‚¬ν•˜κ²Œ overlayfsλ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

sbuild μ„€μ •

sbuild μ„€μΉ˜λŠ” μ•„λž˜μ™€ 같이 apt λͺ…λ ΉμœΌλ‘œ κ°€λŠ₯ν•©λ‹ˆλ‹€.

sudo apt install -y sbuild ubuntu-dev-tools

μ„€μΉ˜ ν›„ μΆ”κ°€ μ„€μ • μž‘μ—…μ΄ ν•„μš”ν•œλ°, sbuild νŒ¨ν‚€μ§€λ₯Ό μ„€μΉ˜ν•˜λ©΄ sbuild 그룹이 μΆ”κ°€λ©λ‹ˆλ‹€. λ”°λΌμ„œ sbuild λͺ…령을 μ‚¬μš©ν•˜λ €λ©΄ μ‚¬μš©μžλ₯Ό 그룹에 μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

sudo sbuild-adduser $USER

참고둜, 그룹에 μ‚¬μš©μžλ₯Ό μΆ”κ°€ν–ˆλ‹€κ³  ν˜„μž¬ μ‰˜μ— λ°”λ‘œ 그룹이 λ°˜μ˜λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μƒˆλ‘œμš΄ μ‰˜μ„ μ—΄κ±°λ‚˜ ν˜„μž¬ μ‰˜μ—μ„œ newgrp sbuild와 같은 λͺ…령을 톡해 그룹을 μ§€μ •ν•΄μ£Όμ–΄μ•Ό μ •μƒμ μœΌλ‘œ μ‚¬μš©μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.

λ‹€μŒμœΌλ‘œ chroot ν™˜κ²½μ„ λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€. νŒ¨ν‚€μ§• ν•˜λ €λŠ” 배포판 λ²„μ „λ³„λ‘œ μ•„λž˜ λͺ…령을 톡해 μƒμ„±ν•©λ‹ˆλ‹€.

mk-sbuild jammy
mk-sbuild focal

μƒμ„±λœ chroot 이름은 기본으둜 이름 뒀에 -{arch}κ°€ μΆ”κ°€λ©λ‹ˆλ‹€. μœ„μ˜ λͺ…령을 예둜 λ“€λ©΄, jammy-amd64, focal-amd64 μ΄λ ‡κ²Œ chroot 이름을 κ°€μ§€κ²Œ λ©λ‹ˆλ‹€.

μ•„λž˜μ™€ 같이 --target을 μ§€μ •ν•˜λ©΄ cross-compile ν™˜κ²½λ„ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

mk-sbuild --target armhf jammy
mk-sbuild --target arm64 jammy

cross-compile ν™˜κ²½μœΌλ‘œ μƒμ„±ν–ˆμ„ 경우 chroot 이름에 -{target}이 μΆ”κ°€λ©λ‹ˆλ‹€. jammy-amd64-armhf, jammy-amd64-arm64

μ΄λ ‡κ²Œ μƒμ„±ν•œ chroot ν™˜κ²½μ„ golden-image라고 λΆ€λ₯΄κ³ , μ•„λž˜ λͺ…λ ΉμœΌλ‘œ 직접 chroot snapshot ν™˜κ²½μœΌλ‘œ λ“€μ–΄κ°ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.

# ν˜„μž¬ μ‚¬μš©μž
schroot -c jammy-amd64

# root μ‚¬μš©
schroot -c jammy-amd64 -u root

참고둜, μœ„ ν™˜κ²½μ—μ„œ νŒŒμΌμ„ λ§Œλ“€κ³  μˆ˜μ •ν•΄λ„ exit둜 λ‚˜κ°”λ‹€κ°€ λ‹€μ‹œ λ“€μ–΄κ°€λ©΄ λͺ¨λ‘ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€. 영ꡬ적으둜 λ³€κ²½ν•˜λ €λ©΄ μ•„λž˜μ™€ 같이 golden-imageλ₯Ό μ‚¬μš©ν•΄μ„œ μ ‘κ·Όν•΄μ•Ό ν•©λ‹ˆλ‹€.

sudo schroot -c source:jammy-amd64 -u root

mk-sbuild둜 chroot 이미지λ₯Ό λ§Œλ“ μ§€ λ„ˆλ¬΄ μ˜€λž˜λ˜μ„œ sbuild둜 νŒ¨ν‚€μ§•μ„ μˆ˜ν–‰ν•  λ•Œλ§ˆλ‹€ apt update 및 apt upgrade에 μ‹œκ°„μ΄ 많이 μ†Œμš”λœλ‹€λ©΄, μ•„λž˜ λͺ…령을 톡해 chroot 이미지에 μ„€μΉ˜λœ νŒ¨ν‚€μ§€λ“€μ„ μ΅œμ‹ μœΌλ‘œ μ—…κ·Έλ ˆμ΄λ“œ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

sudo sbuild-update --upgrade jammy-amd64

sbuildλ₯Ό μ΄μš©ν•œ νŒ¨ν‚€μ§•

μœ„μ—μ„œ sbuildλ₯Ό μœ„ν•œ chroot μ€€λΉ„κ°€ λͺ¨λ‘ λλ‚¬μœΌλ©΄, 이제 sbuild λͺ…λ ΉμœΌλ‘œ deb νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

λ¨Όμ € ALN μ†ŒμŠ€μ½”λ“œλ₯Ό λ‹€μš΄λ‘œλ“œ λ°›κ³  λ°°ν¬νŒμ— λ§žλŠ” debian 디렉토리λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

# μ†ŒμŠ€ λ‹€μš΄λ‘œλ“œ
git clone https://github.com/webispy/aln.git
cd aln

# debian νŒ¨ν‚€μ§€ 디렉토리 μ€€λΉ„ (from packaging/jammy, packaging/focal)
cp -a packaging/jammy debian

이제 sbuild λͺ…λ ΉμœΌλ‘œ νŒ¨ν‚€μ§€ λΉŒλ“œλ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€.

cd aln
sbuild --chroot jammy-amd64

μ•žμ— mk-sbuild κ³Όμ •μ—μ„œ cross-compile을 μœ„ν•œ chrootλ₯Ό λ§Œλ“€μ—ˆλ‹€λ©΄ μ•„λž˜ λͺ…λ ΉμœΌλ‘œ νŒ¨ν‚€μ§€ λΉŒλ“œλ₯Ό μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

sbuild --chroot jammy-amd64-armhf --host armhf

sbuild troubleshooting

일반적으둜 CI/CD ν™˜κ²½ ꡬ성을 μœ„ν•΄ docker ν™˜κ²½κ³Ό Github action을 많이 μ‚¬μš©ν•˜λŠ”λ°, νŒ¨ν‚€μ§•μ„ κ²€μ¦ν•˜κΈ° μœ„ν•΄ docker μ•ˆμ—μ„œ sbuildλ₯Ό μ‹€ν–‰ν•˜κ±°λ‚˜ Github Action runnerμ•ˆμ—μ„œ sbuildλ₯Ό μ‹€ν–‰ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 아무 이슈 없이 μ •μƒμ μœΌλ‘œ μ‹€ν–‰λ˜λ©΄ μ’‹κ² μ§€λ§Œ, sbuildμ—μ„œ overlayfsλ₯Ό μ‚¬μš©ν•΄μ„œ chrootλ₯Ό μ ‘κ·Όν•˜κΈ° λ•Œλ¬Έμ— λ•Œλ•Œλ‘œ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” 기본으둜 docker container μ‹€ν–‰μ‹œ --privileged μ˜΅μ…˜μ΄ ν•„μš”ν•˜κ³ , overlayfs둜 μ‚¬μš©λ˜λŠ” /var/lib/schroot 처리 방법에 따라 λ‹€μŒκ³Ό 2κ°€μ§€ ν•΄κ²° 방법이 μžˆμŠ΅λ‹ˆλ‹€.

  1. overlayfs둜 μ‚¬μš©λ˜λŠ” /var/lib/schroot 경둜λ₯Ό -v μ˜΅μ…˜μ„ 톡해 volume으둜 μ„€μ •:
$ docker run -it --rm -v /var/lib/schroot --privileged ubuntu:latest
root: # apt update 및 sbuild μ„€μΉ˜, μ‚¬μš©μž μΆ”κ°€, sbuild κ·Έλ£Ή 및 sudoers μ„€μ •...
user: mk-sbuild jammy
user: git clone https://github.com/webispy/aln.git
user: cd aln && cp -a packaging/jammy debian
user: sbuild -c jammy-amd64
  1. schroot λ‚΄λΆ€μ—μ„œ tmpfsλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ„€μ •:
$ docker run -it --rm --privileged ubuntu:latest
root: # apt update 및 sbuild μ„€μΉ˜, μ‚¬μš©μž μΆ”κ°€, sbuild κ·Έλ£Ή 및 sudoers μ„€μ •...
root: vi /etc/schroot/setup.d/04tmpfs
#!/bin/sh

set -e

. "$SETUP_DATA_DIR/common-data"
. "$SETUP_DATA_DIR/common-functions"
. "$SETUP_DATA_DIR/common-config"

if [ "$STAGE" = "setup-start" ]; then
  mount -t tmpfs overlay /var/lib/schroot/union/overlay
elif [ "$STAGE" = "setup-recover" ]; then
  mount -t tmpfs overlay /var/lib/schroot/union/overlay
elif [ "$STAGE" = "setup-stop" ]; then
  umount -f /var/lib/schroot/union/overlay
fi

root: chmod +x /etc/schroot/setup.d/04tmpfs
user: mk-sbuild jammy
user: git clone https://github.com/webispy/aln.git
user: cd aln && cp -a packaging/jammy debian
user: sbuild -c jammy-amd64

ALNμ—μ„œλŠ” Github Action을 톡해 CI/CDλ₯Ό μ‚¬μš©ν•˜λŠ”λ°, Runner μ•ˆμ—μ„œ tmpfsλ₯Ό μ„€μ •ν•˜μ—¬ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ ALN의 Github Action 슀크립트(https://github.com/webispy/aln/blob/master/.github/workflows/ci.yaml)λ₯Ό μ°Έκ³  λ°”λžλ‹ˆλ‹€.

마무리

μ§€κΈˆκΉŒμ§€ deb νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“œλŠ” 과정에 λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€. deb νŒ¨ν‚€μ§•μ€ μ²˜μŒμ—λŠ” λ³΅μž‘ν•΄ 보일 수 μžˆμ§€λ§Œ, 각 단계λ₯Ό μ΄ν•΄ν•˜κ³  μ‹€μŠ΅ν•΄λ³΄λ©΄ μΆ©λΆ„νžˆ 읡힐 수 μžˆλŠ” κ³Όμ •μž…λ‹ˆλ‹€. 이 글을 μ°Έκ³ ν•˜μ—¬ 직접 νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€μ–΄λ³΄λŠ” 것도 쒋은 κ²½ν—˜μ΄ 될 κ²ƒμž…λ‹ˆλ‹€.

λ‹€μŒ κΈ€μ—μ„œλŠ” λ§Œλ“€μ–΄μ§„ deb νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©μžλ“€μ—κ²Œ 효과적으둜 λ°°ν¬ν•˜λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. 자체 apt μ €μž₯μ†Œ ꡬ좕, PPA(Personal Package Archive)λ₯Ό μ΄μš©ν•œ 배포, 그리고 νŒ¨ν‚€μ§€ μ„œλͺ… λ“± 배포 κ³Όμ •μ—μ„œ κ³ λ €ν•΄μ•Ό ν•  μ€‘μš”ν•œ 사항듀을 λ‹€λ£° μ˜ˆμ •μž…λ‹ˆλ‹€.

⚠️ **GitHub.com Fallback** ⚠️