Emscripten और npm

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

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

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

डॉकर

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

Docker Registry में एक Emscripten इमेज: trzeci का प्रॉडक्ट जिसे मैं बहुत ज़्यादा इस्तेमाल कर रहा हूं.

npm के साथ इंटिग्रेशन

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

आम तौर पर, Emscripten (.js और .wasm) के बनाए हुए बिल्ड आर्टफ़ैक्ट फ़ाइल) को किसी अन्य JavaScript मॉड्यूल के रूप में माना जाना चाहिए और ऐसेट. JavaScript फ़ाइल को webpack या Rollup जैसे बंडलर की मदद से मैनेज किया जा सकता है, और 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 का मतलब है कि तो डॉकर को "मिरर" बनाना है मौजूदा डायरेक्ट्री ($(pwd)) से /src के अंदर कंटेनर. इसमें /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 से पता है, उन्हें emcc से इस रूप में लागू किया जा सकता है: करते हैं. -s फ़्लैग इसलिए खास है, क्योंकि यह हमें Emscripten को कॉन्फ़िगर करने देता है खास तौर पर. सभी उपलब्ध विकल्प Emscripten's में मिल सकते हैं settings.js लेकिन फ़ाइल बहुत मुश्किल हो सकती है. यहां Mscripten फ़्लैग की सूची दी गई है जो मुझे लगता है कि वेब डेवलपर के लिए सबसे ज़रूरी हैं:

  • --bind चालू करता है एंबाइंड करें.
  • उन सभी बिल्ड विकल्पों के लिए -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 पर जाने से आपको यह आउटपुट दिखेगा DevTools कंसोल:

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

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

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

इस उलझन से बाहर निकलने के लिए, आपके पास नापा पर टैप करें. naa से आपको कोई भी git इंस्टॉल करने की सुविधा मिलती है आपके node_modules फ़ोल्डर में डिपेंडेंसी के तौर पर रिपॉज़िटरी का यूआरएल.

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

$ npm install --save napa

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

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

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

अब libvpx बनाने के लिए अपनी बिल्ड स्क्रिप्ट को बढ़ाया जा सकता है. libvpx configure का इस्तेमाल करता है और make बनाई जाने वाली हैं. अच्छी बात यह है कि Emscripten यह पक्का करने में मदद कर सकता है कि configure और make, एंस्क्रिप्टेन कंपाइलर का इस्तेमाल करता है. इस काम के लिए रैपर का इस्तेमाल किया जाता है निर्देश 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 ...

(यहां एक जानकारी दी गई है जिसमें सभी फ़ाइलें शामिल हैं.)

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

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

$ npm run build:emscripten -- SKIP_LIBVPX=1

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

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

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

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

FROM trzeci/emscripten

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

FROM की मदद से, यह बताया जा सकता है कि आपको किस Docker इमेज को 'शुरुआत' के तौर पर इस्तेमाल करना है अंक. मैंने trzeci/emscripten को आधार के तौर पर चुना है — आप जिस इमेज का इस्तेमाल कर रही हैं का इस्तेमाल भी किया जा सकता है. RUN का इस्तेमाल करके, आप Docker को शेल कमांड चलाने का निर्देश देते हैं. कंटेनर. इन निर्देशों से कंटेनर में जो भी बदलाव किए जाते हैं वे अब इसका हिस्सा हैं Docker इमेज. यह पक्का करने के लिए कि आपकी Docker इमेज बना दी गई है और build.sh को चलाने से पहले उपलब्ध है, तो आपको अपना 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",
    // ...
    },
    // ...
}

(यहां एक जानकारी दी गई है जिसमें सभी फ़ाइलें शामिल हैं.)

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

नतीजा

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

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

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

पहले, आपको हर बार libvpx को फिर से न बनाने के लिए कुछ मेहनत करनी पड़ती थी आपको अपना ऐप्लिकेशन बनाना है. इसके बजाय आप libvpx के लिए बिल्डिंग निर्देशों को स्थानांतरित कर सकते हैं Docker की कैश मेमोरी का इस्तेमाल करने के लिए, अपने 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

(यहां एक जानकारी दी गई है जिसमें सभी फ़ाइलें शामिल हैं.)

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