Mengenal WebAssembly Dengan C [EMSDK]

Pertamakali mendengar WebAsembly pada saat pertamakali berkontribusi sebagai penerjemah di MDN Web Doc sekitar 2 tahun lalu, dan sama sekali tidak tahu kalau webassembly berjalan di browser klien, tahunya kalau selain javascript pasti berjalan di server.

Setelah nonton demo webassembly googleio di youtube, baru tau kalau webassembly dijalankan di browser klien dengan menggunakan source native code c dan c++, tidak hanya dua bahasa tersebut bahasa lain masih dalam tahap implementasi agar bisa di compile menjadi file wasm (aka: webassembly module) dan ada juga yang sudah bisa digunakan untuk produksi.

Web Assembly Menggantikan Javascript.

Javascript sangat cepat setelah hadirnya V8 Engine atau biasa disebut V8, bahkan saat ini kita bisa menggunakan javascript untuk membuat aplikasi backend dan frontend baik web, desktop ataupun mobile. di web javascript juga sudah bisa berjalan tidak hanya single thread, sangat berterimakasih pada HTML 5 dengan adanya web worker.

Walaupun javascript cukup cepat, tapi kurang cepat untuk menjalankan komputasi yang lebih kompleks. Javascript adalah Interpreted Language yang bisa kita jalankan tanpa harus dikompile, yang juga berarti proses untuk menjalankannya perlu waktu, dari proses parse, compile sampai mesin bisa menjalankannya.

WebAssembly module (disingkat WASM) merupakan binary format untuk Virtual machine berbasis stack. WASM didesain sebagai target portable dari kompilasi bahasa pemrograman tingkat tinggi seperti c/c++, rust dan bahasa lainnya untuk dapat dijalankan baik di browser klien maupun di server. Dengan hadirnya webassembly banyak sekali fitur dan teknologi web yang bisa diptimalkan seperti yang kita tahu game web tidak begitu keren seperti di desktop. dengan adanya webassembly mungkin webgl ga akan kalah dengan opengl dan sejenisnya.

Walaupun Webassembly sangat cepat tapi tidak terlalu populer dari javascript saat ini dan web assembly membutuhkan javascript untuk dimuat dan berinteraksi dengan Browser atau bahkan WEB API. Jika WebAssembly menggatikan Javascript mungkin masa depan yang bicara, tapi mungkin akan sama halnya menjalankan native app tapi agak lambat sedikitnya sekitar 20% lebih lambat dari native klien.

Lalu kenapa kita harus nulis native app di web !!😠 untuk memuatnya sama saja dengan mendownload aplikasi desktop sampai ratusan mega (kalo game) dan untuk membukanya harus mendownload ulang setiap resoucenya. Kenapa ga nulis web sebagai native app!!.

Wow, Still working progress beroh!, mungkin nanti setiap browser akan meningkan kuota storage dan cache sizenya jadi lebih besar sehingga kita ga hanya bisa install aplikasi tapi juga install os di beroh..hhser 😆. Keuntungan dari menulis modul webassembly sendiri adalah hasilnya aplikasi multiplatform yang bisa dijalankan disemua environnment sistem operasi. tergantung browser yang dipakai udah bisa menjalankan webAssembly atau belum.

Bagaimana Caranya Membuat WebAssembly Module

Walaupun WebAssembly belum terlalu dewasa untuk digunakan dan sangat sulit memulai, tapi banyak sekali dokumentasi dan tutorial di web untuk memulai menulis WebAssembly pertama kamu.

Walaupun tidak begitu jago di c, nih ada hasil percobaan pertama menulis Webassembly. 😅 tapi mungkin tidak direkomendasikan untuk menjadikan referensi karena banyak hack agar yang penting jalan aja.

Kita akan mencoba menggunakan kode dari artikel lama untuk dikompile menjadi webAssembly menggunakan bahasa c. tapi sebelum kita memulai kita perlu menyiapkan alat-alatnya.

⚠️Peringatan : Untuk mendownload emsdk dibutuhkan kuota internet sekitar 1GB lebih, jadi pastikan kuota cukup untuk download atau isi ulang kuota anda. 😏

Kalau hanya ingin sekedar coba - coba silakan pake Webassembly Studio yang ga perlu ribet install sdknya. Tapi kode ini tidak akan berjalan disana karena kompilernya berbeda/tidak bisa menambahkan library emscripten sdk.

  1. Install SDK tool

    Untuk mengkompile c ke binari format kita memerlukan SDK tool emscripten. yang bisa kita install dari website webAssembly.

    Untuk versi windows mungkin kalian perlu menyetting path dan environment variabelnya secara manual jika file emsdk.bat dan emsdk_env.bat tidak berhasil mensetting secara otomatis. caranya dengan menjalankan file tersebut dan salin text yang ditampilkan ke sistem setting os kalian.

    Cara installya pasti udah tahu dari dokumentasi di websitenya.

  2. Nulis Kode

    Ok, disini kita tidak akan menjelaskan detail kode program c-nya, karena hanya menggunakan kembali kode program yang ada di artikel sebelumnya tentang algoritma queue di c++. jadi disini istilahnya memporting program yang udah ada aja 😅.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    #define MAX 20 //maksimum data queue
    #include <emscripten/emscripten.h>
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    //Deklarasi struct antrian
    struct Queue {
        int front, rear, data[MAX];
    }Q;
    
    //cek apakah antrian penuh
    bool EMSCRIPTEN_KEEPALIVE isFull() {
        return Q.rear == MAX;
    }
    
    //cek apakah antrian kosong
    bool EMSCRIPTEN_KEEPALIVE isEmpty() {
        return Q.rear == 0;
    }
    
    void EMSCRIPTEN_KEEPALIVE printQueue() {
        if (!isEmpty()){
            char msg[100];	
            strcat(msg,"QUEUE : ");
            for (int i = Q.front; i < Q.rear; i++){
            //menambahkan koma jika antrian lebih dari satu
                char str[20];
                sprintf(str, "%d", Q.data[i]);
                strcat(msg,str);
                strcat(msg,(Q.rear-1 == i) ? "" : ",");
            }
            printf("%s\n",msg);
            memset(msg,0,strlen(msg));
        }
        else{
            printf("Antrian kosong\n");
        }
    }
    
    void EMSCRIPTEN_KEEPALIVE enqueue(int data){
        if (!isFull()){
            Q.data[Q.rear] = data;
            //menempatkan tail pada elemen data terakhir yang ditambahkan
            Q.rear++;
            printQueue();
        }
        else {
            printf("Antrian penuh data tidak ditambahkan\n");
        }
    }
    
    // mengambil data dari antrian
    void EMSCRIPTEN_KEEPALIVE dequeue() {
        if (!isEmpty()){
            //menggeser antrian data ke head
            for (int i = Q.front; i < Q.rear; i++){
                Q.data[i] = Q.data[i + 1];
            //menempatkan tail pada data terakhir yang digeser
            }
            Q.rear--;
            printQueue();
        }
        else {
            printf("Antrian kosong data tidak dihapus\n");
        }
    }
    int main(int argc, char ** argv) {
        printQueue();
    }
    #ifdef __cplusplus
    }
    #endif

    🤕 Semoga ga terlalu kepanjangan atau kesini aja recomended. tapi tunggu dulu Souce kode ini yang akan kita kompile menjadi web assembly menggunakan bahasa c yang ga terlalu jauh bedaya dengan c++. Sekarang kita cari tau script tambahan dari library emscripten-nya.

    1. #include <emscripten/emscripten.h> sangat jelas header file yang di include menggunakan preprocessor untuk digunakan di program ini.

    2. Pada baris kode selanjutnya kita menemukan baris ini

      #ifdef __cplusplus
      extern "C" {
      #endif

      pada baris pertama dan terakhir dari snippet tersebut kita menggunakan preprocessor directive untuk mengatakan / memerintahkan kompiler untuk memasukkan code extern "C" { untuk di kompile jika kita menggunakan kompiler c++.

      Sementara itu fungsi dari code extern "C" { sendiri adalah untuk menghindari name mangling yang biasa digunakan oleh kompiler c++ untuk mengkompile kode C++.

      Kembali lagi ke souce lengkap kita di baris akhir kita juga menemukan directive

      #ifdef __cplusplus
      }
      #endif

      fungsinya hanya untuk menutup fungsi kode extern "C" { jika digunakan oleh kompiler.

      Jadi disini kita akan mengangkap semua variabel dan fungsi yang akan kita buat agar tidak mangling.

    3. Selanjunya kita akan menambahkan EMSCRIPTEN_KEEPALIVE sebelum nama fungsi untuk membuat fungsi tersebut bisa di jalankan berulang kali di halaman web kita setelah fungsi main() dijalankan.

ℹ Name mangling (Hanya di C++)

Name mangling adalah encoding dari nama fungsi dan variabel menjadi nama yang unik agar linker bisa membedakan nama yang umum yang ada di bahasa pemrogramman. Biasanya digunakan memfasilitasi fitur overloading dan visibilitas dalam lingkup(scope) yang berbeda

  1. Mengkompile dan menjalanakan program

    Kita sudah punya souce code yang akan kita kompile disini kita simpan file souce codenya dengan nama queue.c

    1. Buka terminal/promp di direktori file berisi kode diatas berada
    2. kompile menggunakan perintah

      emcc -o queue.js queue.c -O3 -s WASM=1 -s NO_EXIT_RUNTIME=1

      Emscripten bisa menghasilkan output html agar bisa langsung kita jalankan proframnya tapi disini kita akan menggunakan javascriptnya saja untuk output dan htmlnya kita buat sendiri

    Setelah kode di kompile kita mendapatkan file queue.wasm dan queue.js sebagai hasilnya. sekarang kita buat htmlnya.

    buat file index.html di direktori yang sama kemudian tambahkan script berikut di dalam tag body html.

    <div id="output" rows="8"></div>
    <button id="enqueue">enqueue</button> 
    <button id="dequeue">dequeue</button> 
    <script>
        var enqueue = document.getElementById('enqueue');
        var dequeue = document.getElementById('dequeue');
    
        enqueue.addEventListener('click', function(){
        var data = prompt("Tambahkan Data Queue :", "");
        _enqueue(data);
        });
    
        dequeue.addEventListener('click', function(){
        _dequeue();
        });
    
        (function () {
        var old = console.log;
        var logger = document.getElementById('output');
        console.log = function () {
        for (var i = 0; i < arguments.length; i++) {
            if (typeof arguments[i] == 'object') {
                logger.innerHTML = (JSON && JSON.stringify ? JSON.stringify(arguments[i], undefined, 2) : arguments[i]) + '<br />';
            } else {
                logger.innerHTML = arguments[i] + '<br />';
            }
        }
        }
        })();
    </script> 
    <script async type="text/javascript" src="queue.js"></script>
    1. Disini kita membuat 3 element html, yaitu 1 div output dan 2 button enqueue dan dequeue
    2. Disini kita juga menggunakan internal javascript dan external javascritp(dari hasil kompile). di internal scriptnya kita menambahkan eventListener pada kedua button untuk memanggil fungsi dari file queue.wasm hasil kompile tadi.
    3. Karena kita hanya membuat fungsi void di file souce code c tadi dan menampilkan teks semuanya menggunakan printf(), kita akan mengambil text log dari javascript console yang secara otomatis di tampilkan melalui hasil output file queue.js ke elemen div output html sebagai loggernya.

    Selesai, sekarang kalian bisa buka index.html di browser dan mencoba hasil program yang telah kita buat. Atau jalankan perintah emrun --no_browser --port 8080 . dan buka localhost:8080 di browser.

  2. Hasil Program

    Hasil program atau demo dari tutorial instant ini bisa dilihat di sini. 😅

Tutorial Selanjutnya

😢🏳️ Cukup satu ini dulu. mungkin nanti ada bahasa lain yang lebih mudah untuk menulis webAssembly atau ada web teknologi yang menarik nantinya yang bisa membawa webassembly.

Jika kamu mau belajar lebih banyak tentang web assembly bisa cek di FreeCodeCamp di medium atau ikuti tutorial An Introduction to Web Assembly, WebAssembly Physics and DOM objects dan tutorial webassembly lainnya di CodeLab

💬 Sumber Artikel Tentang WebAssembly

  1. WebAssembly | MDN

  2. Making WebAssembly even faster

  3. How JavaScript works: A comparison with WebAssembly

  4. On the fly WebP decoding using WASM and a Service Worker

  5. WebAssembly Rock : Topics

🎮 Demo WebAssembly

  1. WebAssembly Rock : Games
  2. 13 Games Built on WebAssembly
  3. Construct 3 online: Scirra
  4. Qt for WebAssembly – check out the examples!
  5. Tanks! Demo

Ada yang terlewatkan, tulis hasil porting atau module webAssembly buatanmu di komentar

#webAssembly#Javascript