Emscripten और npm

इस सेटअप में WebAssembly को कैसे इंटिग्रेट किया जा सकता है? इस लेख में, हम C/C++ और Emscripten के उदाहरण के साथ इसका हल निकालेंगे.

WebAssembly (vasm) को अक्सर परफ़ॉर्मेंस प्रिमिटिव के तौर पर या वेब पर आपके मौजूदा C++ कोडबेस को चलाने के तरीके के तौर पर फ़्रेम किया जाता है. squoosh.app की मदद से, हम यह बताना चाहते हैं कि Wasm का कम से कम एक तीसरा नज़रिया है: दूसरी प्रोग्रामिंग भाषाओं के बहुत बड़े ईकोसिस्टम का इस्तेमाल करना. Emscripten के साथ C/C++ कोड और Rest में Wasm की सहायता पहले से मौजूद है. साथ ही, Go की टीम भी इस पर काम कर रही है. मुझे यकीन है कि दूसरी भाषाएँ भी आएंगी.

इन मामलों में, Wasm आपके ऐप्लिकेशन का केंद्र बिंदु नहीं होता, बल्कि एक पहेली का हिस्सा होता है: बल्कि एक दूसरा मॉड्यूल होता है. आपके ऐप्लिकेशन में पहले से ही JavaScript, सीएसएस, इमेज एसेट, वेब पर आधारित बिल्ड सिस्टम, और शायद React जैसा फ़्रेमवर्क भी मौजूद हो सकता है. इस सेटअप में WebAssembly को इंटिग्रेट करने का तरीका क्या है? इस लेख में, हम C/C++ और Emscripten के उदाहरण के साथ इसका समाधान करने जा रहे हैं.

डॉकर

मैंने पाया है कि Emscripten के साथ काम करते समय Docker अहम है. C/C++ लाइब्रेरी को अक्सर उसी ऑपरेटिंग सिस्टम के साथ काम करने के लिए लिखा जाता है जिस पर वे पहले से बने हुए हैं. एक जैसा माहौल बनाए रखना बहुत ज़रूरी है. Docker में आपको एक वर्चुअल वर्शन वाला Linux सिस्टम मिलता है. यह पहले से ही Emscripten के साथ काम करने के लिए सेट अप किया गया है. इसमें सभी टूल और डिपेंडेंसी इंस्टॉल हैं. अगर कोई चीज़ मौजूद नहीं है, तो उसे इंस्टॉल करें. आपको इस बात की चिंता नहीं करनी होगी कि इससे आपकी मशीन या दूसरे प्रोजेक्ट पर क्या असर पड़ेगा. अगर कुछ गलत होता है, तो कंटेनर को बाहर फेंक दें और फिर से शुरू करें. अगर यह एक बार काम करता है, तो आप पक्का कर सकते हैं कि यह काम करता रहेगा और एक जैसे नतीजे देता रहेगा.

Docker Registry में, trzeci की बनाई हुई एक Emscripten इमेज है, जिसका इस्तेमाल मैं बहुत ज़्यादा करता/करती हूं.

एनपीएम के साथ इंटिग्रेशन

ज़्यादातर मामलों में, किसी वेब प्रोजेक्ट का एंट्री पॉइंट npm का package.json होता है. परंपरागत तरीके से, ज़्यादातर प्रोजेक्ट npm install && npm run build का इस्तेमाल करके बनाए जा सकते हैं.

आम तौर पर, Emscripten (.js और .wasm फ़ाइल) के बनाए गए बिल्ड आर्टफ़ैक्ट को, किसी दूसरे JavaScript मॉड्यूल को और सिर्फ़ दूसरी एसेट की तरह मानना चाहिए. JavaScript फ़ाइल को वेबपैक या रोलअप जैसे बंडलर से मैनेज किया जा सकता है. Wasm फ़ाइल को किसी दूसरी बड़ी बाइनरी ऐसेट की तरह ही माना जाना चाहिए, जैसे कि इमेज.

इसलिए, आपकी "सामान्य" बिल्ड प्रोसेस शुरू होने से पहले, Emscripten बिल्ड आर्टफ़ैक्ट बनाना ज़रूरी है:

{
    "name": "my-worldchanging-project",
    "scripts": {
    "build:emscripten": "docker run --rm -v $(pwd):/src trzeci/emscripten
./build.sh",
    "build:app": "<the old build command>",
    "build": "npm run build:emscripten && npm run build:app",
    // ...
    },
    // ...
}

build:emscripten नए टास्क में, सीधे Emscripten को शुरू किया जा सकता है. हालांकि, जैसा कि पहले बताया गया है, मेरा सुझाव है कि आप Docker का इस्तेमाल करें, ताकि यह पक्का किया जा सके कि बिल्ड एनवायरमेंट एक जैसा है.

docker run ... trzeci/emscripten ./build.sh, Docker को trzeci/emscripten इमेज का इस्तेमाल करके एक नया कंटेनर खोलने और ./build.sh कमांड चलाने के लिए कहता है. build.sh एक शेल स्क्रिप्ट है, जिसे आप आगे लिखेंगे! --rm डॉकर से कहता है कि उसके चलने के बाद कंटेनर को मिटा दिया जाए. इस तरह, समय के साथ मशीन की पुरानी इमेज का कलेक्शन नहीं बनेगा. -v $(pwd):/src का मतलब है कि आपको Docker, कंटेनर के अंदर /src की मौजूदा डायरेक्ट्री ($(pwd)) को "मिररिंग" करना है. अगर कंटेनर के अंदर /src डायरेक्ट्री की फ़ाइलों में कोई बदलाव किया जाता है, तो वह आपके असल प्रोजेक्ट की कॉपी बन जाएगा. मिरर की गई इन डायरेक्ट्री को "बाइंड माउंट" कहा जाता है.

आइए build.sh पर एक नज़र डालें:

#!/bin/bash

set -e

export OPTIMIZE="-Os"
export LDFLAGS="${OPTIMIZE}"
export CFLAGS="${OPTIMIZE}"
export CXXFLAGS="${OPTIMIZE}"

echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
(
    # Compile C/C++ code
    emcc \
    ${OPTIMIZE} \
    --bind \
    -s STRICT=1 \
    -s ALLOW_MEMORY_GROWTH=1 \
    -s MALLOC=emmalloc \
    -s MODULARIZE=1 \
    -s EXPORT_ES6=1 \
    -o ./my-module.js \
    src/my-module.cpp

    # Create output folder
    mkdir -p dist
    # Move artifacts
    mv my-module.{js,wasm} dist
)
echo "============================================="
echo "Compiling wasm bindings done"
echo "============================================="

यहां विचार करने के लिए बहुत कुछ है!

set -e, शेल को "फ़ेल फ़ास्ट" मोड में रखता है. अगर स्क्रिप्ट का कोई भी निर्देश गड़बड़ी दिखाता है, तो पूरी स्क्रिप्ट तुरंत रद्द हो जाती है. इससे बहुत मदद मिल सकती है, क्योंकि स्क्रिप्ट का आखिरी आउटपुट हमेशा सफलता का मैसेज या ऐसी गड़बड़ी होगी जिसकी वजह से बिल्ड फ़ेल हो गया.

export स्टेटमेंट की मदद से, कुछ एनवायरमेंट वैरिएबल की वैल्यू तय की जाती हैं. इनकी मदद से, C कंपाइलर (CFLAGS), C++ कंपाइलर (CXXFLAGS), और लिंकर (LDFLAGS) को अतिरिक्त कमांड लाइन पैरामीटर पास किए जा सकते हैं. इन सभी को OPTIMIZE के ज़रिए ऑप्टिमाइज़र सेटिंग मिलती हैं, ताकि यह पक्का किया जा सके कि सब कुछ एक ही तरह से ऑप्टिमाइज़ किया जाए. OPTIMIZE वैरिएबल के लिए कुछ वैल्यू हो सकती हैं:

  • -O0: कोई ऑप्टिमाइज़ेशन न करें. कोई भी अमान्य कोड नहीं हटेगा और Emscripten उससे मिलने वाले JavaScript कोड को भी छोटा नहीं करता. डीबग करने के लिए सही है.
  • -O3: बेहतर परफ़ॉर्मेंस के लिए, कैंपेन को बेहतर तरीके से ऑप्टिमाइज़ करें.
  • -Os: सेकंडरी शर्त के तौर पर, परफ़ॉर्मेंस और साइज़ के लिए बेहतर तरीके से ऑप्टिमाइज़ करें.
  • -Oz: साइज़ के लिए तेज़ी से ऑप्टिमाइज़ करें और ज़रूरत पड़ने पर परफ़ॉर्मेंस से बचें.

वेब के लिए, मैं ज़्यादातर -Os का सुझाव देता/देती हूं.

emcc कमांड में कई विकल्प हैं. ध्यान दें कि emcc को "GCC या clang जैसे कंपाइलर के लिए ड्रॉप-इन रिप्लेसमेंट" माना जाता है. इसलिए, GCC के जिन फ़्लैग के बारे में आपको पता होगा उन्हें emcc से भी लागू किया जाएगा. -s फ़्लैग इसलिए खास है, क्योंकि इसकी मदद से हम खास तौर पर Emscripten को कॉन्फ़िगर कर पाते हैं. सभी उपलब्ध विकल्प, Emscripten के settings.js में मिल सकते हैं, लेकिन वह फ़ाइल काफ़ी बड़ी हो सकती है. यह रही उन Emscripten फ़्लैग की सूची जो मेरे हिसाब से वेब डेवलपर के लिए सबसे ज़्यादा ज़रूरी हैं:

  • --bind, embind को चालू करता है.
  • -s STRICT=1, बिल्ड के उन सभी विकल्पों के साथ काम नहीं करता है जो अब काम नहीं करते. इससे यह पक्का होता है कि आपका कोड, फ़ॉरवर्ड करने के हिसाब से सही तरीके से बनता है.
  • ज़रूरत पड़ने पर, -s ALLOW_MEMORY_GROWTH=1 की मदद से मेमोरी अपने-आप बड़ी हो जाती है. लिखने के समय, Emscripten शुरुआत में 16 एमबी मेमोरी बांटेगा. आपके कोड से मेमोरी के अलग-अलग हिस्से तय होते हैं, इसलिए यह विकल्प तय करता है कि मेमोरी के खत्म हो जाने पर इन कार्रवाइयों की वजह से पूरा Wasm मॉड्यूल फ़ेल हो जाएगा या नहीं या ग्लू कोड को ऐलोकेशन को सही तरीके से दिखाने के लिए कुल मेमोरी बढ़ाने की अनुमति होगी या नहीं.
  • -s MALLOC=... चुनता है कि लागू किए गए किस malloc() का इस्तेमाल करना है. emmalloc, खास तौर पर Emscripten के लिए malloc() को लागू करने का एक छोटा और तेज़ तरीका है. विकल्प dlmalloc है, जो पूरी तरह से malloc() लागू करता है. आपको dlmalloc पर स्विच करने की ज़रूरत सिर्फ़ तब होगी, जब आपको बहुत सारे छोटे ऑब्जेक्ट बार-बार असाइन किए जा रहे हों या थ्रेड की सुविधा का इस्तेमाल करना हो.
  • -s EXPORT_ES6=1, JavaScript कोड को डिफ़ॉल्ट एक्सपोर्ट के साथ ES6 मॉड्यूल में बदल देगा, जो किसी भी बंडलर के साथ काम करता है. इसके लिए, -s MODULARIZE=1 को सेट करना भी ज़रूरी है.

नीचे दिए गए फ़्लैग हमेशा ज़रूरी नहीं होते या ये सिर्फ़ डीबग करने के कामों में मदद करते हैं:

  • -s FILESYSTEM=0, ऐसा फ़्लैग है जो Emscripten से जुड़ा होता है. जब आपका C/C++ कोड, फ़ाइल सिस्टम की कार्रवाइयों का इस्तेमाल करता है, तब यह आपके लिए किसी फ़ाइल सिस्टम को एम्युलेट कर सकता है. यह अपने इकट्ठा किए गए कोड का कुछ विश्लेषण करता है, ताकि यह तय किया जा सके कि ग्लू कोड में फ़ाइल सिस्टम एम्युलेशन को शामिल किया जाए या नहीं. हालांकि, कभी-कभी इस विश्लेषण में गलती हो सकती है. इस विश्लेषण से आपको एक ऐसे फ़ाइल सिस्टम के लिए 70kB का अतिरिक्त ग्लू कोड देना पड़ता है जिसकी शायद आपको ज़रूरत न हो. -s FILESYSTEM=0 का इस्तेमाल करके, Emscripten को हर हाल में इस कोड को शामिल न किया जा सकता है.
  • -g4 की मदद से, Emscripten में .wasm में डीबग करने की जानकारी शामिल हो जाएगी. साथ ही, Wasm मॉड्यूल के लिए सोर्स मैप फ़ाइल भी निकलेगी. Emscripten के साथ डीबग करने के बारे में ज़्यादा जानने के लिए, उनके डीबगिंग सेक्शन में जाएं.

और बस काम हो गया! इस सेटअप की जांच करने के लिए, आइए एक छोटा my-module.cpp बनाएं:

    #include <emscripten/bind.h>

    using namespace emscripten;

    int say_hello() {
      printf("Hello from your wasm module\n");
      return 0;
    }

    EMSCRIPTEN_BINDINGS(my_module) {
      function("sayHello", &say_hello);
    }

और एक index.html:

    <!doctype html>
    <title>Emscripten + npm example</title>
    Open the console to see the output from the wasm module.
    <script type="module">
    import wasmModule from "./my-module.js";

    const instance = wasmModule({
      onRuntimeInitialized() {
        instance.sayHello();
      }
    });
    </script>

(यहां सभी फ़ाइलों के बारे में जानकारी देने वाला gist है.)

सब कुछ बनाने के लिए, चलाएं

$ npm install
$ npm run build
$ npm run serve

localhost:8080 पर जाने से, आपको DevTool कंसोल में यह आउटपुट दिखेगा:

DevTools में C++ और Emscripten के ज़रिए प्रिंट किया गया मैसेज दिखाया गया है.

C/C++ कोड को डिपेंडेंसी के तौर पर जोड़ा जा रहा है

अगर आपको अपने वेब ऐप्लिकेशन के लिए C/C++ लाइब्रेरी बनानी है, तो अपने प्रोजेक्ट का हिस्सा बनने के लिए उसके कोड की ज़रूरत होगी. अपने प्रोजेक्ट के डेटा स्टोर करने की जगह में, मैन्युअल तरीके से कोड जोड़ा जा सकता है या इस तरह की डिपेंडेंसी मैनेज करने के लिए npm का इस्तेमाल भी किया जा सकता है. मान लें कि मुझे अपने वेब ऐप्लिकेशन में libvpx का इस्तेमाल करना है. .webm फ़ाइलों में इस्तेमाल किए जाने वाले कोडेक, VP8 वाली इमेज को कोड में बदलने के लिए, libvpx एक C++ लाइब्रेरी है. हालांकि, libvpx npm पर नहीं है और उसमें package.json नहीं है, इसलिए मैं उसे सीधे npm का इस्तेमाल करके इंस्टॉल नहीं कर सकता.

इस समस्या से बाहर निकलने के लिए, napa का इस्तेमाल किया जा सकता है. Snapa आपको अपने node_modules फ़ोल्डर में किसी भी git डेटा स्टोर करने की जगह के यूआरएल को डिपेंडेंसी के तौर पर इंस्टॉल करने की अनुमति देता है.

नैपा को डिपेंडेंसी के तौर पर इंस्टॉल करें:

$ npm install --save napa

और napa को इंस्टॉल स्क्रिप्ट के रूप में चलाना पक्का करें:

{
// ...
"scripts": {
    "install": "napa",
    // ...
},
"napa": {
    "libvpx": "git+https://github.com/webmproject/libvpx"
}
// ...
}

जब आप npm install चलाते हैं, तो Snapa आपके node_modules में libvpx नाम से libvpx GitHub डेटा स्टोर करने की जगह बनाता है.

अब बिल्ड स्क्रिप्ट को libvpx बनाने के लिए बढ़ाया जा सकता है. libvpx बनाने के लिए, configure और make का इस्तेमाल किया जाता है. अच्छी बात यह है कि Emscripten यह पक्का करने में मदद कर सकता है कि configure और make, Emscripten के कंपाइलर का इस्तेमाल करें. इस काम के लिए रैपर कमांड emconfigure और emmake हैं:

# ... above is unchanged ...
echo "============================================="
echo "Compiling libvpx"
echo "============================================="
(
    rm -rf build-vpx || true
    mkdir build-vpx
    cd build-vpx
    emconfigure ../node_modules/libvpx/configure \
    --target=generic-gnu
    emmake make
)
echo "============================================="
echo "Compiling libvpx done"
echo "============================================="

echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
# ... below is unchanged ...

C/C++ लाइब्रेरी दो हिस्सों में बंटी होती है: हेडर (आम तौर पर .h या .hpp फ़ाइलें) जो डेटा स्ट्रक्चर, क्लास, कॉन्सटेंट वगैरह के बारे में जानकारी देते हैं. लाइब्रेरी इन्हें दिखाती है. साथ ही, असल लाइब्रेरी (परंपरागत तौर पर .so या .a फ़ाइलें) भी होती हैं. अपने कोड में लाइब्रेरी के VPX_CODEC_ABI_VERSION कॉन्सटेंट का इस्तेमाल करने के लिए, आपको #include स्टेटमेंट का इस्तेमाल करके लाइब्रेरी की हेडर फ़ाइलें शामिल करनी होंगी:

#include "vpxenc.h"
#include <emscripten/bind.h>

int say_hello() {
    printf("Hello from your wasm module with libvpx %d\n", VPX_CODEC_ABI_VERSION);
    return 0;
}

समस्या यह है कि कंपाइलर को यह नहीं पता कि vpxenc.h को कहां खोजना है. -I फ़्लैग इसी काम के लिए है. यह कंपाइलर को बताता है कि हेडर फ़ाइलों की किन डायरेक्ट्री की जांच करनी है. इसके अलावा, आपको कंपाइलर को भी असल लाइब्रेरी फ़ाइल देनी होगी:

# ... above is unchanged ...
echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
(
    # Compile C/C++ code
    emcc \
    ${OPTIMIZE} \
    --bind \
    -s STRICT=1 \
    -s ALLOW_MEMORY_GROWTH=1 \
    -s ASSERTIONS=0 \
    -s MALLOC=emmalloc \
    -s MODULARIZE=1 \
    -s EXPORT_ES6=1 \
    -o ./my-module.js \
    -I ./node_modules/libvpx \
    src/my-module.cpp \
    build-vpx/libvpx.a

# ... below is unchanged ...

अगर npm run build को अभी चलाया जाता है, तो आपको दिखेगा कि यह प्रोसेस एक नई .js और नई .wasm फ़ाइल बनाती है. साथ ही, यह भी देखा जा सकता है कि डेमो पेज से वाकई यह नतीजा मिलता है:

DevTools
emscripten के ज़रिए प्रिंट किए गए libvpx का एबीआई वर्शन दिखाता है.

यह भी देखा जाएगा कि बिल्ड प्रोसेस में ज़्यादा समय लगता है. बिल्ड प्रोसेस होने में ज़्यादा समय लगने की वजहें अलग-अलग हो सकती हैं. libvpx के मामले में, इसे बहुत ज़्यादा समय लगता है, क्योंकि आपके बिल्ड निर्देश को चलाने पर VP8 और VP9, दोनों के लिए एन्कोडर और डिकोडर एक साथ इकट्ठा हो जाते हैं. भले ही, सोर्स फ़ाइलों में कोई बदलाव न हुआ हो. my-module.cpp में किए गए एक छोटे से बदलाव को भी बनने में ज़्यादा समय लगेगा. पहली बार में ही libvpx के बिल्ड आर्टफ़ैक्ट को बनाए रखने से काफ़ी फ़ायदा होगा.

एनवायरमेंट वैरिएबल का इस्तेमाल करके भी ऐसा किया जा सकता है.

# ... above is unchanged ...
eval $@

echo "============================================="
echo "Compiling libvpx"
echo "============================================="
test -n "$SKIP_LIBVPX" || (
    rm -rf build-vpx || true
    mkdir build-vpx
    cd build-vpx
    emconfigure ../node_modules/libvpx/configure \
    --target=generic-gnu
    emmake make
)
echo "============================================="
echo "Compiling libvpx done"
echo "============================================="
# ... below is unchanged ...

(सभी फ़ाइलों के बारे में यहां एक gist दिया गया है.)

eval कमांड की मदद से, हम बिल्ड स्क्रिप्ट में पैरामीटर पास करके एनवायरमेंट वैरिएबल सेट कर सकते हैं. अगर $SKIP_LIBVPX (किसी भी वैल्यू पर) सेट है, तो test कमांड, libvpx बनाना छोड़ देगा.

अब अपने मॉड्यूल को कंपाइल किया जा सकता है, लेकिन libvpx को फिर से बनाना स्किप किया जा सकता है:

$ npm run build:emscripten -- SKIP_LIBVPX=1

बिल्ड एनवायरमेंट को पसंद के मुताबिक बनाना

कभी-कभी लाइब्रेरी बनाने के लिए, अतिरिक्त टूल का इस्तेमाल करना पड़ता है. अगर Docker इमेज के बिल्ड एनवायरमेंट में ये डिपेंडेंसी मौजूद नहीं हैं, तो आपको इन्हें खुद जोड़ना होगा. उदाहरण के तौर पर, मान लें कि आपको doxygen का इस्तेमाल करके, libvpx का दस्तावेज़ भी बनाना है. Doxygen आपके Docker कंटेनर में उपलब्ध नहीं है, लेकिन apt का इस्तेमाल करके इसे इंस्टॉल किया जा सकता है.

अगर आपको अपने build.sh में ऐसा करना होता, तो हर बार अपनी लाइब्रेरी बनाने के लिए Doxygen को दोबारा डाउनलोड करके फिर से इंस्टॉल करें. यह न सिर्फ़ बहुत बेकार होगा, बल्कि यह आपको ऑफ़लाइन रहते हुए अपने प्रोजेक्ट पर काम करने से भी रोक देगा.

यहां अपनी Docker इमेज बनाने में कोई मतलब हो सकता है. Docker इमेज, एक Dockerfile लिखकर बनाई जाती हैं, जिसमें बिल्ड के तरीके की जानकारी होती है. Dockerफ़ाइलें काफ़ी असरदार हैं और इनमें कई कमांड हैं, लेकिन ज़्यादातर समय सिर्फ़ FROM, RUN, और ADD का इस्तेमाल करके, ऐसा किया जा सकता है. इस मामले में:

FROM trzeci/emscripten

RUN apt-get update && \
    apt-get install -qqy doxygen

FROM की मदद से, यह बताया जा सकता है कि शुरुआती पॉइंट के तौर पर, आपको किस Docker इमेज का इस्तेमाल करना है. मैंने trzeci/emscripten को आधार के रूप में चुना — जिस इमेज का आप हमेशा इस्तेमाल करते आ रहे हैं. RUN के साथ, आप Docker को कंटेनर के अंदर शेल कमांड चलाने का निर्देश देते हैं. इन निर्देशों से कंटेनर में जो भी बदलाव किए जाते हैं वे अब Docker इमेज का हिस्सा होते हैं. यह पक्का करने के लिए कि build.sh को चलाने से पहले आपकी Docker इमेज बनाई गई है और उपलब्ध है, आपको अपने package.json में थोड़ा बदलाव करना होगा:

{
    // ...
    "scripts": {
    "build:dockerimage": "docker image inspect -f '.' mydockerimage || docker build -t mydockerimage .",
    "build:emscripten": "docker run --rm -v $(pwd):/src mydockerimage ./build.sh",
    "build": "npm run build:dockerimage && npm run build:emscripten && npm run build:app",
    // ...
    },
    // ...
}

(सभी फ़ाइलों के बारे में यहां एक gist दिया गया है.)

इससे आपकी Docker इमेज बनेगी, लेकिन ऐसा तब होगा, जब इसे अब तक न बनाया गया हो. इसके बाद, सब कुछ पहले की तरह ही काम करता रहेगा, लेकिन अब बिल्ड एनवायरमेंट में doxygen कमांड उपलब्ध है. इससे libvpx का दस्तावेज़ भी बन जाएगा.

नतीजा

यह हैरानी की बात नहीं है कि C/C++ कोड और npm स्वाभाविक रूप से फ़िट नहीं होते, लेकिन आपके पास कुछ अतिरिक्त टूल और उन्हें Docker से मिलने वाले अलग-अलग टूल के साथ आसानी से काम करने का विकल्प होता है. यह सेटअप हर प्रोजेक्ट के लिए काम नहीं करेगा. हालांकि, यह एक ऐसा प्लैटफ़ॉर्म है जहां अपनी ज़रूरतों के हिसाब से बदलाव किए जा सकते हैं. अगर आपको कोई सुधार किया गया है, तो कृपया हमें बताएं.

अपेन्डिक्स: Docker इमेज लेयर का इस्तेमाल करना

इस समस्या का दूसरा हल है, Docker और Docker के स्मार्ट तरीके से कैश मेमोरी में सेव करने का तरीका. Docker, Dockerfiles को सिलसिलेवार तरीके से एक्ज़ीक्यूट करता है और हर चरण के नतीजे को अपनी एक इमेज असाइन करता है. इन इंटरमीडिएट इमेज को अक्सर "लेयर" कहा जाता है. अगर Dockerfile में कोई कमांड नहीं बदला है, तो Docker को फिर से बनाने के दौरान उस चरण को फिर से नहीं चलाया जाएगा. इसके बजाय, यह पिछली बार इमेज बनाए जाने के समय की लेयर का फिर से इस्तेमाल करता है.

पहले, हर बार अपना ऐप्लिकेशन बनाते समय libvpx को फिर से बनाने की कोशिश नहीं करनी पड़ती थी. इसकी जगह आप Docker की कैश मेमोरी का इस्तेमाल करने के लिए, libvpx के बिल्डिंग निर्देशों को build.sh से Dockerfile में ले जा सकते हैं:

FROM trzeci/emscripten

RUN apt-get update && \
    apt-get install -qqy doxygen git && \
    mkdir -p /opt/libvpx/build && \
    git clone https://github.com/webmproject/libvpx /opt/libvpx/src
RUN cd /opt/libvpx/build && \
    emconfigure ../src/configure --target=generic-gnu && \
    emmake make

(सभी फ़ाइलों के बारे में यहां एक gist दिया गया है.)

ध्यान दें कि आपको git और क्लोन libvpx को मैन्युअल तरीके से इंस्टॉल करना होगा, क्योंकि docker build चलाते समय आपके पास बाइंड माउंट नहीं होते. इसके बुरे असर के रूप में, नापा की कोई ज़रूरत नहीं है.