คุณจะผสานรวม WebAssembly เข้ากับการตั้งค่านี้ได้อย่างไร ในบทความนี้ เราจะพูดถึง C/C++ และ Emscripten เป็นตัวอย่าง
WebAssembly (wasm) มักได้รับการจัดให้เป็นแบบประสิทธิภาพพื้นฐานหรือวิธีเรียกใช้โค้ดเบส C++ ที่มีอยู่บนเว็บ เราต้องการแสดงให้เห็นว่ามีมุมมองอย่างน้อย 3 ด้านสำหรับ Wasm ด้วย squoosh.app ซึ่งก็คือการใช้ระบบนิเวศขนาดใหญ่ของภาษาโปรแกรมอื่นๆ เมื่อใช้ Emscripten คุณจะใช้โค้ด C/C++, Rust มีการสนับสนุน Wasm ในตัว และ ทีม Go ก็กำลังจัดการเรื่องนี้อยู่เช่นกัน ฉันมั่นใจว่ามีภาษาอื่นๆ อีกหลายภาษาที่จะตามมา
ในสถานการณ์เหล่านี้ Wasm ไม่ใช่หัวใจสำคัญของแอป แต่เป็นส่วนปริศนา ก็เป็นอีกโมดูลหนึ่ง แอปของคุณมี JavaScript, CSS, ชิ้นงานรูปภาพ, ระบบบิลด์ที่เน้นเว็บเป็นหลัก และแม้แต่เฟรมเวิร์กอย่าง React ด้วย คุณจะผสานรวม WebAssembly เข้ากับการตั้งค่านี้ได้อย่างไร ในบทความนี้เราจะพูดถึง C/C++ และ Emscripten เป็นตัวอย่าง
Docker
ผมพบว่า Docker มีคุณค่าอย่างมากเมื่อทำงานกับ Emscripten ไลบรารี C/C++ มักจะถูกเขียนขึ้นเพื่อทำงานกับระบบปฏิบัติการที่สร้างขึ้นมา การมีสภาพแวดล้อมที่สอดคล้องกันเป็นสิ่งที่เป็นประโยชน์มาก Docker จะมีระบบ Linux เสมือนจริงที่ตั้งค่าให้ทำงานกับ Emscripten พร้อมติดตั้งเครื่องมือและ Dependencies ทั้งหมดแล้ว หากมีอะไรหายไป คุณก็ติดตั้งได้โดยไม่ต้องกังวลว่าจะส่งผลกับเครื่องของคุณเองหรือโปรเจ็กต์อื่นๆ อย่างไร หากมีข้อผิดพลาด ให้ทิ้งคอนเทนเนอร์ไปและเริ่มใหม่ หากใช้งานได้เพียงครั้งเดียว คุณสามารถมั่นใจได้ว่ากิจกรรมดังกล่าวจะยังทำงานต่อไปและให้ผลลัพธ์ที่เหมือนกัน
Docker Registry มีอิมเมจ Emscripten โดย trzeci ที่ฉันใช้มาอย่างกว้างขวาง
การผสานรวมกับ npm
ในกรณีส่วนใหญ่ จุดแรกเข้าของโปรเจ็กต์เว็บคือ package.json
ของ npm โดยทั่วไปแล้ว โปรเจ็กต์ส่วนใหญ่สร้างได้ด้วย npm install &&
npm run build
โดยทั่วไปแล้ว อาร์ติแฟกต์บิลด์ที่สร้างโดย Emscripten (ไฟล์ .js
และไฟล์ .wasm
) ควรเป็นโมดูล JavaScript อีกรายการหนึ่งและเป็นเนื้อหาอีกรายการเท่านั้น ไฟล์ JavaScript สามารถจัดการโดย Bundler เช่น 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
จะบอกให้ Docker ลบคอนเทนเนอร์หลังจากทำงานเสร็จแล้ว วิธีนี้จะทำให้คุณไม่สะสมคอลเล็กชันรูปภาพเครื่อง
ที่ไม่มีอัปเดตเมื่อเวลาผ่านไป -v $(pwd):/src
หมายความว่าคุณต้องการให้ Docker "มิเรอร์" ไดเรกทอรีปัจจุบัน ($(pwd)
) ไปยัง /src
ในคอนเทนเนอร์ การเปลี่ยนแปลงที่คุณทำกับไฟล์ในไดเรกทอรี /src
ในคอนเทนเนอร์จะมิเรอร์กับโปรเจ็กต์จริง ไดเรกทอรีที่มิเรอร์เหล่านี้
เรียกว่า "bind mounts"
มาดู 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 เข้าสู่โหมด "Fail Fast" หากคำสั่งในสคริปต์แสดงผลข้อผิดพลาด สคริปต์ทั้งหมดจะถูกยกเลิกทันที ซึ่งจะเป็นประโยชน์อย่างยิ่งเนื่องจากเอาต์พุตล่าสุดของสคริปต์จะเป็นข้อความแสดงความสำเร็จหรือข้อผิดพลาดที่ทำให้บิลด์ล้มเหลวเสมอ
เมื่อใช้คำสั่ง export
คุณจะกำหนดค่าของตัวแปรสภาพแวดล้อม 2 รายการ ซึ่งช่วยให้คุณส่งผ่านพารามิเตอร์บรรทัดคำสั่งเพิ่มเติมไปยังคอมไพเลอร์ C (CFLAGS
), คอมไพเลอร์ C++ (CXXFLAGS
) และตัวลิงก์ (LDFLAGS
) ทั้งหมดนี้ได้รับการตั้งค่าเครื่องมือเพิ่มประสิทธิภาพผ่านทาง OPTIMIZE
เพื่อให้มั่นใจว่าทุกอย่างจะได้รับการเพิ่มประสิทธิภาพแบบเดียวกัน ค่าที่เป็นไปได้สำหรับตัวแปร OPTIMIZE
มีค่าต่อไปนี้
-O0
: ไม่ทำการเพิ่มประสิทธิภาพใดๆ ไม่มีการกำจัดโค้ดที่ใช้งานไม่ได้ และ Emscripten จะไม่ลดขนาดโค้ด JavaScript ที่ปล่อยออกมาเช่นกัน เหมาะสำหรับการแก้ไขข้อบกพร่อง-O3
: เพิ่มประสิทธิภาพเชิงรุก-Os
: เพิ่มประสิทธิภาพเชิงรุกเพื่อเพิ่มประสิทธิภาพและขนาดเป็นเกณฑ์รอง-Oz
: เพิ่มประสิทธิภาพในเชิงรุกสำหรับขนาด โดยลดประสิทธิภาพหากจำเป็น
สําหรับเว็บ ฉันส่วนใหญ่แนะนําให้ใช้ -Os
คำสั่ง emcc
มีตัวเลือกของตัวเองมากมาย โปรดทราบว่า emcc ถือเป็น "การแทนที่คอมไพเลอร์อย่าง GCC หรือ clang" ดังนั้น การแจ้งทั้งหมดที่คุณอาจทราบจาก GCC มักจะดำเนินการโดย emcc เช่นกัน แฟล็ก -s
มีความพิเศษตรงที่ช่วยให้เรากำหนดค่า Emscripten โดยเฉพาะได้ ดูตัวเลือกที่มีทั้งหมดได้ใน settings.js
ของ Emscripten แต่ไฟล์นี้อาจมากเกินไป นี่คือรายการแฟล็ก Emscripten ที่คิดว่าสำคัญที่สุดสำหรับนักพัฒนาเว็บ
--bind
จะเปิดใช้ embind-s STRICT=1
ลดการรองรับตัวเลือกบิลด์ทั้งหมดที่เลิกใช้งานแล้ว วิธีนี้ช่วยให้โค้ดของคุณสร้างในลักษณะที่เข้ากันได้แบบ Forward-s ALLOW_MEMORY_GROWTH=1
อนุญาตให้เพิ่มหน่วยความจำโดยอัตโนมัติหากจำเป็น เวลาที่เขียน Emscripten จะจัดสรรหน่วยความจำ 16 MB ในช่วงเริ่มต้น เนื่องจากโค้ดจัดสรรส่วนของหน่วยความจำ ตัวเลือกนี้จะตัดสินใจว่าการดำเนินการเหล่านี้จะทำให้โมดูล Wasm ทั้งหมดล้มเหลวเมื่อหน่วยความจำหมดหรือไม่ หรือหากโค้ด Glue ได้รับอนุญาตให้ขยายหน่วยความจำทั้งหมดเพื่อรองรับการจัดสรร-s MALLOC=...
เลือกการติดตั้งใช้งานmalloc()
emmalloc
เป็นการใช้งานmalloc()
ขนาดเล็กและรวดเร็วสำหรับ Emscripten โดยเฉพาะ อีกทางเลือกคือdlmalloc
ซึ่งเป็นการติดตั้งใช้งานmalloc()
อย่างเต็มรูปแบบ คุณเพียงแค่ต้องเปลี่ยนไปใช้dlmalloc
เท่านั้นหากจัดสรรออบเจ็กต์ขนาดเล็กจำนวนมากบ่อยหรือต้องการใช้การแยกชุดข้อความ-s EXPORT_ES6=1
จะเปลี่ยนโค้ด JavaScript เป็นโมดูล ES6 ที่มีการส่งออกเริ่มต้นที่ใช้งานกับ Bundler ใดก็ได้ ต้องตั้งค่า-s MODULARIZE=1
ด้วย
แฟล็กต่อไปนี้ไม่จำเป็นเสมอไปหรือมีประโยชน์สำหรับจุดประสงค์ในการแก้ไขข้อบกพร่องเท่านั้น
-s FILESYSTEM=0
เป็นแฟล็กที่เกี่ยวข้องกับ Emscripten ซึ่งจำลองระบบไฟล์ให้คุณได้เมื่อโค้ด C/C++ ใช้การดำเนินการของระบบไฟล์ โดยจะวิเคราะห์โค้ดที่คอมไพล์เพื่อตัดสินใจว่าจะรวมการจำลองระบบไฟล์ไว้ในโค้ด Glue Code หรือไม่ อย่างไรก็ตาม บางครั้งการวิเคราะห์นี้อาจผิดพลาดได้ และคุณต้องจ่ายค่าโค้ดกาวเพิ่มเติมถึง 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
เพิ่มโค้ด C/C++ เป็นทรัพยากร Dependency
หากต้องการสร้างไลบรารี C/C++ สำหรับเว็บแอป คุณต้องมีโค้ดของไลบรารีดังกล่าวเพื่อเป็นส่วนหนึ่งของโปรเจ็กต์ คุณเพิ่มโค้ดลงในที่เก็บของโปรเจ็กต์ด้วยตนเองได้ หรือจะใช้ npm เพื่อจัดการทรัพยากร Dependency เหล่านี้ได้เช่นกัน สมมติว่าผมต้องการใช้ libvpx ในเว็บแอป libvpx
เป็นไลบรารี C++ เพื่อเข้ารหัสรูปภาพด้วย VP8 ซึ่งเป็นตัวแปลงรหัสที่ใช้ใน .webm
ไฟล์
แต่ libvpx ไม่ได้อยู่ใน npm และไม่มี package.json
ก็เลยติดตั้งโดยใช้ npm โดยตรงไม่ได้
เพื่อออกจากปัญหานี้ เรามี napa อยู่ ซึ่ง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
ใหม่ และหน้าสาธิตจะแสดงค่าคงที่
คุณจะสังเกตเห็นว่าขั้นตอนการสร้างใช้เวลานาน เหตุผลสำหรับระยะเวลาในการสร้างที่ยาวนานอาจแตกต่างกันไป ในกรณีของ 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
การปรับแต่งสภาพแวดล้อมของบิลด์
บางครั้งไลบรารีต้องอาศัยเครื่องมือเพิ่มเติมในการสร้าง หากทรัพยากร Dependency เหล่านี้หายไปในสภาพแวดล้อมบิลด์ที่ได้จากอิมเมจ 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 เรียกใช้คำสั่ง Shell ภายในคอนเทนเนอร์ การเปลี่ยนแปลงคำสั่งเหล่านี้ในคอนเทนเนอร์จะกลายเป็นส่วนหนึ่งของอิมเมจ 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",
// ...
},
// ...
}
(นี่คือ 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 และ clone libvpx ด้วยตนเอง เนื่องจากคุณไม่มี Bind mounts เมื่อเรียกใช้ docker build
ผลข้างเคียงคือ ไม่จำเป็นต้องใช้ Napa อีกต่อไป