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):

DirektoriIsi
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:

bash Pola bila aplikasi membawa library sendiri
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/aplikasi

Pola $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:

cpp
#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:

text
Bunga total : Rp1200000
Saldo akhir : Rp11200000

Baris 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:

bash
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 | sort

Output yang Dihasilkan:

text
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.xml

Tiga 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:

bash
bunga-tunggal_1.0.0-amd64/bin/bunga-tunggal 10000000 6 2

Output yang Dihasilkan:

text
Bunga total : Rp1200000
Saldo akhir : Rp11200000

Outputnya 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”:

text
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:

text
.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:

text
<?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:

bash
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.gz

Output yang Dihasilkan:

text
7abdd1eff19787973d7b479ae14ca404b498941c7b4a033fc03103a16c66a593  bunga-tunggal_1.0.0-amd64.tar.gz

Hash 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:

bash
sha256sum bunga-tunggal_1.0.0-amd64.tar.gz > SHA256SUMS
sha256sum -c SHA256SUMS

Output yang Dihasilkan:

text
bunga-tunggal_1.0.0-amd64.tar.gz: OK

sha256sum -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:

bash Contoh — di mesin penerbit
gpg --armor --detach-sign SHA256SUMS

Perintah itu menghasilkan SHA256SUMS.asc, tanda tangan yang diterbitkan berdampingan dengan tarball dan manifest-nya:

bash Contoh — di mesin pengguna
gpg --import kunci-penerbit.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS

Urutannya 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:

text
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.md diperbarui dan release notes ditulis per rilis.
  • Build dengan flag rilis -O2 -DNDEBUG, -Wall -Wextra bersih dari peringatan baru.
  • Biner di-strip, berkas .debug diarsipkan terpisah (di macOS: strip sebelum codesign).
  • 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) plus SHA256SUMS yang ditandatangani.
  • Catatan per platform: Depends dari ldd (Linux), runtime MSVC dan signtool (Windows), codesign plus 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 .