1. WebAssembly技術(shù)介紹
WebAssembly是2015年誕生的一項(xiàng)新的技術(shù),在2015年7月,Wasm首次對(duì)外公開,并正式開始設(shè)計(jì),同年,W3C成立了Wasm社區(qū)小組(成員包括Chrome、Edge、Firefox和WebKit),致力于推動(dòng)Wasm技術(shù)的早期發(fā)展。
wasm 是一個(gè)可移植、體積小、加載快并且兼容 Web 的全新格式。
WebAssembly的中文官網(wǎng):webassembly.org.cn/
來(lái)至官網(wǎng)的介紹:
WebAssembly 是由主流瀏覽器廠商組成的 W3C 社區(qū)團(tuán)體 制定的一個(gè)新的規(guī)范。
高效 WebAssembly 有一套完整的語(yǔ)義,實(shí)際上 wasm 是體積小且加載快的二進(jìn)制格式, 其目標(biāo)就是充分發(fā)揮硬件能力以達(dá)到原生執(zhí)行效率
安全 WebAssembly 運(yùn)行在一個(gè)沙箱化的執(zhí)行環(huán)境中,甚至可以在現(xiàn)有的 JavaScript 虛擬機(jī)中實(shí)現(xiàn)。在web環(huán)境中,WebAssembly將會(huì)嚴(yán)格遵守同源策略以及瀏覽器安全策略。
開放 WebAssembly 設(shè)計(jì)了一個(gè)非常規(guī)整的文本格式用來(lái)、調(diào)試、測(cè)試、實(shí)驗(yàn)、優(yōu)化、學(xué)習(xí)、教學(xué)或者編寫程序??梢砸赃@種文本格式在web頁(yè)面上查看wasm模塊的源碼。
標(biāo)準(zhǔn) WebAssembly 在 web 中被設(shè)計(jì)成無(wú)版本、特性可測(cè)試、向后兼容的。WebAssembly 可以被 JavaScript 調(diào)用,進(jìn)入 JavaScript 上下文,也可以像 Web API 一樣調(diào)用瀏覽器的功能。當(dāng)然,WebAssembly 不僅可以運(yùn)行在瀏覽器上,也可以運(yùn)行在非web環(huán)境下。
由于不同的計(jì)算機(jī) CPU 架構(gòu)不同,機(jī)器碼標(biāo)準(zhǔn)有所差別,常見的架構(gòu)有 x86、AMD 64、ARM,因此高級(jí)語(yǔ)言編譯成可執(zhí)行代碼時(shí)需要指定目標(biāo)架構(gòu)。
WebAssembly 抹平了不同 CPU 架構(gòu)的機(jī)器碼,WebAssembly 的機(jī)器碼不能放在任何一個(gè)平臺(tái)上運(yùn)行,但由于非常接近機(jī)器碼,可以被非??焖俚姆g為對(duì)應(yīng)架構(gòu)的機(jī)器碼。因此,WebAssembly 的運(yùn)行速度和機(jī)器碼非常接近。
通過官網(wǎng)的介紹看出,WebAssembly技術(shù)的目的就是提高web端代碼性能,總所周知C/C++語(yǔ)言的運(yùn)行性能一直是天花板,許多 3D 游戲,大型圖形編輯相關(guān)的工具軟件都是用 C/C++ 語(yǔ)言寫的,如果能把C/C++代碼搬到web端運(yùn)行,那么理論上可以大大提高web端的運(yùn)行效率。
要使用WebAssembly技術(shù),需要先安裝Emscripten編譯器,這個(gè)Emscripten編譯器可以將 C/C++ 代碼編譯成 JS 代碼,但不是普通的 JS,而是一種叫做 asm.js 的 JavaScript 變體。
在WebAssembly官網(wǎng)有介紹如何編譯安裝Emscripten SDK,網(wǎng)站地址: webassembly.org.cn/getting-sta…
Emscripten的官網(wǎng)也有詳細(xì)介紹: emscripten.org/docs/gettin…
2. 安裝Emscripten編譯器
官網(wǎng)上有步驟介紹,這里再把安裝的步驟做個(gè)總結(jié)。
注: 當(dāng)前是在win10 64 位環(huán)境下操作。
(1)需要先安裝python環(huán)境,推薦安裝python3.X,因?yàn)镋mscripten編譯器里用到了python命令。
python環(huán)境安裝看這里:
xiaolong.blog.csdn.net/article/det…
xiaolong.blog.csdn.net/article/det…
(2)安裝Git工具,因?yàn)樾枰褂胓it命令在線從倉(cāng)庫(kù)下載需要的文件。
Git工具安裝看這里:翻到Git工具安裝章節(jié)。
blog.csdn.net/xiaolong112…
(3)從GitHub倉(cāng)庫(kù)下載編譯器項(xiàng)目文件,選擇一個(gè)英文目錄,鼠標(biāo)右鍵,打開git命令行。(安裝完Git工具后會(huì)自動(dòng)關(guān)關(guān)鍵鼠標(biāo)右鍵)
運(yùn)行下面命令進(jìn)行下載,過程中需要等待一段時(shí)間。
git clone https://github.com/emscripten-core/emsdk.git
復(fù)制代碼
下載成功后,當(dāng)前目錄下會(huì)出現(xiàn)一個(gè)emsdk目錄。
(4)在當(dāng)前目錄下的文件夾地址欄里輸入cmd,按下回車,快速打開cmd命令終端。
輸入命令進(jìn)入到emdk目錄下。
cd emsdk
復(fù)制代碼
(5)安裝最新的SDK并激活,在當(dāng)前命令行繼續(xù)輸入命令。 注: 安裝要一點(diǎn)時(shí)間,需要耐心等待,具體速度看網(wǎng)絡(luò)情況。
emsdk install latest
emsdk activate latest --permanent
復(fù)制代碼
完成輸出的過程:
C:\Qt\emsdk>emsdk install latest
Installing SDK 'sdk-releases-upstream-37fc7647c754ac9a28ad588c143b82286de0ef71-64bit'..
Skipped installing node-12.18.1-64bit, already installed.
Skipped installing python-3.7.4-pywin32-64bit, already installed.
Skipped installing java-8.152-64bit, already installed.
Installing tool 'releases-upstream-37fc7647c754ac9a28ad588c143b82286de0ef71-64bit'..
Downloading: C:/Qt/emsdk/zips/37fc7647c754ac9a28ad588c143b82286de0ef71-wasm-binaries.zip from https://storage.googleapis.com/webassembly/emscripten-releases-builds/win/37fc7647c754ac9a28ad588c143b82286de0ef71/wasm-binaries.zip, 476624087 Bytes
Unpacking 'C:/Qt/emsdk/zips/37fc7647c754ac9a28ad588c143b82286de0ef71-wasm-binaries.zip' to 'C:/Qt/emsdk/upstream'
Done installing tool 'releases-upstream-37fc7647c754ac9a28ad588c143b82286de0ef71-64bit'.
Running post-install step: npm ci ...
Running post-install step: npm install google-closure-compiler-windows
Done running: npm ci
Done installing SDK 'sdk-releases-upstream-37fc7647c754ac9a28ad588c143b82286de0ef71-64bit'.
?
C:\Qt\emsdk>emsdk activate latest --permanent
Registering active Emscripten environment permanently
?
Setting the following tools as active:
node-12.18.1-64bit
python-3.7.4-pywin32-64bit
java-8.152-64bit
releases-upstream-37fc7647c754ac9a28ad588c143b82286de0ef71-64bit
?
Setting environment variables:
PATH = C:\Qt\emsdk;C:\Qt\emsdk\node\12.18.1_64bit\bin;C:\Qt\emsdk\python\3.7.4-pywin32_64bit;C:\Qt\emsdk\java\8.152_64bit\bin;C:\Qt\emsdk\upstream\emscripten;C:\Users\11266\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\11266\AppData\Local\Programs\Python\Python38-32;%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;C:\Users\11266\AppData\Local\Programs\Microsoft VS Code\bin;C:\MinGW\i686-8.1.0-release-posix-dwarf-rt_v6-rev0\mingw32\bin;C:\OpenCV_3.4.7\OpenCV-MinGW-Build-OpenCV-3.4.7\x86\mingw\bin;%USERPROFILE%.dotnet\tools;C:\FFMPEG\ffmpeg_x86_4.2.2\bin;C:\FFMPEG\ffmpeg_x86_x64_3.3.2\bin;C:\Users\11266\AppData\Roaming\npm
Global environment variables up to date
復(fù)制代碼
(6)在命令行輸入em++ -v測(cè)試編譯器是否安裝成功。
出現(xiàn)以下提示,表示編譯器已經(jīng)安裝成功。
C:\Qt\emsdk>emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.10
clang version 12.0.0 (Cswircachegitchromium.googlesource.com-external-github.com-llvm-llvm--project 445289aa63e1b82b9eea6497fb2d0443813a9d4e)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:/Qt/emsdk/upstream/bin
shared:INFO: (Emscripten: Running sanity checks)
?
C:\Qt\emsdk>em++ -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.10
clang version 12.0.0 (Cswircachegitchromium.googlesource.com-external-github.com-llvm-llvm--project 445289aa63e1b82b9eea6497fb2d0443813a9d4e)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:/Qt/emsdk/upstream/bin
shared:INFO: (Emscripten: Running sanity checks)
?
C:\Qt\emsdk>
復(fù)制代碼
(7)這時(shí)可以先關(guān)閉當(dāng)前終端,再重新開一個(gè)新終端,運(yùn)行emcc或者em++查看幫助,會(huì)出現(xiàn)以下提示。
C:\Users\11266>cd /d D:\linux-share-dir\tmp\WebAssembly_TestCode
?
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc -help
?
==============================================================================
Welcome to Emscripten!
?
This is the first time any of the Emscripten tools has been run.
?
A settings file has been copied to ~/.emscripten, at absolute path: C:\Users\11266.emscripten
?
It contains our best guesses for the important paths, which are:
?
LLVM_ROOT = /usr/bin
NODE_JS = C:\Program Files\nodejs\node.exe
EMSCRIPTEN_ROOT = C:\Qt\emsdk\upstream\emscripten
?
Please edit the file if any of those are incorrect.
?
This command will now exit. When you are done editing those paths, re-run it.
==============================================================================
復(fù)制代碼
打開當(dāng)前系統(tǒng)的用戶目錄,會(huì)看到一個(gè).emscripten文件。這個(gè)文件里存放了編譯器需要的環(huán)境變量和路徑。
如果后續(xù)運(yùn)行emcc或者em++命令編譯程序時(shí)報(bào)錯(cuò),例如:
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.cpp -Os -s WASM=1 -s SIDE_MODULE=1 -o hello.wasm
shared:ERROR: BINARYEN_ROOT is set to empty value in C:\Users\11266/.emscripten
?
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.cpp -Os -s WASM=1 -s SIDE_MODULE=1 -o hello.wasm
cache:INFO: generating system asset: is_vanilla.txt... (this will be cached in "C:\Users\11266.emscripten_cache\is_vanilla.txt" for subsequent builds)
shared:ERROR: llc executable not found at `C:\Users\11266/upstream/bin\llc.exe`
復(fù)制代碼
解決辦法:將.emscripten文件里的所有路徑改成絕對(duì)路徑。
例如:原來(lái)的路徑
import os
emsdk_path = os.path.dirname(os.environ.get('EM_CONFIG')).replace('\', '/')
NODE_JS = emsdk_path + '/node/12.18.1_64bit/bin/node.exe'
PYTHON = emsdk_path + '/python/3.7.4-pywin32_64bit/python.exe'
JAVA = emsdk_path + '/java/8.152_64bit/bin/java.exe'
LLVM_ROOT = emsdk_path + '/upstream/bin'
BINARYEN_ROOT = emsdk_path + '/upstream'
EMSCRIPTEN_ROOT = emsdk_path + '/upstream/emscripten'
TEMP_DIR = emsdk_path + '/tmp'
COMPILER_ENGINE = NODE_JS
JS_ENGINES = [NODE_JS]
復(fù)制代碼
修改后的配置文件路徑:
import os
NODE_JS = 'C:/Qt/emsdk/node/12.18.1_64bit/bin/node.exe'
PYTHON = 'C:/Qt/emsdk/python/3.7.4-pywin32_64bit/python.exe'
JAVA = 'C:/Qt/emsdk/java/8.152_64bit/bin/java.exe'
LLVM_ROOT = 'C:/Qt/emsdk/upstream/bin'
BINARYEN_ROOT = 'C:/Qt/emsdk/upstream'
EMSCRIPTEN_ROOT = 'C:/Qt/emsdk/upstream/emscripten'
TEMP_DIR = 'C:/Qt/emsdk/tmp'
COMPILER_ENGINE = NODE_JS
JS_ENGINES = [NODE_JS]
復(fù)制代碼
再重新運(yùn)行即可:
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.cpp -Os -s WASM=1 -s SIDE_MODULE=1 -o hello.wasm
cache:INFO: generating system asset: generated_struct_info.json... (this will be cached in "C:\Users\11266.emscripten_cache\wasm-obj-pic\generated_struct_info.json" for subsequent builds)
cache:INFO: - ok
復(fù)制代碼
3. 編寫C/C++代碼瀏覽器運(yùn)行測(cè)試
(1)編寫一個(gè)簡(jiǎn)單的C/C++代碼
#include
int main()
{
printf("Hello World! \n");
printf("WebAssembly 牛逼!\n");
return 0;
}
復(fù)制代碼
(2)使用emcc編譯編譯
D:>cd /d D:\linux-share-dir\tmp\WebAssembly_TestCode
?
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.cpp -s WASM=1 -O3 -o hello-emcc.js
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.cpp -s WASM=1 -O3 -o hello-emcc.html
復(fù)制代碼
編譯成功之后,在目錄下會(huì)生成:js,html,wasm 等3個(gè)文件。
(3)開一個(gè)HTTP服務(wù)器,測(cè)試網(wǎng)頁(yè)運(yùn)行效果
在當(dāng)前編譯目錄,使用python開一個(gè)HTTP服務(wù)器。
D:\linux-share-dir\tmp\WebAssembly_TestCode>python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
復(fù)制代碼
打開Edge瀏覽器(win10自帶的瀏覽器),輸入http://127.0.1:8000。
選擇hello-emcc.html文件打開。下面是運(yùn)行效果。
也可以使用 emrun 命令來(lái)創(chuàng)建一個(gè) http 協(xié)議的 web server 展示編譯后的文件,和前面python命令的功能類似。
$ emrun --no_browser --port 8080
復(fù)制代碼
4. 編寫C/C++代碼給前端調(diào)用測(cè)試
(1)編寫一個(gè)函數(shù),用于測(cè)試調(diào)用
#include
#include
?
int func_square(int x)
{
return x * x;
}
?
int func_sum(int x, int y)
{
return x + y;
}
?
char* func_string(char* str)
{
return str;
}
復(fù)制代碼
(2)編譯成wasm文件
D:\linux-share-dir\tmp\WebAssembly_TestCode>emcc hello.c -Os -s WASM=1 -s SIDE_MODULE=1 -o hello.wasm
復(fù)制代碼
(3)編寫一個(gè)js文件。名稱為: loader.js
function loadWebAssembly(filename, imports = {}) {
return fetch(filename)
.then(response => response.arrayBuffer())
.then(buffer => {
imports.env = imports.env || {}
Object.assign(imports.env, {
memoryBase: 0,
tableBase: 0,
__memory_base: 0,
__table_base: 0,
memory: new WebAssembly.Memory({ initial: 256, maximum: 256 }),
table: new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' })
})
return WebAssembly.instantiate(buffer, imports)
})
.then(result => result.instance )
}
?
function loadJS (url, imports = {}) {
return fetch(url)
.then(response => response.text())
.then(code => new Function('imports', `return (${code})()`))
.then(factory => ({ exports: factory(imports) }))
}
復(fù)制代碼
(4)編寫一個(gè)HTML文件調(diào)用函數(shù)接口 : 例如: index.html
?
Compile C to WebAssembly
The test result can be found in console.
? 復(fù)制代碼
(5)啟動(dòng)http服務(wù)器,訪問測(cè)試。
python -m http.server
復(fù)制代碼
打開谷歌瀏覽器輸入地址訪問: http://127.0.0.1:8000/index.html
運(yùn)行后,按下F12,查看控制臺(tái)的輸出。
注意:如果要反復(fù)修改HTML文件測(cè)試結(jié)果,瀏覽器最好打開無(wú)痕模式進(jìn)行測(cè)試。
在瀏覽器里可以看到wasm轉(zhuǎn)成wast文本格式的代碼,從代碼里可以看到導(dǎo)出的函數(shù)。
5. webassembly在線調(diào)試工具
地址:wasdk.github.io/WasmFiddle/
6. wasm2wast工具安裝
wasm2wast這個(gè)工具是將 WebAssembly 二進(jìn)制轉(zhuǎn)換為 S-expressions。他是命令行工具,一個(gè)二進(jìn)制文件作為輸入,輸出一個(gè)包含可以讀文本的文件。開發(fā)者可以編輯文本文件,然后再將其轉(zhuǎn)換為二進(jìn)制文件,比如優(yōu)化算法、追蹤問題、插入調(diào)試語(yǔ)句等等。
地址: github.com/WebAssembly…
用法示例:
wast2wasm demo.wast -o demo.wasm
?
wasm2wast demo.wasm -o demo.wast
復(fù)制代碼
7. emsdk常用命令介紹
(1)emcc -v 顯示安裝的版本號(hào)
?
(2)em++ -v 顯示安裝的版本號(hào)
?
(3)emsdk update 更新emssk庫(kù)到最新版
?
(4)emsdk list --old 查看emsdk歷史版本號(hào)列表
?
(5)emsdk list --old > sdklist.txt 將歷史版本號(hào)寫入到sdklist.txt文件中
?
(6)emsdk install <版本號(hào)> 安裝對(duì)應(yīng)版本號(hào)的sdk tool
例如: emsdk install 1.39.7
(7)emsdk install latest 安裝最新版本號(hào)的std tool
?
(8)emsdk activate <版本號(hào)> 激活對(duì)應(yīng)版本號(hào)的std tool ,也就是設(shè)置當(dāng)前使用的版本
例如:emsdk activate --embedded 1.39.7 --permanent
?
?
(9)emsdk uninstall <版本號(hào)> 卸載對(duì)應(yīng)版本號(hào)的sdk tool
?
?
(10)emsdk help 或者 emsdk --help 查看幫助
復(fù)制代碼
8. 總結(jié)
審核編輯:湯梓紅
-
Web
+關(guān)注
關(guān)注
2文章
1303瀏覽量
73972 -
編譯器
+關(guān)注
關(guān)注
1文章
1672瀏覽量
51236 -
Win10
+關(guān)注
關(guān)注
2文章
710瀏覽量
42235
發(fā)布評(píng)論請(qǐng)先 登錄
win10下無(wú)法運(yùn)行STVD怎么解決?
win10使用技巧有哪些 win10使用技巧分享
Win10 強(qiáng)制更新重啟解決辦法
想要安裝win10系統(tǒng),它對(duì)電腦的最低配置是什么
win10的Proteus 8應(yīng)用程序安裝教程免費(fèi)下載
CC Debugger win10 win7驅(qū)動(dòng)及CC Debugger固件免費(fèi)下載
win10系統(tǒng)激活密鑰key詳細(xì)步驟
win10系統(tǒng)新電腦分區(qū)的詳細(xì)教程
PICKIT3 WIN10無(wú)法識(shí)別問題
關(guān)于win10驅(qū)動(dòng)安裝失敗的解決
WebAssembly_Web運(yùn)行CC++程序(win10)
評(píng)論