Emscripten และ npm

คุณจะผสานรวม WebAssembly ในการตั้งค่านี้ได้อย่างไร ในบทความนี้ เราจะใช้ C/C++ และ Emscripten เป็นตัวอย่าง

WebAssembly (WASM) มักถูกมองว่าเป็นพื้นฐานด้านประสิทธิภาพหรือวิธีเรียกใช้ฐานโค้ด C++ ที่มีอยู่บนเว็บ เมื่อใช้ squoosh.app เราต้องการแสดงให้เห็นว่า Wasm มีมุมมองที่ 3 เป็นอย่างน้อย นั่นคือการใช้ประโยชน์จากระบบนิเวศขนาดใหญ่ของภาษาโปรแกรมอื่นๆ เมื่อใช้ Emscripten คุณจะใช้โค้ด C/C++, Rust มีการรองรับ Wasm ในตัว และทีม Go กำลังดำเนินการอยู่ และเรามั่นใจว่าจะมีภาษาอื่นๆ ตามมาอีกมากมาย

ในกรณีเหล่านี้ wasm ไม่ใช่หัวใจหลักของแอป แต่เป็นชิ้นส่วนของปริศนาอีกชิ้นหนึ่ง แอปของคุณมี JavaScript, CSS, ชิ้นงานรูปภาพ, ระบบบิลด์ที่เน้นเว็บ และอาจรวมถึงเฟรมเวิร์กอย่าง React อยู่แล้ว คุณจะผสานรวม WebAssembly เข้ากับการตั้งค่านี้ได้อย่างไร ในบทความนี้ เราจะมาดูตัวอย่าง โดยใช้ C/C++ และ Emscripten

Docker

ฉันพบว่า Docker มีประโยชน์อย่างมากเมื่อทำงานกับ Emscripten ไลบรารี C/C++ มักเขียนขึ้นให้ทำงานร่วมกับระบบปฏิบัติการที่ใช้สร้าง การมีสภาพแวดล้อมที่สอดคล้องกันมีประโยชน์อย่างยิ่ง เมื่อใช้ Docker คุณจะได้รับระบบ Linux แบบเสมือนจริงที่ตั้งค่าให้ทำงานร่วมกับ Emscripten อยู่แล้ว รวมถึงมีเครื่องมือและไลบรารีที่ต้องพึ่งพาทั้งหมดติดตั้งไว้แล้ว หากมีบางอย่างขาดหายไป คุณสามารถติดตั้งได้โดยไม่ต้องกังวลว่าสิ่งเหล่านั้นจะส่งผลกระทบต่อเครื่องของคุณเองหรือโปรเจ็กต์อื่นๆ ของคุณ หากเกิดข้อผิดพลาด ให้ทิ้งคอนเทนเนอร์และเริ่มใหม่ หากได้ผลเพียงครั้งเดียว คุณก็มั่นใจได้ว่าเครื่องมือดังกล่าวจะยังคงทำงานต่อไปและให้ผลลัพธ์ที่เหมือนกัน

Docker Registry มีอิมเมจ Emscripten โดย trzeci ที่ฉันใช้มายาวนาน

การผสานรวมกับ npm

ในกรณีส่วนใหญ่ จุดแรกเข้าไปยังโปรเจ็กต์เว็บคือ package.json ของ npm ตามธรรมเนียมแล้ว โปรเจ็กต์ส่วนใหญ่จะสร้างด้วย npm install && npm run build ได้

โดยทั่วไปแล้ว ควรจัดการอาร์ติแฟกต์ของบิลด์ที่ Emscripten (ไฟล์ .js และ .wasm) เป็นเพียงโมดูล JavaScript อื่นและเป็นเพียงเนื้อหาอื่น ไฟล์ JavaScript สามารถจัดการโดย Bundler เช่น Webpack หรือภาพรวม และควรดำเนินการกับไฟล์ 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 จะสั่งให้ Docker ลบคอนเทนเนอร์หลังจากทำงานเสร็จแล้ว วิธีนี้จะช่วยป้องกันไม่ให้คุณมีคอลเล็กชันอิมเมจเครื่องที่ล้าสมัยเมื่อเวลาผ่านไป -v $(pwd):/src หมายความว่าคุณต้องการให้ Docker "มิเรอร์" ไดเรกทอรีปัจจุบัน ($(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 ทำให้ Shell เข้าสู่โหมด "ล้มเหลวอย่างรวดเร็ว" หากคําสั่งใดในสคริปต์แสดงข้อผิดพลาด ระบบจะยกเลิกสคริปต์ทั้งรายการทันที ซึ่งมีประโยชน์อย่างยิ่งเนื่องจากเอาต์พุตสุดท้ายของสคริปต์จะเป็นข้อความ "สำเร็จ" หรือข้อผิดพลาดที่ทำให้บิลด์ไม่สำเร็จเสมอ

คำสั่ง export ให้คุณกำหนดค่าของตัวแปรสภาพแวดล้อม 2 รายการ ซึ่งช่วยให้คุณส่งผ่านพารามิเตอร์บรรทัดคำสั่งเพิ่มเติมไปยังคอมไพเลอร์ C (CFLAGS) คอมไพเลอร์ C++ (CXXFLAGS) และ Linker (LDFLAGS) ได้ ทั้งหมดนี้จะได้รับการตั้งค่าเครื่องมือเพิ่มประสิทธิภาพผ่าน OPTIMIZE เพื่อให้มั่นใจว่าทุกอย่างจะได้รับการเพิ่มประสิทธิภาพแบบเดียวกัน ค่าที่เป็นไปได้สำหรับตัวแปร OPTIMIZE มี 2 ค่า ดังนี้

  • -O0: ห้ามเพิ่มประสิทธิภาพใดๆ ทั้งนี้จะไม่มีการนำโค้ดที่ใช้งานไม่ได้ออก และ Emscripten จะไม่ลดขนาดโค้ด JavaScript ที่ออกมาเช่นกัน เหมาะสำหรับการแก้ไขข้อบกพร่อง
  • -O3: เพิ่มประสิทธิภาพในเชิงรุก
  • -Os: เพิ่มประสิทธิภาพอย่างเต็มรูปแบบโดยให้ขนาดเป็นเกณฑ์รอง
  • -Oz: เพิ่มประสิทธิภาพในเชิงรุกในส่วนของขนาด โดยลดประสิทธิภาพหากจำเป็น

สำหรับเว็บ เราแนะนำให้ใช้ -Os เป็นส่วนใหญ่

คำสั่ง emcc มีตัวเลือกมากมายในตัวเอง โปรดทราบว่า emcc ควรทำหน้าที่เป็น "การแทนที่แบบดร็อปอินสำหรับคอมไพเลอร์ เช่น GCC หรือ clang" ดังนั้น Flag ทั้งหมดที่คุณอาจรู้จักจาก GCC ก็มีแนวโน้มที่ emcc จะใช้ด้วยเช่นกัน แฟล็ก -s มีความพิเศษตรงที่ช่วยให้เรากำหนดค่า Emscripten โดยเฉพาะได้ ตัวเลือกทั้งหมดที่ใช้ได้อยู่ใน settings.js ของ Emscripten แต่ไฟล์นั้นอาจดูน่าสับสน ต่อไปนี้คือรายการ Flag ของ Emscripten ที่ฉันคิดว่าสำคัญที่สุดสำหรับนักพัฒนาเว็บ

  • --bind enables embind
  • -s STRICT=1 หยุดรองรับตัวเลือกการสร้างที่เลิกใช้งานทั้งหมด วิธีนี้ช่วยให้มั่นใจว่าโค้ดของคุณจะสร้างในรูปแบบที่เข้ากันได้แบบไปข้างหน้า
  • -s ALLOW_MEMORY_GROWTH=1 อนุญาตให้เพิ่มหน่วยความจำโดยอัตโนมัติหากจําเป็น ณ เวลาที่เขียนบทความนี้ Emscripten จะจัดสรรหน่วยความจำ 16 MB ในเบื้องต้น เมื่อโค้ดจัดสรรกลุ่มหน่วยความจำ ตัวเลือกนี้จะกำหนดว่าการดำเนินการเหล่านี้จะทำให้โมดูล Wasm ทั้งโมดูลล้มเหลวเมื่อหน่วยความจำหมดหรือไม่ หรือมีการอนุญาตให้ Glue Code ขยายหน่วยความจำทั้งหมดเพื่อรองรับการจัดสรรหรือไม่
  • -s MALLOC=... จะเลือกการใช้งาน malloc() ที่จะใช้ emmalloc เป็นการใช้งาน malloc() ขนาดเล็กและรวดเร็วสำหรับ Emscripten โดยเฉพาะ อีกทางเลือกหนึ่งคือ dlmalloc ซึ่งเป็นการใช้งาน malloc() อย่างเต็มรูปแบบ คุณต้องเปลี่ยนไปใช้ dlmalloc ก็ต่อเมื่อจัดสรรออบเจ็กต์ขนาดเล็กจำนวนมากบ่อยครั้งหรือหากต้องการใช้ชุดข้อความ
  • -s EXPORT_ES6=1 จะเปลี่ยนโค้ด JavaScript เป็นโมดูล ES6 ด้วยการส่งออกเริ่มต้นที่ใช้งานได้กับ Bundler ใดก็ได้ และต้องตั้งค่า -s MODULARIZE=1

Flag ต่อไปนี้ไม่จําเป็นเสมอไปหรือมีประโยชน์สําหรับการแก้ไขข้อบกพร่องเท่านั้น

  • -s FILESYSTEM=0 เป็น Flag ที่เกี่ยวข้องกับ Emscripten และเป็นความสามารถในการจำลองระบบไฟล์ให้คุณเมื่อโค้ด C/C++ ใช้การดำเนินการของระบบไฟล์ โดยจะทำการวิเคราะห์บางอย่างในโค้ดที่คอมไพล์เพื่อตัดสินใจว่าจะรวมการจําลองไฟล์ระบบไว้ในโค้ด Glue หรือไม่ อย่างไรก็ตาม บางครั้งการวิเคราะห์นี้อาจทำให้เกิดความผิดพลาดได้ และบางครั้งคุณอาจจะต้องจ่ายเงินจำนวนมากถึง 70kB สำหรับ Glue Code เพิ่มเติมเพื่อจำลองระบบไฟล์ที่คุณอาจไม่จำเป็นต้องใช้ คุณจะบังคับให้ Emscripten ไม่รวมรหัสนี้ได้ด้วย -s FILESYSTEM=0
  • -g4 จะทำให้ Emscripten รวมข้อมูลการแก้ไขข้อบกพร่องไว้ใน .wasm และยังสร้างไฟล์ Source Map สำหรับโมดูล 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>

(ต่อไปนี้คือส่วนสำคัญที่มีไฟล์ทั้งหมด)

หากต้องการสร้างทุกอย่าง ให้เรียกใช้

$ npm install
$ npm run build
$ npm run serve

การไปยัง localhost:8080 ควรแสดงเอาต์พุตต่อไปนี้ในคอนโซล DevTools

เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์แสดงข้อความที่พิมพ์ผ่าน C++ และ Emscripten

เพิ่มโค้ด C/C++ เป็นทรัพยากร Dependency

หากต้องการสร้างไลบรารี C/C++ สําหรับเว็บแอป คุณต้องใส่โค้ดของไลบรารีนั้นไว้ในโปรเจ็กต์ คุณอาจเพิ่มโค้ดลงในที่เก็บของโปรเจ็กต์ด้วยตนเอง หรือจะใช้ npm เพื่อจัดการทรัพยากร Dependency เหล่านี้ก็ได้เช่นกัน สมมติว่าผม ต้องการใช้ libvpx ในเว็บแอป ส่วน libvpx เป็นไลบรารี C++ เพื่อเข้ารหัสรูปภาพด้วย VP8 ซึ่งเป็นตัวแปลงรหัสที่ใช้ในไฟล์ .webm อย่างไรก็ตาม libvpx ไม่ได้อยู่ใน npm และไม่มี package.json เราจึงติดตั้งโดยใช้ npm โดยตรงไม่ได้

ทางออกของปัญหานี้ก็คือ napa ซึ่งช่วยให้คุณติดตั้ง URL ของที่เก็บ Git ใดก็ได้เป็นข้อกำหนดไว้ในโฟลเดอร์ node_modules

ติดตั้ง Napa เป็นทรัพยากร Dependency

$ npm install --save napa

และตรวจสอบว่าได้เรียกใช้ napa เป็นสคริปต์การติดตั้ง

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

เมื่อเรียกใช้ npm install แล้ว Napa จะดูแลการโคลนที่เก็บ libvpx GitHub ลงใน node_modules ในชื่อ libvpx

ตอนนี้คุณสามารถขยายสคริปต์บิลด์เพื่อสร้าง libvpx ได้แล้ว libvpx จะใช้ configure และ make ในการสร้าง โชคดีที่ Emscripten ช่วยให้ configure และ make ใช้คอมไพเลอร์ของ Emscripten ได้ คำสั่ง Wrapper 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++ จะแบ่งออกเป็น 2 ส่วน ได้แก่ ส่วนหัว (ไฟล์ .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 ที่แสดงเวอร์ชัน ABI ของ libvpx ที่พิมพ์ผ่าน emscripten

นอกจากนี้ คุณจะเห็นว่ากระบวนการสร้างใช้เวลานาน สาเหตุของเวลา การสร้างที่นานอาจแตกต่างกันไป ในกรณีของ 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 มีให้ คุณจะต้องเพิ่มทรัพยากรเหล่านั้นด้วยตนเอง ตัวอย่างเช่น สมมติว่าคุณต้องการสร้างเอกสารประกอบ libvpx โดยใช้ doxygen Doxygen ไม่พร้อมใช้งานภายในคอนเทนเนอร์ Docker แต่คุณติดตั้งได้โดยใช้ apt

หากดำเนินการดังกล่าวใน build.sh คุณจะต้องดาวน์โหลด Doxygen และติดตั้งใหม่ทุกครั้งที่สร้างไลบรารี วิธีนี้ไม่เพียงจะเป็นการเสียเปล่า แต่ยังทำให้คุณทำงานในโปรเจ็กต์ขณะออฟไลน์ได้ด้วย

ในกรณีนี้ คุณควรสร้างอิมเมจ 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 คุณต้องปรับ package.json เล็กน้อยเพื่อให้แน่ใจว่าระบบได้สร้างและทำให้รูปภาพ Docker พร้อมใช้งานแล้วก่อนเรียกใช้ build.sh โดยทำดังนี้

{
    // ...
    "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 จะเรียกใช้ไฟล์ Docker แบบทีละขั้นตอนและกำหนดผลลัพธ์ของแต่ละขั้นตอนเป็นอิมเมจของตนเอง รูปภาพตรงกลางเหล่านี้ มักเรียกว่า "เลเยอร์" หากคำสั่งใน Dockerfile ไม่เปลี่ยนแปลง Docker จะไม่เรียกใช้ขั้นตอนนั้นซ้ำเมื่อคุณสร้าง Dockerfile ใหม่ แต่จะใช้เลเยอร์จากครั้งที่แล้วที่สร้างรูปภาพซ้ำแทน

ก่อนหน้านี้ คุณต้องใช้ความพยายามบางอย่างเพื่อไม่ให้ต้องสร้าง libvpx ใหม่ทุกครั้งที่สร้างแอป แต่ตอนนี้คุณสามารถย้ายวิธีการสร้าง libvpx จาก build.sh ไปยัง Dockerfile เพื่อใช้ประโยชน์จากกลไกการแคชของ Docker แทนได้ โดยทำดังนี้

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 และ clone libvpx ด้วยตนเองเนื่องจากไม่มีการต่อเชื่อมแบบผูกเมื่อเรียกใช้ docker build คุณไม่จำเป็นต้องใช้ Napa อีกต่อไป