Emscripten และ npm

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

WebAssembly (wasm) มักถูก มองว่าเป็นทั้งองค์ประกอบพื้นฐานด้านประสิทธิภาพหรือวิธีเรียกใช้โค้ดเบส C++ ที่มีอยู่บนเว็บ เราต้องการแสดงให้เห็นว่า squoosh.app มีมุมมองที่ 3 สำหรับ wasm อย่างน้อย 1 มุมมอง นั่นคือการใช้ประโยชน์จากระบบนิเวศขนาดใหญ่ของภาษาโปรแกรมอื่นๆ เมื่อใช้ 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 อีกโมดูลหนึ่งและเป็นเพียงชิ้นงานอีกชิ้นหนึ่ง Bundler เช่น webpack หรือ rollup สามารถจัดการไฟล์ 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 บอก Docker ให้ลบคอนเทนเนอร์หลังจากที่ทำงานเสร็จแล้ว วิธีนี้จะช่วยให้คุณไม่ต้องสร้างคอลเล็กชันอิมเมจเครื่องที่ล้าสมัยเมื่อเวลาผ่านไป -v $(pwd):/src หมายความว่า คุณต้องการให้ Docker "มิเรอร์" ไดเรกทอรีปัจจุบัน ($(pwd)) ไปยัง /src ภายใน คอนเทนเนอร์ การเปลี่ยนแปลงใดๆ ที่คุณทำกับไฟล์ในไดเรกทอรี /src ภายใน คอนเทนเนอร์จะได้รับการทำซ้ำไปยังโปรเจ็กต์จริง โดยไดเรกทอรีที่มิเรอร์เหล่านี้ เรียกว่า "การเชื่อมโยงแบบ Bind"

มาดูรายละเอียดกัน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 ช่วยให้คุณกำหนดค่าตัวแปรสภาพแวดล้อม 2 ตัวได้ ซึ่งช่วยให้คุณส่งพารามิเตอร์บรรทัดคำสั่งเพิ่มเติมไปยังคอมไพเลอร์ C (CFLAGS), คอมไพเลอร์ C++ (CXXFLAGS) และลิงเกอร์ (LDFLAGS) ได้ พารามิเตอร์ทั้งหมดจะได้รับการตั้งค่าเครื่องมือเพิ่มประสิทธิภาพผ่าน OPTIMIZE เพื่อให้มั่นใจว่า ทุกอย่างได้รับการเพิ่มประสิทธิภาพในลักษณะเดียวกัน ค่าที่เป็นไปได้สำหรับตัวแปร OPTIMIZE มีอยู่ 2 ค่า ดังนี้

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

สำหรับเว็บ เราขอแนะนำ -Os เป็นหลัก

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

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

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

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

(ดูGist ที่มีไฟล์ทั้งหมดได้ที่นี่)

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

$ npm install
$ npm run build
$ npm run serve

การไปที่ localhost:8080 ควรแสดงเอาต์พุตต่อไปนี้ในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ

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

การเพิ่มโค้ด C/C++ เป็นการขึ้นต่อกัน

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

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

ติดตั้ง napa เป็นการอ้างอิงด้วยคำสั่งต่อไปนี้

$ 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 ...

(Gist ที่มีไฟล์ทั้งหมดอยู่ตรงนี้)

คำสั่ง 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 หากต้องการตรวจสอบว่าได้สร้างอิมเมจ 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",
    // ...
    },
    // ...
}

(Gist ที่มีไฟล์ทั้งหมดอยู่ตรงนี้)

การดำเนินการนี้จะสร้างอิมเมจ Docker แต่จะสร้างก็ต่อเมื่อยังไม่ได้สร้าง จากนั้น ทุกอย่างจะทำงานเหมือนเดิม แต่ตอนนี้สภาพแวดล้อมในการสร้างมีคำสั่ง doxygen ให้ใช้งานแล้ว ซึ่งจะทำให้มีการสร้างเอกสารประกอบของ libvpx ด้วย เช่นกัน

บทสรุป

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

ภาคผนวก: การใช้เลเยอร์อิมเมจ Docker

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

(Gist ที่มีไฟล์ทั้งหมดอยู่ตรงนี้)

โปรดทราบว่าคุณต้องติดตั้ง git และโคลน libvpx ด้วยตนเองเนื่องจากคุณไม่มี การเชื่อมโยงเมื่อเรียกใช้ docker build และผลพลอยได้คือคุณไม่จำเป็นต้องใช้ napa อีกต่อไป