Chapter Cross-compilation menunjukkan bahwa satu source C++ dapat dibangun menjadi biner untuk arsitektur mana pun, asalkan toolchain targetnya tersedia. Target berikutnya paling tidak terduga: browser web. Sejak format WebAssembly (Wasm) distandarisasi, kode C++ tidak lagi berhenti di terminal dan server — game engine, editor gambar, dan codec media kini berjalan di dalam tab browser setelah dikompilasi dari source C++. Chapter ini membahas kapan porting ke browser masuk akal, bagaimana toolchain Emscripten bekerja, dan batasan apa yang dikenakan sandbox browser terhadap program kita.

Kapan C++ ke Browser Masuk Akal #

Membawa C++ ke browser bukan gerakan untuk semua jenis aplikasi. Keputusan ini masuk akal ketika nilai utama program terletak pada komputasinya, bukan pada antarmukanya. Tiga pola pemakaian yang paling umum:

  • Porting library komputasi. Codec audio/video, kompresi, kriptografi, dan pemrosesan gambar adalah pekerjaan berat di CPU yang sudah lama ditulis dalam C++; kompilasi ke Wasm memakai kode itu di browser tanpa menulis ulang di JavaScript.
  • Game engine dan rendering. Game engine seperti Unity menyediakan target ekspor WebAssembly, sehingga sebagian besar logika engine identik dengan versi desktop dapat berjalan di browser.
  • Reuse kode lintas platform. Ketika satu produk memiliki klien desktop C++ dan klien web, logika inti seperti parser dan mesin perhitungan bisa menjadi satu source yang dibangun dua kali.

Sebaliknya, aplikasi yang antarmukanya sepenuhnya berada di DOM — form, dashboard, tampilan data — lebih alami ditulis langsung dengan JavaScript. Wasm bukan pengganti JavaScript; keduanya berdampingan, dan ada biaya komunikasi di batasnya, sehingga fungsi kecil yang dipanggil bergantian dari dua sisi bisa justru lebih lambat.

WebAssembly dalam Satu Halaman #

WebAssembly adalah format instruksi biner untuk sebuah mesin virtual berbasis stack yang dijalankan browser. Format ini dirancang sebagai target kompilasi portabel — compiler menerjemahkan C++ menjadi bytecode Wasm — dan dieksekusi di dalam sandbox dengan kecepatan mendekati kode native. Bagi browser, modul Wasm adalah pasangan kode dan linear memory: seluruh data program berada di satu blok memori yang ukurannya disepakati dan hanya bertambah bila diminta.

Artefak yang dikirim ke browser biasanya berupa pasangan berkas: .wasm berisi bytecode, sedangkan .js adalah glue code — kode perantara yang memuat modul dan menerjemahkan pemanggilan antara JavaScript dan Wasm. Karena itu, halaman web tetap berkomunikasi dengan program C++ tersebut lewat JavaScript.

Emscripten: Toolchain dari C++ ke Wasm #

Emscripten adalah toolchain standar industri untuk pekerjaan ini. Driver utamanya, emcc, berperilaku seperti pengganti g++: flag -std, -O2, dan -Wall dikenalinya, standard library C++ disediakan oleh toolchain, sehingga source yang ramah compiler GNU umumnya langsung dapat dikompilasi. Pemasangannya memakai emsdk:

bash Contoh — pemasangan Emscripten di mesin sendiri
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Lima perintah di atas mengikuti panduan resmi Getting Started: install mengunduh toolchain, activate memilih versi aktif, dan source memasukkan emcc ke PATH. Setelah itu, emcc dipakai seperti g++ dengan satu keputusan tambahan — bentuk keluaran:

Flag keluaranHasil yang diperoleh
-o hitung.htmlHalaman web lengkap: wasm + glue + halaman siap dibuka
-o hitung.jsGlue code saja — untuk dijalankan via Node atau disisipkan ke halaman
-o hitung.wasmBytecode murni tanpa glue — untuk integrasi manual

Untuk percobaan pertama, -o file.html paling cepat: buka hasilnya di browser dan program berjalan. Flag -O2 bekerja seperti pada Release Build — optimasi penting karena bytecode Wasm yang belum dioptimasi berukuran besar dan lambat.

Fungsi Perhitungan Murni sebagai Bahan Uji #

Kriteria kode yang paling layak dibawa ke Wasm sama dengan prasyarat cross-compilation: komputasi murni tanpa API OS. Program berikut memuat dua fungsi kecil — matematika murni (hitungFpb, algoritma Euclid) dan konversi unit audio (dbKeGain, desibel menjadi faktor gain). Keduanya ditandai extern "C" agar nama simbolnya tidak ter-mangle sehingga daftar ekspor di sisi Emscripten mudah ditulis. Kita bangun program ini dengan g++ di praktikum untuk memverifikasi logikanya; fungsi yang sama persis inilah yang nantinya dikompilasi emcc.

cpp
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>

// Dua fungsi komputasi murni: masukan lewat parameter, hasil lewat return.
// Tanpa I/O, tanpa variabel global, tanpa API OS — kandidat ideal untuk
// dibawa ke WebAssembly. Penanda extern "C" menjaga nama simbol tetap
// tidak ter-mangle sehingga daftar EXPORTED_FUNCTIONS emcc tetap sederhana,
// sedangkan g++ di praktikum tetap membangun source ini apa adanya.

extern "C" std::int64_t hitungFpb(std::int64_t a, std::int64_t b) {
    while (b != 0) {
        std::int64_t sisa = a % b;
        a = b;
        b = sisa;
    }
    return a;
}

extern "C" double dbKeGain(double db) {
    return std::pow(10.0, db / 20.0);
}

int main() {
    std::cout << "FPB(1071, 462) = " << hitungFpb(1071, 462) << "\n";

    for (double db : {-6.0, 0.0, 6.0}) {
        std::cout << std::defaultfloat << "Gain " << db << " dB = "
                  << std::fixed << std::setprecision(3) << dbKeGain(db) << "\n";
    }
    return 0;
}

Output yang Dihasilkan:

text
FPB(1071, 462) = 21
Gain -6 dB = 0.501
Gain 0 dB = 1.000
Gain 6 dB = 1.995

Mari kita telaah baris-baris yang menentukan:

  1. Baris 12 (extern "C" std::int64_t hitungFpb(...)): penanda extern "C" mematikan name mangling C++ untuk fungsi ini; simbolnya tetap bernama hitungFpb di binary, dan g++ tetap membangun source tanpa keluhan.
  2. Baris 13-18 (algoritma Euclid): loop modulo menghitung FPB tanpa alokasi memori dinamis sama sekali — pola yang ideal untuk linear memory Wasm yang ukurannya disepakati sejak awal.
  3. Baris 21-23 (dbKeGain): std::pow berasal dari standard library; Emscripten menyediakan implementasinya sebagai bagian dari sysroot-nya, sehingga source tidak perlu diubah.
  4. Baris 28-30 (loop cetak): manipulator defaultfloat dan fixed dipakai bergantian agar label desibel tampil bulat sementara gain tampil tiga desimal — format yang identik antara hasil g++ dan hasil Node nantinya.

Sesi emcc Ilustratif #

Sesi berikut mengompilasi hitung-wasm.cpp lalu menjalankan hasilnya di Node.js — runtime JavaScript luar browser yang mampu mengeksekusi modul Wasm dari terminal:

bash Sesi ilustratif — kompilasi dan uji di Node (tidak dijalankan di praktikum)
emcc -std=c++23 -O2 hitung-wasm.cpp -o hitung.js \
     -sEXPORTED_FUNCTIONS=_main,_hitungFpb,_dbKeGain \
     -sEXPORTED_RUNTIME_METHODS=ccall
ls hitung.*
node hitung.js

Bentuk keluaran yang diharapkan (ilustrasi — nama dan ukuran berkas bergantung pada versi toolchain):

text
hitung.js  hitung.wasm
FPB(1071, 462) = 21
Gain -6 dB = 0.501
Gain 0 dB = 1.000
Gain 6 dB = 1.995

Dua hal penting terjadi di sini. Pertama, emcc menghasilkan pasangan hitung.wasm + hitung.js — bytecode beserta glue code-nya; flag -sEXPORTED_FUNCTIONS mencegah optimizer membuang fungsi yang belum dipanggil. Kedua, keluaran Node identik dengan keluaran g++ di bagian sebelumnya: logika tidak berubah, yang berganti hanyalah mesin yang mengeksekusinya. Bila targetnya halaman web, ganti -o hitung.js menjadi -o hitung.html; fungsi yang diekspor dapat dipanggil dari JavaScript, antara lain lewat helper ccall.

Batasan Sandbox: Memori dan I/O #

Program C++ yang pindah ke browser menandatangani kontrak baru. Memori program berada di dalam linear memory Wasm — satu blok berukuran tetap (2 GB secara bawaan) yang hanya bertambah bila toolchain dikonfigurasi dengan ALLOW_MEMORY_GROWTH — dan pointer C++ tidak menunjuk keluar dari blok itu. Berkas tidak dibaca dari disk nyata: Emscripten menyediakan filesystem virtual (MEMFS) di dalam memori, dan berkas host ditanam ke dalamnya lewat flag --preload-file saat kompilasi. Jaringan tidak diakses lewat socket seperti pada chapter Network Programming; jalur keluarnya adalah API browser (fetch, WebSocket) lewat glue code.

Dengan toolchain yang tepat dan kode yang bersih dari API OS, browser menjadi target distribusi yang sah untuk komputasi C++. Selanjutnya kita kembali ke distribusi klasik: menyalurkan aplikasi ke pengguna desktop, dimulai dari Deployment di Linux.

Referensi: Getting Started — Emscripten Docs , WebAssembly — MDN Web Docs .