Sepanjang section ini kita memakai library dari berbagai belahan dunia — SQLite, asio, OpenCV, ONNX Runtime — dan semuanya punya satu kesamaan yang jarang disyukuri: kodenya berjalan mulus di Linux, Windows, dan macOS. Kini giliran kode Anda sendiri untuk mendapatkan kualitas yang sama. Kode C++ yang “berjalan di komputer saya” bisa berperilaku berbeda di mesin lain bukan karena kerapian programmer, melainkan karena empat sumber perbedaan nyata: representasi jalur file, urutan byte (endianness), konvensi line ending, dan perbedaan antar compiler. Pada Chapter penutup section ini kita lewati satu per satu dengan alat bantu standar C++, memverifikasinya dengan program yang melaporkan platform-nya sendiri, lalu merangkum seluruh perjalanan section ini sebelum menyerahkan tongkatnya ke dunia deployment.

Jalur File: Satu Masalah yang Sudah Terselesaikan #

Sebelum C++17, developer menulis "C:\\Users\\data" untuk Windows dan "/home/data" untuk Linux, lalu menyisipkan #ifdef di mana-mana. std::filesystem menyelesaikannya: class std::filesystem::path menerima pemisah dari kedua konvensi, menyimpannya dalam bentuk netral, dan mengeluarkan bentuk asli platform lewat native(). Aturannya tinggal satu — selalu bangun jalur dengan operator/ dan path, jangan pernah menggabungkan string dengan \ manual:

cpp Pola std::filesystem (ilustrasi)
#include <filesystem>
namespace fs = std::filesystem;

fs::path lokasi = fs::current_path() / "data" / "koperasi.db";  // pemisah otomatis
fs::create_directories(lokasi.parent_path());                    // mkdir -p
bool ada = fs::exists(lokasi);

Bonus yang sering dilupakan: filesystem macOS secara bawaan case-insensitive sedangkan Linux case-sensitive — Data.csv dan data.csv adalah dua file di Linux tetapi satu di macOS. std::filesystem tidak menyelamatkan Anda dari perbedaan ini, hanya membuat jalurnya sendiri netral; konsistensi penulisan huruf adalah tanggung jawab kita.

Endianness dan Ukuran Tipe #

Recap singkat dari chapter-chapter data: CPU x86-64 dan ARM64 menyusun byte bilangan dari yang terkecil (little-endian), sementara format jaringan dan banyak format file menuntut big-endian. Menyimpan int mentah ke file lalu membacanya di mesin ber-endian lain menghasilkan angka yang berbeda — dan kode tetap “berhasil”. Disiplin amannya: pakai tipe berlebar tetap (int32_t, uint64_t) untuk data biner, tetapkan endianness format secara eksplisit, dan konversi saat serialisasi.

Perbedaan ukuran tipe juga nyata: long berukuran 4 byte di Windows (model LLP64) tetapi 8 byte di Linux dan macOS (model LP64). sizeof(long) yang berbeda di antara dua platform adalah sumber bug serialisasi yang halus; program uji di bawah mencetak nilai-nilai ini agar Anda bisa membandingkannya antar mesin.

Line Endings: \n, \r\n, dan Mode Teks #

Linux dan macOS menutup baris dengan \n (LF); Windows dengan \r\n (CRLF). Bahaya aslinya bukan perbedaan itu sendiri, melainkan mode teks: di Windows, membuka file dengan "r"/"w" membuat runtime menerjemahkan CRLF menjadi \n (dan sebaliknya) secara diam-diam, sehingga ftell tidak lagi sama dengan jumlah byte di disk, dan file biner yang dibuka tanpa mode "b" bisa terpotong di byte 0x1A. Kebiasaan yang menyelamatkan: data biner selalu dengan "rb"/"wb", data teks simpan dengan \n dan biarkan alat (mis. git config core.autocrlf) yang menangani konversi tampilan. File CSV yang dihasilkan di Windows dan dibaca parser sederhana di Linux tanpa membuang \r adalah gotcha klasik dari keluarga yang sama.

Preprocessor: Cabang Kode per Platform #

Preprocessor bisa memilih kode per platform saat kompilasi. Program berikut melaporkan lingkungan tempat ia dibangun — dan kita jalankan sungguhan di mesin course ini:

cpp
// info-platform.cpp — program portabel yang melaporkan lingkungan tempat ia
// dikompilasi. Semua cabang #ifdef dipilih saat compile time, bukan runtime,
// sehingga satu binary hanya membawa cabang yang cocok dengan platformnya.
#include <bit>
#include <cstdio>
#include <filesystem>

int main() {
#if defined(_WIN32)
    const char* os = "Windows";
#elif defined(__APPLE__)
    const char* os = "macOS";
#elif defined(__linux__)
    const char* os = "Linux";
#else
    const char* os = "tidak dikenal";
#endif
    std::printf("OS            : %s\n", os);

#if defined(__x86_64__) || defined(_M_X64)
    const char* arsitektur = "x86-64";
#elif defined(__aarch64__) || defined(_M_ARM64)
    const char* arsitektur = "ARM64";
#else
    const char* arsitektur = "tidak dikenal";
#endif
    std::printf("Arsitektur    : %s\n", arsitektur);

#if defined(__clang__)
    std::printf("Compiler      : Clang %d.%d.%d\n",
                __clang_major__, __clang_minor__, __clang_patchlevel__);
#elif defined(__GNUC__)
    std::printf("Compiler      : GCC %d.%d.%d\n",
                __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
#elif defined(_MSC_VER)
    std::printf("Compiler      : MSVC %d\n", _MSC_VER);
#endif

    const char* endian = "tidak dikenal";
    if constexpr (std::endian::native == std::endian::little) {
        endian = "little-endian";
    } else if constexpr (std::endian::native == std::endian::big) {
        endian = "big-endian";
    }
    std::printf("Endian        : %s\n", endian);

    std::printf("sizeof(long)  : %zu byte\n", sizeof(long));
    std::printf("sizeof(void*) : %zu byte\n", sizeof(void*));
    std::printf("Pemisah path  : '%c'\n",
                static_cast<char>(std::filesystem::path::preferred_separator));
    return 0;
}

Output yang Dihasilkan:

text
OS            : Linux
Arsitektur    : x86-64
Compiler      : GCC 14.2.0
Endian        : little-endian
sizeof(long)  : 8 byte
sizeof(void*) : 8 byte
Pemisah path  : '/'

Bedah bagian pentingnya:

  1. Baris 9-18 (identifikasi OS) — #if defined(_WIN32) memilih konstanta string pada saat kompilasi; bila file yang sama dikompilasi di Windows, hanya cabang pertama yang masuk ke binary — cabang lain tidak pernah ada saat runtime.
  2. Baris 20-27 (identifikasi arsitektur) — makro __x86_64__ (GCC/Clang) dan _M_X64 (MSVC) menyaring dua ejaan untuk mesin yang sama; inilah mengapa compiler-dependent code selalu menguji beberapa nama.
  3. Baris 29-37 (identifikasi compiler) — Clang juga mendefinisikan __GNUC__, sehingga uji __clang__ harus didahulukan; urutan #if yang salah adalah gotcha klasiknya.
  4. Baris 39-45 (std::endian) — dimulai C++20, <bit> memberi cara tanpa preprocessor: std::endian::native dibandingkan saat kompilasi dengan if constexpr, jauh lebih aman daripada menebak dari makro.
  5. Baris 47-50 (sizeof dan pemisah) — nilai-nilai yang berbeda antar platform; bila program ini dikompilasi dengan MSVC di Windows x64, sizeof(long) mencetak 4 dan pemisah path mencetak '\'.

Perbedaan Compiler dan Matriks CI #

Tiga compiler mendominasi: GCC (Linux), Clang (macOS, juga umum di Linux), dan MSVC (Windows). Semua mengklaim dukungan C++23 dengan cakupan yang berbeda-beda, diagnostik warning yang berbeda, dan — yang paling penting — undefined behavior bisa berperilaku berbeda: kode yang “jalan” di GCC belum tentu benar. Oleh karena itu, kompilasi ulang dengan compiler kedua adalah test sanitizer murah, dan tool yang mengoperasikannya secara otomatis adalah CI (Continuous Integration). Konsepnya: setiap push diuji pada matriks platform × compiler.

Runner CICompilerPerbedaan yang bisa ditangkap
ubuntu-latestGCCKonfigurasi dasar; warning -Wall -Wextra
ubuntu-latestClangDiagnostik alternatif, ekstensi berbeda
windows-latestMSVCLLP64 (long 4 byte), path Windows, /W4
macos-latestApple ClangFilesystem case-insensitive, linker berbeda

Untuk orkestrasi build lintas platform itu sendiri, CMake yang dipelajari pada section Build System adalah standar de facto: satu CMakeLists.txt, tiga platform:

cmake CMakeLists.txt minimal lintas platform
cmake_minimum_required(VERSION 3.20)
project(informasi_platform CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(info-platform info-platform.cpp)

if(WIN32)
    target_compile_definitions(info-platform PRIVATE APP_WINDOWS=1)
elseif(APPLE)
    target_compile_definitions(info-platform PRIVATE APP_MACOS=1)
endif()

WIN32, APPLE, dan UNIX adalah variabel platform bawaan CMake; perhatikan polanya — perbedaan ditangani di satu titik (definisi compile time), bukan tersebar di kode.

Checklist Portabilitas #

Kumpulkan semua disiplin di atas menjadi daftar yang bisa dicoret sebelum rilis:

  • Bangun jalur file dengan std::filesystem::path dan operator/; tanpa \ manual.
  • Pakai tipe fixed-width (int32_t, uint64_t) dan endianness eksplisit untuk data biner.
  • Data biner dibuka dengan "rb"/"wb"; teks disimpan \n.
  • Jangan mengandalkan ukuran atau alignment tipe tertentu — gunakan sizeof dan alignof.
  • Kode khusus platform terbungkus di belakang antarmuka; #ifdef seminimal mungkin.
  • Kompilasi dengan -Wall -Wextra (GCC/Clang) dan /W4 (MSVC); perlakukan warning sebagai tugas.
  • Uji di minimal dua compiler — idealnya lewat matriks CI.
  • Konsisten huruf besar-kecil pada nama file (ingat macOS case-insensitive).

Penutup Section: Peta yang Sudah Kita Lalui #

Section Interoperabilitas dan Ecosystem dimulai dari satu pertanyaan — “bagaimana C++ berbicara dengan dunia luar?” — dan berakhir dengan peralatan lengkap. Rekap perjalanannya:

ChapterWarisan utamanya
Interoperabilitas C dan C++extern "C" dan kompilasi campuran .c/.cpp
C ABI dan C++ ABIBatas biner yang stabil; apa yang aman melewati batas
Menggunakan Library EksternalHeader + file library; sistem, vendored, header-only
Binding C++ ke PythonC ABI + ctypes; pemetaan tipe manual
pybind11Binding otomatis via template; GIL
C++ dan SQLitePola C API open/prepare/bind/step/finalize + RAII
C++ dan NetworkingBSD sockets; errno; kapan naik ke asio
C++ dan JSONWriter/parser; nlohmann/json dan RapidJSON
C++ dan OpenCVcv::Mat, buffer piksel, luminance
C++ dan ONNX RuntimeEnv/session/tensor; deployment model ML
Cross-platform DevelopmentDisiplin portabilitas yang menyatukan semuanya

Benang merahnya konsisten: di level bawah semua interop berdiri di atas C ABI, di level menengah pada disiplin resource (RAII) dan error handling yang jujur, dan di level atas pada disiplin portabilitas chapter ini. Kode yang lulus semua ujian di atas kini layak naik panggung: Section berikutnya, Deployment dan Distribusi, membawa program Anda keluar dari mesin development — dimulai dari pertanyaan paling mendasar yang selama ini kita abaikan: file executable itu sendiri, dan dependensi runtime apa saja yang harus dibawanya agar hidup di mesin orang lain.

Referensi: std::filesystem di cppreference , CMake Documentation .