本常見問題解答包含在 IRC 和郵件列表上提出的許多問題的答案。
請參閱 Emscripten 教學 和 emcc。
Emscripten 測試套件 中的所有測試都已知在我們的測試基礎架構上建置並通過,因此如果您在本地看到失敗,則很可能是您的環境存在問題。(很少有臨時中斷,但永遠不會在已標記的發布版本上。)
首先呼叫 emcc --check
,它會執行基本健全性檢查並印出有用的環境資訊。如果這沒有幫助,請按照 驗證 Emscripten 開發環境 中的說明進行操作。
您可能還想再次瀏覽 Emscripten 教學,因為它會隨著 Emscripten 的變更而更新。
另請確保您已具備執行 Emscripten 所需的要求,如 SDK 區段中所指定,包括依賴項的足夠新版本。
一些可能有助於找出問題的通用步驟
看看是否在沒有最佳化的情況下發生問題(-O0,或未指定任何最佳化層級)。在沒有最佳化的情況下,emscripten 會在編譯和執行階段啟用許多斷言,這可能會捕獲問題並顯示錯誤訊息,其中包含有關如何修復它的建議。
在本網站上搜尋文件。
檢查 Emscripten 測試套件 中是否有失敗功能的測試(在 test/ 中執行
grep -r
)。它們都應通過(只有極少數例外),因此它們提供了如何使用各種選項和程式碼的具體「已知良好」範例。
在大多數情況下,您將能夠將專案目前的建置系統與 Emscripten 一起使用。請參閱 建置專案。
Emscripten 做出了一些權衡,使得產生的程式碼更快、更小,但代價是連結時間更長。例如,我們使用 -flto(連結時間最佳化)建置標準程式庫的部分內容,這會啟用一些額外的最佳化,但可能需要更長的時間才能建置。我們也會(在最佳化的建置中)即使沒有 LTO,也會在整個輸出上執行 Binaryen 最佳化工具。
注意
您可以透過在環境中編譯 EMCC_DEBUG=1
,然後檢閱除錯日誌(預設在 /tmp/emscripten_temp
中)來判斷哪個編譯步驟花費的時間最長。請注意,在除錯模式下編譯比正常情況下需要更長的時間,因為我們會在磁碟上印出許多中間步驟,因此它適用於除錯,但不適用於實際編譯。
改善建置時間的主要提示是
使用 -O0
進行快速疊代建置。您仍然可以使用較高的最佳化層級進行編譯,但在連結期間指定 -O0
將使連結步驟更快。
在具有更多核心的機器上編譯
對於編譯您的原始檔,請使用並行建置系統(例如,在 make
中,您可以執行類似 make -j8
的操作來使用 8 個核心執行)。
對於連結步驟,Emscripten 可以並行執行一些最佳化(具體來說,用於 Wasm 的 Binaryen 最佳化和我們的 JavaScript 最佳化)。增加核心數量會產生幾乎線性的改善。Emscripten 將在有更多核心可用時自動使用更多核心,但您可以使用環境中的 EMCC_CORES=N
來控制它(如果您有很多核心但相對較少的記憶體,這會很有用)。
請確保透過使用 -O2
進行建置來最佳化程式碼(可以使用更多積極的最佳化,但代價是編譯時間顯著增加)。
請確保使用 -O3
或 -Os
進行建置,以便程式碼完全最佳化和最小化。您應該在您的網路伺服器上使用 Closure Compiler、gzip 壓縮等,請參閱最佳化程式碼中關於程式碼大小的章節。
請確保您使用的是 Emscripten 捆綁的系統標頭。預設情況下,使用 emcc 會這樣做,但如果您使用本地系統標頭搭配 emcc
,則可能會發生問題。
請確保您正在執行最佳化的建置(較小的建置啟動速度更快)。
網路延遲也是啟動時間的一個可能因素。請考慮將檔案載入程式碼放在與產生的程式碼不同的腳本元素中,以便瀏覽器可以與啟動程式碼庫並行開始網路下載(執行檔案打包器並將檔案載入程式碼放在一個腳本元素中,然後將產生的程式碼庫放在後來的腳本元素中)。
當使用 file://
URL 載入頁面時可能會發生該錯誤,該 URL 在某些瀏覽器中有效,但在其他瀏覽器中無效。相反,最好使用本地網路伺服器。例如,Python 有一個內建的伺服器,Python 3 中為 python -m http.server
,Python 2 中為 python -m SimpleHTTPServer
。執行此操作後,您可以訪問 https://127.0.0.1:8000/
。您也可以使用 emrun FILENAME.html
(它會為您執行一個 python 網路伺服器)。
當進行快速的本地測試時,除了本地網頁伺服器之外,另一種選擇是使用 -sSINGLE_FILE
將所有內容打包成單一檔案(這樣就不會向 file://
URL 發出 XHR 請求)。
否則,要偵錯此問題,請查看網頁本身或瀏覽器開發人員工具(網頁控制台和網路標籤)或您的網頁伺服器日誌中報告的錯誤。
machine type must be wasm32
或 unknown file type
的錯誤?¶這表示其中一個或多個連結器輸入檔案不是由 Emscripten 建置的(或者更具體地說,不是為正確的目標架構建置的)。
通常,有問題的檔案會是為本機建置的 ELF 檔案或 Mach-O 檔案。您可以執行 file
命令列工具來查看它們實際包含的內容。
常見的問題是:
嘗試連結針對主機系統建置的程式庫。例如,如果您的連結命令中有類似 -L/usr/lib
的內容,則幾乎總是會導致這些錯誤,因為那些系統目錄中存在的程式庫幾乎可以肯定不是使用/為 Emscripten 建置的。解決方案是使用 Emscripten 建置您所依賴的所有程式庫,並且永遠不要使用主機程式庫。
您專案中的某些程式庫或物件檔案是使用主機編譯器而不是 emscripten 編譯器建置的。如果您使用 autoconf 或 cmake,請確保使用 emconfigure/emmake 包裝器,請參閱 建置專案。
來自舊後端的 LLVM IR,如果您在 1.39.0 之前的版本(預設使用舊後端)建置專案,並且現在正在執行增量重建。要解決此問題,請從頭開始完整重建專案的所有檔案,包括程式庫(如果您有來自第三方的預建程式庫,則通常會發生此錯誤;這些程式庫也必須使用新後端重新編譯)。
{"text":"asm"}
)的錯誤訊息?¶Emscripten 無法編譯內嵌組譯碼(除非該組譯碼是專門針對 WebAssembly 編寫的)。
您需要找到使用內嵌組譯碼的地方,並停用它或將其替換為與平台無關的程式碼。
瀏覽器事件模型使用協作式多工處理 — 每個事件都有一個執行的「回合」,然後必須將控制權返回給瀏覽器事件迴圈,以便可以處理其他事件。HTML 頁面停滯的常見原因是 JavaScript 沒有完成並且沒有將控制權返回給瀏覽器。
圖形 C++ 應用程式通常有一個無限的主迴圈,在其中執行事件處理、處理和渲染,然後延遲以保持正確的畫面播放速率(SDL 應用程式中的 SDL_DELAY
)。由於主迴圈不會完成(是無限的),因此它無法將控制權返回給瀏覽器,並且應用程式將停滯。
使用無限主迴圈的應用程式應重新編碼,以將迴圈單次迭代的動作放入單個「有限」函數中。在本機建置中,此函數可以像以前一樣在無限迴圈中執行。在 Emscripten 建置中,它會設定為主迴圈函數,並且將由瀏覽器以指定的頻率呼叫。
有關此主題的更多資訊,請參閱Emscripten 執行環境。
要重複執行 C 函數,請使用 emscripten_set_main_loop()
(這在Emscripten 執行環境中有討論)。emscripten.h 中的相關函數也很有用,可讓您加入會封鎖主迴圈的事件等等。
要回應瀏覽器事件,請以正常方式使用 SDL API。在 SDL 測試中 (在 test/runner.py 中搜尋 SDL) 有範例。
另請參閱:為什麼我的 HTML 應用程式會停滯?
如需運作範例,請參閱 SDL 自動測試:test/runner.py browser
。
當您編譯時,Emscripten 中包含的系統程式庫會自動連結(僅連結必要的部分)。這包括 *libc*、*libc++* (C++ 標準程式庫) 和 SDL。
未包含在 Emscripten 中的程式庫(如 Boost)必須像專案中的模組一樣,使用程式編譯和連結。
有一組移植到 Emscripten 以方便使用的程式庫,Emscripten Ports。請參閱 建置專案。
另一個選項是將需要的 C API 實作為 JavaScript 程式庫(請參閱 emcc 中的 --js-library
和在 JavaScript 中實作 C API)。Emscripten 本身也針對 *libc* (不包括 *malloc*)和 SDL (但不包括 *libc++* 或 *malloc*) 執行此操作。
注意
與其他編譯器不同,您不需要使用 -lSDL
來包含 SDL(指定它不會造成任何損害)。
就 *Boost* 的特定情況而言,如果您只需要 boost 標頭,則無需編譯任何內容。
Emscripten 部分支援 SDL1 和 2 音訊以及 OpenAL。
要使用 SDL1 音訊,請將其包含為 #include <SDL/SDL_mixer.h>
。您可以將其與 SDL1、SDL2 或另一個用於平台整合的程式庫一起使用。
要使用 SDL2 音訊,請將其包含為 #include <SDL2/SDL_mixer.h>
並使用 -sUSE_SDL_MIXER=2。格式支援目前僅限於 OGG、WAV、MID 和 MOD。
Emscripten 使用虛擬檔案系統,可以預先載入資料或連結到 URL 以進行延遲載入。如需更多詳細資訊,請參閱檔案系統概述。
在瀏覽器中執行的 Emscripten 產生程式碼無法存取本機檔案系統中的檔案。相反地,您可以使用 預先載入 和 嵌入 來解決缺乏同步檔案 IO 的問題。如需更多資訊,請參閱 檔案系統概述。
可以允許存取在 node.js 中執行的程式碼的本機檔案系統,請使用 NODEFS 檔案系統選項。
(如果您看到錯誤訊息,例如 native function `x` called before runtime initialization
,這是 ASSERTIONS
建置中啟用的檢查,您可能需要此答案。)
如果函數依賴可能不存在的檔案,則在頁面完全載入之前呼叫已編譯的函數可能會導致錯誤(例如,預先載入的檔案會非同步載入,因此,如果您只是在 --post-js
中放置一些呼叫已編譯程式碼的 JS,則該程式碼會在組合的 JS 檔案末尾同步呼叫,這可能會在非同步事件發生之前,這是不好的做法)。
找出載入何時完成的最簡單方法是加入 main()
函數,並在其中呼叫 JavaScript 函數以通知您的程式碼載入已完成。
注意
當啟動完成後,會呼叫 main()
函數,表示呼叫任何已編譯的方法都是安全的。
例如,如果 allReady()
是您希望在一切準備就緒時呼叫的 JavaScript 函數,您可以執行
#include <emscripten.h>
int main() {
EM_ASM( allReady() );
}
另一個選項是定義 onRuntimeInitialized
函數,
Module['onRuntimeInitialized'] = function() { ... };
當執行階段準備就緒且可以呼叫已編譯的程式碼時,就會呼叫該方法。實際上,這與呼叫 main()
的時間完全相同,因此 onRuntimeInitialized
不會讓您執行任何新操作,但您可以從執行階段的 JavaScript 中以彈性的方式設定它。
以下是如何使用它的範例
<script type="text/javascript">
var Module = {
onRuntimeInitialized: function() {
Module._foobar(); // foobar was exported
}
};
</script>
<script type="text/javascript" src="my_project.js"></script>
關鍵在於,在載入包含 emscripten 輸出的指令碼(在此範例中為 my_project.js
)之前,Module
存在,並且具有屬性 onRuntimeInitialized
。
另一個選項是使用 MODULARIZE
選項,使用 -sMODULARIZE
。這會將所有產生的 JavaScript 放入工廠函數,您可以使用該函數建立模組的執行個體。工廠函數會傳回一個 Promise,該 Promise 會使用模組執行個體解析。在可以安全地呼叫已編譯的程式碼之後,即在下載並具現化已編譯的程式碼之後,就會解析 Promise。例如,如果您使用 -sMODULARIZE -s 'EXPORT_NAME="createMyModule"'
建置,則可以執行以下操作
createMyModule(/* optional default settings */).then(function(Module) {
// this is reached when everything is ready, and you can call methods on Module
});
請注意,在 MODULARIZE
模式下,我們不會尋找全域的 Module 物件來取得預設值。預設值必須作為參數傳遞給工廠函式。(詳情請參閱 settings.js)
atexit()
不會執行?¶(如果您看到類似 atexit() called, but EXIT_RUNTIME is not set
或 stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1
的錯誤訊息,您可能需要這個答案。)
預設情況下,Emscripten 設定 EXIT_RUNTIME=0
,這表示我們不會包含關閉執行階段的程式碼。這表示當 main()
退出時,我們不會刷新 stdio 串流,也不會呼叫全域 C++ 物件的解構子,或呼叫 atexit
回呼。這讓我們能夠預設發出更小的程式碼,而且這通常是您在網路上想要的:即使 main()
已經退出,您可能還有一些稍後想要執行的非同步事件。
但在某些情況下,您可能想要更像「命令列」的體驗,也就是當 main()
退出時,我們會關閉執行階段。您可以使用 -sEXIT_RUNTIME
進行建置,然後我們將呼叫 atexits
等等。當您使用 ASSERTIONS
進行建置時,當您需要這個選項時,應該會收到警告。例如,如果您的程式在沒有換行符號的情況下印出某些內容,
#include <stdio.h>
int main() {
printf("hello"); // note no newline
}
如果我們不關閉執行階段並刷新 stdio 串流,則不會印出「hello」。在 ASSERTIONS
建置中,您會收到通知,指出 stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1
。
Emscripten 會刪除未從已編譯程式碼呼叫的函式中的無用程式碼。雖然這樣可以最小化程式碼大小,但它可能會移除您打算自行呼叫的函式(在已編譯程式碼之外)。
為了確保可以從一般的 JavaScript 呼叫 C 函式,必須使用 emcc 命令列將其新增至 EXPORTED_FUNCTIONS。例如,為了避免移除/重新命名函式 my_func()
和 main()
,請使用以下方式執行 emcc:
emcc -sEXPORTED_FUNCTIONS=_main,_my_func ...
注意
如果您的程式碼中有 main() 函式,則 _main 應在匯出清單中,如同範例所示。否則,它會被當作無用程式碼移除;預設沒有特殊邏輯可以讓 main() 保持存活。
注意
EXPORTED_FUNCTIONS 會影響編譯成 JavaScript。如果您先編譯成物件檔,然後再將物件編譯成 JavaScript,則需要在第二個命令中加入該選項。
如果您的函式在其他函式中使用,LLVM 可能會將其內嵌,並且它不會在 JavaScript 中顯示為唯一的函式。若要防止內嵌,請使用 EMSCRIPTEN_KEEPALIVE
來定義函式。
void EMSCRIPTEN_KEEPALIVE yourCfunc() {..}
EMSCRIPTEN_KEEPALIVE 也會匯出函式,如同在 EXPORTED_FUNCTIONS 中一樣。
注意
所有未透過 EXPORTED_FUNCTIONS
或 EMSCRIPTEN_KEEPALIVE
保持存活的函式都可能會被移除。請確保您使用其中一種或兩種方法讓您需要的項目保持存活。
匯出的函式需要是 C 函式(以避免 C++ 名稱修飾)。
如果您不想明確追蹤要匯出的函式,以及這些匯出沒有變更時,使用 EMSCRIPTEN_KEEPALIVE
修飾程式碼會很有用。它不一定適合從其他程式庫匯出函式 — 例如,修飾和重新編譯 C 標準程式庫的原始碼並不是一個好主意。如果您以多種方式建置相同的原始碼並變更匯出的內容,那麼在命令列上管理匯出會比較容易。
使用 -sLINKABLE
執行 emcc 也會停用連結時最佳化和無用程式碼刪除。不建議這樣做,因為它會使程式碼變大且較少最佳化。
程式碼遺失的另一個可能原因是 .a
檔案的連結不正確。.a
檔案只會連結命令列上先前檔案所需的內部物件檔,因此檔案的順序很重要,這可能會令人驚訝。如果您要連結 .a
檔案,請確保它們位於檔案清單的末尾,並且它們彼此之間的順序正確。或者,您可以直接在專案中使用 .so
檔案。
提示
將環境設定為 EMCC_DEBUG=1
來進行編譯會很有用(在 Linux 上是 EMCC_DEBUG=1 emcc ...
,在 Windows 上是 set EMCC_DEBUG=1
)。這會將編譯步驟分開並將其儲存在 /tmp/emscripten_temp
中。然後您可以查看程式碼在什麼階段消失(您需要在位元碼階段執行 llvm-dis
來讀取它們,或執行 llvm-nm
等)。
Closure Compiler 會縮減檔案伺服器 API 程式碼。使用檔案系統的程式碼必須使用 emcc 的 --pre-js
選項**與**檔案系統 API 一起最佳化。
-O2 --closure 1
時,我的程式碼會損壞並產生奇怪的錯誤?¶Closure Compiler 會縮減變數名稱,這會導致產生非常短的變數名稱,例如 i
、j
、xa
等等。如果其他程式碼在全域範圍內宣告了具有相同名稱的變數,可能會導致嚴重的問題。
如果您的程式碼可以使用設定的 -O2
和未設定的 --closure
成功執行,則這很可能是原因。
一個解決方案是停止在全域範圍內使用小的變數名稱(通常這是一個錯誤 — 在指派變數時忘記使用 var
)。
另一個替代方案是將產生的程式碼(或您的其他程式碼)包裝在閉包中,如下所示:
var CompiledModule = (function() {
.. GENERATED CODE ..
return Module;
})();
TypeError: Module.someThing is not a function
?¶Module
物件將包含匯出的方法。為了讓某些內容出現在那裡,您應該將其新增至已編譯程式碼的 EXPORTED_FUNCTIONS
,或執行階段方法(例如 getValue
)的 EXPORTED_RUNTIME_METHODS
。例如,
emcc -sEXPORTED_FUNCTIONS=_main,_my_func ...
會匯出 C 方法 my_func
(在此範例中,還有 main
)。和
emcc -sEXPORTED_RUNTIME_METHODS=ccall ...
會匯出 ccall
。在這兩種情況下,您都可以存取 Module
物件上匯出的函式。
注意
如果編譯器可以看到它們被使用,您可以直接使用執行階段方法,而無需匯出它們。例如,您可以透過直接呼叫,在 EM_ASM
程式碼或 --pre-js
中使用 getValue
。最佳化工具不會移除該 JS 執行階段方法,因為它會看到它被使用。如果您想從編譯器看不到的 JS 程式碼外部呼叫該方法,則只需要使用 Module.getValue
,然後您需要匯出它。
注意
Emscripten 過去預設會匯出許多執行階段方法。這增加了程式碼大小,因此我們變更了該預設值。如果您依賴於過去匯出的內容,您應該會在未最佳化的建置中或啟用了 ASSERTIONS
的建置中看到指向解決方案的警告,我們希望這能將任何惱人程度降到最低。詳情請參閱 ChangeLog.md
。
Runtime
不再存在?為什麼我嘗試存取 Runtime.someThing
時會收到錯誤?¶1.37.27 包含重構以移除 Runtime
物件。這使得產生的程式碼更有效率且更精簡,但如果您使用 Runtime.*
API,則需要進行小的變更。您只需要移除 Runtime.
前綴,因為這些函式現在是頂層範圍中的簡單函式(在 -O0
中或啟用了判言的建置中的錯誤訊息會建議這一點)。換句話說,請將
x = Runtime.stackAlloc(10);
取代為
x = stackAlloc(10);
注意
上述方法適用於 --pre-js
或 JS 程式庫中的程式碼,也就是與 emscripten 輸出一起編譯的程式碼。如果您嘗試從已編譯程式碼外部存取 Runtime.*
方法,則必須匯出該函式(使用 EXPORTED_RUNTIME_METHODS
),並在 Module 物件上使用它,請參閱 該常見問題解答條目。
-s
選項時,會得到 NameError
或 在 評估 "-s" 之後的內容時發生問題
?¶如果您在 -s
參數中使用非簡單的字串,並且在取得正確的 shell 引號/跳脫字元時遇到問題,則可能會發生這種情況。
使用更簡單的列表形式(不帶引號、空格或方括號)有時可以幫助解決問題。
emcc a.c -sEXPORTED_RUNTIME_METHODS=foo,bar
也可以使用回應檔案,也就是:
emcc a.c -sEXPORTED_RUNTIME_METHODS=@extra.txt
其中 extra.txt
是一個純文字檔案,其中在不同的行包含 foo
和 bar
。
-s
選項?¶像這樣簡單的事情應該可以在 CMakeLists.txt
檔案中直接運作。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sUSE_SDL=2")
然而,某些 -s
選項可能需要引號,或者當使用 target_link_options
之類的功能時,-s
和下一個參數之間的空格可能會使 CMake 感到困惑。為了避免這些問題,您可以使用 -sX=Y
表示法,也就是說,不使用空格、方括號或引號。
# same as before but no space after -s
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sUSE_SDL=2")
# example of target_link_options with a list of names
target_link_options(example PRIVATE "-sEXPORTED_FUNCTIONS=_main")
另請注意,即使 _main
是一個字串名稱,也不需要加上引號(emcc
知道 EXPORTED_FUNCTIONS
的參數是一個字串列表,因此它接受 a
或 a,b
等)。
file=..
或以 f'..'
開頭的字串上得到 Python SyntaxError: invalid syntax
?¶Emscripten 需要一個足夠新的 Python 版本。較舊的 Python 版本,例如 2.*
,預設情況下將不支援 print 語法,因此它會在諸如 print('..', file=..)
之類的語法上產生錯誤。較舊的 3.*
Python 可能不支援 f 字串,其看起來像 f'..'
。
請確保您已安裝足夠新的 Python 版本,如 SDK 指示中所指定,並確保 emcc 使用該版本(例如,通過使用該 Python 執行 emcc.py
)。
在 CI 環境中,如果預設版本不夠新,您可能需要指定要使用的 Python 版本。例如,在 Netlify 上,您可以使用 PYTHON_VERSION
。
RangeError: Maximum call stack size exceeded
或類似錯誤?¶您可能需要增加 node.js 的堆疊大小。
在 Linux 和 Mac macOS 上,您只需在 Emscripten 編譯器設定檔 (.emscripten) 中執行 NODE_JS = ['/path/to/node', '--stack_size=8192']
即可。在 Windows 上(對於低於 v19 的 node 版本),您還需要 --max-stack-size=8192
,並執行 editbin /stack:33554432 node.exe
。
如果您使用 -sWASM_BIGINT 標誌進行建置,則 int64_t 和 uint64_t 將在 JS 中表示為 bigint 值。如果不使用 -sWASM_BIGINT 標誌,這些值將在 JS 中表示為 number,這無法表示 int64,因此會發生以下情況:在導出的函式中(您可以從 JS 中呼叫),我們會通過將 i64 參數轉換為兩個 i32(低位和高位),並將 i64 回傳值變成 i32 來「合法化」這些類型,並且您可以通過呼叫名為 getTempRet0 的輔助函式來存取高位。
Emscripten 的預設輸出只是一些程式碼。當放在 script 標籤中時,這意味著程式碼位於全域範圍中。因此,同一個頁面上的多個此類模組無法運作。
但是通過將每個模組放在函式範圍中,可以避免該問題。Emscripten 甚至有一個編譯標誌來做到這一點,即 MODULARIZE
,它與 EXPORT_NAME
結合使用非常有用(詳細資訊請參閱 settings.js)。
但是,如果多個單獨的模組之間使用相同的 Module 物件(它定義了畫布、文字輸出區域等),仍然會存在一些問題。Emscripten 預設輸出甚至會在全域範圍中尋找 Module,但是當使用 MODULARIZE
時,您會得到一個必須使用 Module 作為參數呼叫的函式,這樣可以避免該問題。但是請注意,每個模組可能需要自己的畫布、文字輸出區域等;僅僅傳遞相同的 Module 物件(例如,從預設的 HTML shell 傳遞)可能無法運作。
因此,通過使用 MODULARIZE
並為每個模組建立一個正確的 Module 物件,然後將這些物件傳遞進去,多個模組可以正常運作。
另一個選項是使用 iframe,在這種情況下,預設的 HTML shell 將會正常運作,因為每個 iframe 都有自己的畫布等。但是對於小型程式而言,這有點過頭了,這些程式可以如上所述以模組化的方式執行。
可以,您可以在 settings.js
中使用 ENVIRONMENT 選項。例如,使用 emcc -sENVIRONMENT=web
進行建置將會發出僅在 Web 上執行的程式碼,並且不包含對 Node.js 和其他環境的支援程式碼。
這對於減少程式碼大小很有用,並且還可以解決 Node.js 支援程式碼使用 require()
的問題,Webpack 會處理該問題並包含不必要的程式碼。
我不知道為什麼;這是一個完全 cromulent 的單字!