Semua bahan sudah ada di tangan: biner rilis yang ramping dari Chapter Release Build, kemampuan membangun untuk arsitektur mana pun, resep distribusi Linux/Windows/macOS, dan disiplin versi yang baru kita latih. Chapter penutup section ini menyatukan semuanya menjadi satu objek yang bisa diunduh, diverifikasi, dipasang, dan diperbarui: paket aplikasi. Kita merakitnya secara nyata dari nol — struktur bin/lib/share, berkas metainformasi, tarball reproducible, checksum dan tanda tangan, hingga mekanisme pembaruan — lalu menutup section dengan checklist rilis lengkap yang merangkum seluruh perjalanan.
Anatomi Struktur Paket #
Paket aplikasi yang sehat menempati satu prefix — di Linux lazimnya /usr atau /usr/local — dan di dalamnya berbagi tiga direktori inti yang aturannya ditetapkan FHS (Chapter Deployment di Linux sudah kita pakai untuk paket .deb):
| Direktori | Isi |
|---|---|
bin/ | Executable aplikasi, sudah melalui strip |
lib/ | Library milik aplikasi sendiri (bila ada) |
share/doc/<nama>/ | README, CHANGELOG, LICENSE |
share/man/man1/ | Halaman manual (format roff, ter-gzip) |
share/metainfo/ | Deskripsi terstruktur untuk katalog toko aplikasi (AppStream) |
Pembagian ini punya alasan teknis, bukan sekadar kerapian: bin/ berisi kode mesin yang terikat arsitektur, sedangkan share/ berisi data yang sama untuk semua arsitektur — dokumen, ikon, manual — sehingga distribusi bisa memisahkannya ke paket “arch-independent”. lib/ hanya terisi bila aplikasi membawa library miliknya sendiri, dan bila iya, keduanya diikat dengan rpath yang relatif terhadap aplikasi:
g++ -std=c++23 -O2 -fPIC -shared logika.cpp -o paket/lib/liblogika.so
g++ -std=c++23 -O2 aplikasi.cpp -Lpaket/lib -llogika \
-Wl,-rpath,'$ORIGIN/../lib' -o paket/bin/aplikasiPola $ORIGIN/../lib adalah turunan langsung dari mekanisme di Chapter Dynamic Library Deployment: library bergerak bersama aplikasi ke mana pun paketnya dipasang. Aplikasi contoh kita satu biner murni sehingga lib/ disiapkan kosong — strukturnya yang tetap dibangun, agar paket tumbuh tanpa renovasi.
Program yang Kita Kemas #
Bahan ujinya kalkulator bunga tunggal — aplikasi CLI dengan disiplin argumen yang sama dengan semua program rilis di section ini:
#include <iomanip>
#include <iostream>
// Kalkulator bunga tunggal: aplikasi CLI yang kita kemas sebagai paket
// rilis di chapter ini. Pokok, bunga tahunan (persen), dan durasi (tahun)
// diambil dari argumen baris perintah.
int main(int argc, char* argv[]) {
if (argc < 4) {
std::cerr << "Pemakaian: bunga-tunggal <pokok> <bunga-persen> <tahun>\n";
return 1;
}
double pokok = std::stod(argv[1]);
double bunga = std::stod(argv[2]);
int tahun = std::stoi(argv[3]);
if (pokok <= 0 || bunga < 0 || tahun <= 0) {
std::cerr << "Parameter tidak valid\n";
return 1;
}
double bungaTotal = pokok * (bunga / 100.0) * tahun;
double total = pokok + bungaTotal;
std::cout << std::fixed << std::setprecision(0);
std::cout << "Bunga total : Rp" << bungaTotal << '\n';
std::cout << "Saldo akhir : Rp" << total << '\n';
return 0;
}Output yang Dihasilkan:
Bunga total : Rp1200000
Saldo akhir : Rp11200000Baris 8-12 menagih tiga argumen dan kembali dengan exit code 1 plus pesan pemakaian ke std::cerr bila kurang. Baris 14-19 mengubah teks menjadi angka lalu menolak kombinasi tidak masuk akal — pokok nol atau negatif, bunga negatif, durasi nol — dengan exit code 1 juga, sehingga skrip yang memakainya bisa mengandalkan exit code sebagai kontrak. Baris 21-22 menerapkan formula bunga tunggal pokok × (bunga% / 100) × tahun. Baris 24-26 mencetak rupiah tanpa desimal agar angka ratusan juta tetap terbaca. Tanpa argumen program juga keluar dengan kode 1, dan itulah program yang mulai sekarang kita perlakukan sebagai “produk”: dibangun dengan flag rilis, di-strip, lalu dikemas.
Merakit Struktur Paket #
Staging paket kita beri nama yang menyandikan versi dan arsitektur — bunga-tunggal_1.0.0-amd64 — kebiasaan yang sama dengan penamaan .deb di Chapter Deployment di Linux dan tarball di formula Homebrew. Empat berkas pendamping (README.txt, LICENSE, halaman manual, metainfo) sudah kita siapkan di direktori kerja — isinya kita bedah setelah rakitan jadi. Build rilis, strip, lalu susun:
mkdir -p /tmp/demo-paket && cd /tmp/demo-paket
g++ -std=c++23 -Wall -Wextra -O2 -DNDEBUG bunga-tunggal.cpp -o bunga-tunggal
strip bunga-tunggal
mkdir -p bunga-tunggal_1.0.0-amd64/bin \
bunga-tunggal_1.0.0-amd64/share/doc/bunga-tunggal \
bunga-tunggal_1.0.0-amd64/share/man/man1 \
bunga-tunggal_1.0.0-amd64/share/metainfo
install -m755 bunga-tunggal bunga-tunggal_1.0.0-amd64/bin/
cp README.txt LICENSE bunga-tunggal_1.0.0-amd64/share/doc/bunga-tunggal/
cp bunga-tunggal.metainfo.xml bunga-tunggal_1.0.0-amd64/share/metainfo/
gzip -n -9 -c bunga-tunggal.1 > bunga-tunggal_1.0.0-amd64/share/man/man1/bunga-tunggal.1.gz
find bunga-tunggal_1.0.0-amd64 -type f | sortOutput yang Dihasilkan:
bunga-tunggal_1.0.0-amd64/bin/bunga-tunggal
bunga-tunggal_1.0.0-amd64/share/doc/bunga-tunggal/LICENSE
bunga-tunggal_1.0.0-amd64/share/doc/bunga-tunggal/README.txt
bunga-tunggal_1.0.0-amd64/share/man/man1/bunga-tunggal.1.gz
bunga-tunggal_1.0.0-amd64/share/metainfo/bunga-tunggal.metainfo.xmlTiga perintah di rakitan ini berhak dicermati. install -m755 menyalin biner sekaligus menetapkan izin eksekusinya dalam satu langkah — cp saja tidak mengatur izin secara eksplisit. gzip -n adalah kunci kecil yang besar efeknya: header berkas gzip menyimpan stempel waktu berkas asal dan namanya, sehingga tanpa -n halaman manual yang isinya identik menghasilkan byte .gz yang berbeda setiap kali dibuat — dan checksum paket yang kita terbitkan berubah tanpa alasan. Baris find | sort memastikan daftar isi tercetak dengan urutan tetap, kebiasaan kecil yang sama dengan filosofi reproducible builds. Lalu, sebelum apa pun dikirim, kita uji biner di dalam staging-nya sendiri:
bunga-tunggal_1.0.0-amd64/bin/bunga-tunggal 10000000 6 2Output yang Dihasilkan:
Bunga total : Rp1200000
Saldo akhir : Rp11200000Outputnya sama persis dengan uji di awal chapter — bukti bahwa biner yang diuji adalah biner yang dikirim, bukan build debug yang kebetulan berada di folder yang sama.
Metainformasi: Dokumen Pendamping #
Paket tanpa dokumen pendamping membuat pengguna menebak. Berkas pertama, README.txt, cukup sembilan baris — cukup untuk menjawab “ini apa dan cara pakainya”:
bunga-tunggal 1.0.0
Kalkulator bunga tunggal dari kursus C++.
Pemakaian:
bunga-tunggal <pokok> <bunga-persen> <tahun>
Dokumentasi lengkap: halaman manual bunga-tunggal(1).Berkas kedua, halaman manual bunga-tunggal.1, ditulis dalam format roff yang sudah dipakai manual Unix sejak puluhan tahun — distro menyimpannya di share/man/man1/ ter-gzip, dan pengguna membacanya dengan man bunga-tunggal:
.TH BUNGA-TUNGGAL 1 "Januari 2026" "bunga-tunggal 1.0.0" "Manual pengguna"
.SH NAMA
bunga-tunggal \- menghitung bunga tunggal dari pokok, bunga tahunan, dan durasi
.SH SINOPSIS
.B bunga-tunggal
.I pokok bunga-persen tahun
.SH DESKRIPSI
Menghitung bunga tunggal: bunga = pokok x (bunga% / 100) x tahun.
Menagih tiga argumen dan menolak nilai yang tidak valid dengan exit code 1.
.SH LIHAT JUGA
CHANGELOG dan LICENSE di share/doc/bunga-tunggal/.Berkas ketiga, bunga-tunggal.metainfo.xml, mengikuti format AppStream — katalog terstruktur yang dibaca toko aplikasi grafis (GNOME Software, KDE Discover) untuk menampilkan deskripsi, lisensi, dan riwayat versi aplikasi CLI pun:
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>com.example.bunga-tunggal</id>
<name>bunga-tunggal</name>
<summary>Kalkulator bunga tunggal dari baris perintah</summary>
<metadata_license>MIT</metadata_license>
<releases>
<release version="1.0.0" date="2026-01-10">
<description>
<p>Rilis stabil pertama: perhitungan bunga tunggal CLI.</p>
</description>
</release>
</releases>
</component>Pola yang akrab: id reverse-DNS sama seperti CFBundleIdentifier di bundle macOS, dan entri <releases> menyandikan versi dengan tanggal — data yang di Chapter Versioning dan Release kita simpan di changelog dan tag. Keempat berkas pendamping ini satu paket dengan lisensinya: LICENSE berisi teks standar MIT yang menempel di share/doc/, kewajiban hukum termurah yang paling sering terlupa.
Checksum dan Tanda Tangan #
Paket yang siap terbit diketarkan menjadi satu tarball, dan di sinilah semua kunci determinisme bekerja bersama — --sort=name, --mtime, --owner/--group di tar (Chapter Deployment di Linux), ditambah -n di gzip:
tar --sort=name --mtime='2026-01-01' --owner=0 --group=0 \
-cf - bunga-tunggal_1.0.0-amd64 | gzip -n -9 > bunga-tunggal_1.0.0-amd64.tar.gz
sha256sum bunga-tunggal_1.0.0-amd64.tar.gzOutput yang Dihasilkan:
7abdd1eff19787973d7b479ae14ca404b498941c7b4a033fc03103a16c66a593 bunga-tunggal_1.0.0-amd64.tar.gzHash sha256 itu bukan angka kebetulan: kita membangun ulang seluruh pipeline di dua direktori bersih yang berbeda dan keduanya menghasilkan tarball yang byte-per-byte identik — inilah prinsip reproducible builds dari Chapter Release Build yang kini benar-benar terukur, dari source sampai checksum. Hash yang stabil bermakna karena bisa diverifikasi ulang siapa pun; penerbitannya sendiri berbentuk manifest:
sha256sum bunga-tunggal_1.0.0-amd64.tar.gz > SHA256SUMS
sha256sum -c SHA256SUMSOutput yang Dihasilkan:
bunga-tunggal_1.0.0-amd64.tar.gz: OKsha256sum -c membaca manifest dan memeriksa ulang setiap berkasnya — perintah inilah yang nanti dijalankan pengguna, manajer paket, atau mekanisme pembaruan sebelum memercayai tarball. Namun checksum hanya menjawab pertanyaan integritas (“apakah berkasnya utuh?”), bukan keaslian (“apakah ini benar-benar dari penerbit?”). Untuk yang kedua, manifest ditandatangani dengan kunci pribadi penerbit:
gpg --armor --detach-sign SHA256SUMSPerintah itu menghasilkan SHA256SUMS.asc, tanda tangan yang diterbitkan berdampingan dengan tarball dan manifest-nya:
gpg --import kunci-penerbit.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMSUrutannya penting: tanda tangan diperiksa lebih dulu (kunci publik diperoleh lewat saluran terpisah dari unduhan), baru checksum dieksekusi — rantai kepercayaan terbentang dari kunci penerbit sampai byte terakhir tarball.
Pembaruan Aplikasi secara Ringkas #
Paket yang terpasang akan menua, dan ada tiga saluran pembaruannya. Pertama, manajer paket: aplikasi yang masuk repositori distro atau tap Homebrew diperbarui dengan apt upgrade atau brew upgrade — penerbit hanya menyegarkan paketnya. Kedua, katalog toko aplikasi: metainfo AppStream di share/metainfo/ inilah yang memberi tahu GNOME Software bahwa versi baru tersedia. Ketiga, saat menyalurkan sendiri di luar keduanya, aplikasi memeriksa manifest pembaruan secara mandiri:
1. Unduh manifest pembaruan: versi terbaru, URL tarball, checksum sha256.
2. Bandingkan versi manifest dengan keluaran ./bunga-tunggal --version;
bila MAJOR berbeda, tampilkan peringatan perubahan yang memutus.
3. Unduh tarball baru, jalankan sha256sum -c terhadap checksum manifest.
4. Pasang secara atomik: tulis berkas baru ke nama sementara, lalu rename
menimpa biner lama — proses yang gagal di tengah tidak merusak yang lama.
5. Simpan biner sebelumnya sebagai cadangan untuk rollback cepat.Kelima langkah itu merangkai ulang semua yang sudah kita kuasai: langkah 2 memakai konvensi --version satu baris dari Chapter Versioning dan Release, langkah 3 persis sha256sum -c di atas, dan langkah 4 adalah teknik rename atomik yang membuat pembaruan tidak pernah meninggalkan biner setengah tertulis. Manajer paket tetap saluran yang paling disarankan; self-update hanya pantas dipakai bila distribusi memang berdiri sendiri.
Checklist Rilis Lengkap #
Section ini menutup dengan daftar yang bisa Anda pakai sebagai gerbang sebelum setiap rilis — gabungan seluruh aturan yang kita latih:
- Nomor versi naik secara sadar (SemVer): konstanta
VERSI, tag, dan changelog cocok; gerbang otomasi lulus. CHANGELOG.mddiperbarui dan release notes ditulis per rilis.- Build dengan flag rilis
-O2 -DNDEBUG,-Wall -Wextrabersih dari peringatan baru. - Biner di-strip, berkas
.debugdiarsipkan terpisah (di macOS: strip sebelumcodesign). - Staging lengkap:
bin/,lib/bila ada library sendiri,share/doc/,share/man/,share/metainfo/. - README, LICENSE, halaman manual, dan metainfo menyebut versi baru.
- Tarball reproducible (sort, mtime, owner,
gzip -n) plusSHA256SUMSyang ditandatangani. - Catatan per platform:
Dependsdarildd(Linux), runtime MSVC dansigntool(Windows),codesignplus notarization dan universal binary (macOS). - Saluran pembaruan siap: entri repositori/toko, atau manifest self-update dengan rename atomik.
- Smoke test di mesin bersih, memakai biner hasil staging — bukan build debug.
Proyek CMake dapat mengotomatiskan rakitan di atas lewat CPack: generator Archive mengetarkan paket dari instalasi yang sudah terstruktur, dan variabel CPACK_PACKAGE_CHECKSUM menerbitkan berkas checksum sekaligus (lihat Referensi). Jalur distribusi modern terakhir menyusul pada chapter berikutnya: kontainer dengan Docker untuk aplikasi yang harus berjalan identik di lingkungan apa pun.
Referensi: CPack — CMake Docs , CPack Archive Generator — CMake Docs .