<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C/C++與JavaScript的WebAssembly編程(一)

      1. JavaScript與C/C++混合編程的技術

      JavaScript與C++混合編程可以實現兩種語言的優勢結合,C++的程序性能很高且支持強大的系統調用能力,JavaScript則生態豐富且開發效率高。

      JavaScript與C++混合編程常見的技術手段主要有以下幾種:

      • Node.js的C++擴展: 常用于Node.js實現的后端服務代碼。在WebAssembly出現之前,Node.js的服務器代碼通常以這種方式調用C/C++的模塊。
      • JsAPI和Native API: 常應用于包含WebView的客戶端。將Native端的代碼封裝成Web接口(JsAPI)供前端調用,將Web端的代碼封裝成Native接口供Native調用。像Electron、CEF技術棧的客戶端均采用了此種方式。
      • WebAssembly: 主要用于瀏覽器上運行的前端頁面,Node.js從8.0開始也支持WebAssembly,因此也可用于服務端開發。

      本章所講的內容是基于WebAssembly的混合編程技術。

      2. 什么是WebAssembly?

      WebAssembly是一種新的編碼方式,是一種為web設計的高效、低級字節碼格式。我們可以將C/C++、Rust等低級語言編寫的代碼編譯成WebAssembly字節碼,現代的Web瀏覽器可以加載WebAssembly,并與JavaScript協同運行。從而使得WebAssembly成為JavaScript與C/C++混合編程并在Web上運行的最有效機制。C/C++編譯成的WebAssembly能夠以接近原生語言的效率在瀏覽器上運行。

      2.1. 支持WebAssembly的瀏覽器

      支持WebAssembly的常用瀏覽器及版本:

      • Chrome 57及以上版本。
      • Firefox 52及以上版本。
      • Edge 16(基于Chromium的版本)及以上。
      • Safari 11及以上版本。
      • Opera 44及以上版本。

      參考信息: https://caniuse.com/wasm

      此外,Node.js從8.0版本也開始支持WebAssembly,WebAssembly目前已經成了W3C的Web標準之一。

      2.2. WebAssembly的編譯器

      除了C/C++外,WebAssembly還支持多種其他計算機語言編譯成.wasm,常見的語言和編譯器如下:

      • C/C++: emscripten編譯工具鏈可以將 C/C++ 編譯成 WebAssembly。
      • Rust: wasm-pack:工具可以將 Rust 編譯成 WebAssembly。
      • Go: Go語言的官方工具就鏈支持將 Go 編譯成 WebAssembly。

      3. 開發環境搭建

      1. emscripten官方文檔: https://emscripten.org/docs/getting_started/downloads.html

      2. 依賴的環境準備

        • git
        • Python3.6或更新版本(Windows)
      3. 安裝步驟

        # 1. 從Github上克隆emsdk倉庫
        # emsdk即Emscripten SDK,是將C/C++編譯成WebAssembly的工具
        git clone https://github.com/emscripten-core/emsdk.git
        
        # 2. 進入emsdk目錄
        cd emsdk
        
        # 3. 下載和安裝最新的SDK tools(包括node.js、emscripten等)
        # Linux/macOS:
        ./emsdk install latest
        # Windows:
        ./emsdk.bat install latest
        # (安裝大概需要十幾分鐘的時間,可以去喝杯茶休息一下了)
        # 會將相關的工具安裝在以下三個目錄
        # emsdk/node
        # emsdk/upstream
        # emsdk/python (Windows才有,會安裝nuget)
        
        # 4. 為當前用戶設置latest版本為當前激活的工具
        # Linux/macOS:
        ./emsdk activate latest
        # Windows:
        ./emsdk.bat activate latest
        
        # 5. 為當前命令終端設置環境變量
        # Linux/macOS:
        source ./emsdk_env.sh
        # Windows:
        ./emsdk_env.bat
        
        # 6. 驗證是否安裝成功
        emcc -v
        # (如果有顯示正常的版本信息,則說明安裝成功)
        

        以上示例基于3.1.72版本的emscripten。

      4. Hello World程序

      我們從一個Hello World程序開始,了解WebAssembly程序的開發、編譯、運行的大致流程。

      1. 新建一個測試目錄hello_world和源碼文件hello.cpp

        // hello_world/hello.cpp
        #include <iostream>
        
        int main()
        {
            std::cout << "Hello World from C++" << std::endl;
            return 0;
        }
        
      2. 執行以下命令編譯為WebAssembly

        emcc hello.cpp -o hello.html
        

        編譯后會生成如下三個文件:

        ./hello_world
        ├── hello.html # emscripten的測試頁面,用來展示輸出內容的HTML頁面。
        ├── hello.js   # 是Emscripten生成的膠水代碼,其中包含了Emscripten的運行環境和.wasm文件的封裝。
        └── hello.wasm # 二進制的字節碼文件
        
      3. 在當前Demo目錄下啟動一個http-server服務,可以用python或node.js工具。

        # 進入目錄
        cd hello_world
        
        # 在當前目錄啟動http-server服務
        # Python3的用法
        python -m http.server
        # Python2的用法
        python -m SimpleHTTPServer
        
      4. 在支持WebAssembly的瀏覽器中打開http://localhost:8000/hello.html頁面,正常情況下就可以看到輸出內容(Hello World from C++)了。

        file

      5. emscripten常見用法

      5.1. emscripten編譯流程

      Emscripten的誕生早于WebAssembly。WebAssembly出現之前,Emscripten的編譯目標時asm.js,即Emscripten的主要功能是將C/C++代碼編譯成JavaScript代碼。Emscripten在1.37.3開始正式支持WebAssembly,可以根據編譯選項設置編譯目標為asm.js或WebAssembly。

      Emscripten的編譯流程如下:

      file

      • C/C++代碼先通過Clang編譯為LLVM的字節碼,然后再根據設置的不同目標編譯為asm.js或WebAssembly(.wasm)。
      • 可以通過-s WASM=1-s WASM=0來設置編譯目標,Emscripten自v1.38.1開始,默認的缺省編譯選項為WASM=1,之前的版本默認為WASM=0
      • 相比于asm.js,.wasm具有體積小、執行效率高的優勢,因此一般會優先選擇.wasm作為編譯目標。當然,在實際的項目中,為了增加程序的兼容性,可能會同時構建兩個編譯目標,在支持WebAssembly的瀏覽器中加載.wasm,不支持WebAssembly的老版本瀏覽器中降級為asm.js。

      5.2. emsdk常見用法

      emsdk是emscripten工具鏈最核心的部分,emsdk是將C/C++編譯成WebAssembly的編譯工具,其用法與Clang/GCC有點相似。

      1. 最簡單用法。

      • 編譯指令emcc ./hello.cpp
      • 結果文件
        • a.out.wasm: 為C/C++源文件編譯后形成的WebAssembly匯編文件,是一個二進制的字節碼文件。
        • a.out.js: 是Emscripten生成的膠水代碼,其中包含了Emscripten的運行環境和.wasm文件的封裝,導入a.out.js即可自動完成.wasm文件的載入、編譯、實例化、運行時初始化等繁雜的工作。

      2. -o選項

      -o選項可以指定輸出的文件名和文件類型。

      【demo1】

      • 編譯指令: emcc ./hello.cpp -o hello.js
      • 結果文件:
        • hello.wasm: 與a.out.wasm文件相同。
        • hello.js: 與a.out.js文件相同。

      【demo2】

      • 編譯指令: emcc ./hello.cpp -o hello2.html
      • 結果文件:
        • hello2.wasm: 與a.out.wasm文件相同。
        • hello2.js: 與a.out.js文件相同。
        • hello2.html: emscripten的測試頁面,用來展示輸出內容的HTML頁面。

      3. -s選項。

      -s選項是一個用于設置編譯目標和編譯屬性的重要選項:

      • -s WASM=1: 指定輸出為WebAssembly 式,這能提升執行性能,WASM=1是默認的缺省參數,此選項會生成XXX.wasmXXX.js文件。
      • -s WASM=0: 指定輸出為asm.js格式,此選項只會生成XXX.js文件,不會生成XXX.wasm文件。
      • -s EXPORTED_RUNTIME_METHODS=['ccall','cwrap']: 指定導出運行時方法ccallcwrapccall/cwrap輔助函數默認沒有導出,在編譯時需要通過此選項顯示導出。
      • -s MODULARIZE=1:使輸出的 JavaScript 代碼成為一個模塊化的形式,便于在不同的環境下使用。
      • -s EXPORT_NAME='myModule':自定義導出的模塊名稱。
      • -s ALLOW_MEMORY_GROWTH=1:允許動態擴展內存,適用于需要可變內存的應用場景。

      4. --bind選項

      --bind選項表示使用embind模塊。embind模塊可以將C++類和函數綁定到JavaScript環境中,后文將講解此部分內容。

      5. --js-library選項

      --js-library選項可以指定一個JavaScript文件作為JS庫,參與C/C++的編譯過程。后文將進一步講解此相關內容。

      5.3. 導出一個函數

      Hello World程序中,我們在HTML頁面中加載并調用了C++的main函數。main函數是C/C++程序的入口函數,實際項目中,底層的C/C++模塊通常希望通過接口來提供特定功能,而不是直接調用main函數作為單一入口。

      emscripten中C/C++要導出一個接口,有兩個關鍵的點:

      • extern "C"以C的方式導出接口,避免C++的函數在編譯后會對函數名稱進行重整,在《導出接口的定義》一章中已介紹過相關內容。
      • EMSCRIPTEN_KEEPALIVE宏告知編譯器后續函數在優化時必須保留,并且該函數將被導出至JavaScript環境。EMSCRIPTEN_KEEPALIVE是emscripten編譯器內置的預編譯宏,在<emscripten.h>頭文件中定義了該宏。

      函數定義:

      extern "C" EMSCRIPTEN_KEEPALIVE int32_t add(int32_t a, int32_t b)
      {
          return a + b;
      }
      

      C++代碼:

      為了代碼編寫方便,我們可以定義一個宏來簡化代碼,如下代碼(export_function.cpp)。

      #include <cstdint>
      #include <emscripten.h>
      
      #define DECL_API(rettype) extern "C" EMSCRIPTEN_KEEPALIVE rettype
      
      DECL_API(int32_t) add(int32_t a, int32_t b)
      {
          return a + b;
      }
      
      DECL_API(int32_t) sub(int32_t a, int32_t b)
      {
          return a - b;
      }
      

      編譯指令:

      通過以下指令編譯代碼。

      emcc ./export_function.cpp -o ./export_function.js
      

      HTML代碼:

      編寫html測試頁面(test.html)如下。

      <html>
        <head>
          <meta charset="utf-8" />
          <title>Emscripten</title>
        </head>
      
        <body>
          <h2>Emscripten:你好,世界!</h2>
          <script>
            Module = {};
            Module.onRuntimeInitialized = function () {
              let r1 = Module._add(3, 2);
              console.log("add(3, 2) = " + r1);
              let r2 = Module._sub(3, 2);
              console.log("sub(3, 2) = " + r2);
            };
          </script>
          <script src="export_function.js"></script>
        </body>
      </html>
      

      運行結果:

      瀏覽器打開該頁面,可以看到控制臺輸出了add(3, 2) = 5sub(3, 2) = 1

      file

      代碼說明:

      WebAssembly模塊是異步加載的,這意味著JS加載完成后emscripten的運行時環境可能并未準備好,我們要等待emscripten的運行時環境準備就緒后再調用WebAssembly模塊的代碼。而onRuntimeInitialized()就是emscripten的運行時環境準備就緒后的一個回調函數,因此可在該函數內安全的調用WebAssembly模塊相關的代碼。在無特殊說明(不產生歧義)的情況下,后續文章的測試代碼將不再列出該回調函數的完整代碼。

      Module.onRuntimeInitialized = function () {
          <!-- TODO -->
      };
      

      歷史文章推薦:

      01. 什么是SDK

      02. SDK的設計目標

      03. 接口設計與規范

      04. 接口注釋與接口文檔

      05. 原理篇:字符集與字符編碼(一)

      06. 原理篇:字符集與字符編碼(二)

      07. 原理篇:多字節字符與寬字節字符

      08. 原理篇:靜態庫、動態庫與運行庫

      09. 跨平臺:C++標準的版本

      10. 跨平臺:源碼的保存格式與中文亂碼問題

      11. 跨平臺:宏定義隔離平臺差異

      12. 跨平臺:基礎數據類型的定義

      13. 跨平臺:文件系統的操作

      14. 跨平臺:頭文件包含的差異

      15. 跨平臺:導出接口的定義

      16. 跨平臺:字節序大端與小端

      17. 跨平臺:內存和資源管理

      18. 工程篇:C/C++常用編譯器

      19. 工程篇:用VSCode搭建C++開發環境

      20. 工程篇:CMake實現跨平臺構建

      21. 工程篇:VSCode中使用CMake插件運行和調試程序

      22. 跨語言:跨語言的混合編程

      23. 跨語言:C++接口設計和代碼實現

      24. 跨語言:C語言接口設計和代碼實現

      25. 跨語言:C/C++與Python混合編程(一)

      26. 跨語言:C/C++與Python混合編程(二)

      27. 跨語言:C/C++與Python混合編程(三)

      附錄A-計算機術語中成對出現的單詞

      附錄B: 計算機術語中常見的單詞縮寫


      大家好,我是陌塵。

      IT從業10年+, 北漂過也深漂過,目前暫定居于杭州,未來不知還會飄向何方。

      搞了8年C++,也干過2年前端;用Python寫過書,也玩過一點PHP,未來還會折騰更多東西,不死不休。

      感謝大家的關注,期待與你一起成長。



      【SunLogging】
      掃碼二維碼,關注微信公眾號,閱讀更多精彩內容
      posted @ 2025-04-02 20:47  陌塵(MoChen)  閱讀(353)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 高清无打码一区二区三区| 日韩欧美精品suv| 欧美肥妇毛多水多bbxx| 亚洲国产精品久久久久婷婷图片| 国产精品十八禁一区二区| 欧美乱码伦视频免费| 欧美人成精品网站播放| 欧美激情内射喷水高潮| 94人妻少妇偷人精品| 国产在线拍揄自揄拍无码视频| 99在线小视频| 亚洲精品动漫免费二区| 中日韩黄色基地一二三区| 精品国产国语对白主播野战| 久久精品国产福利一区二区| 色视频不卡一区二区三区| 亚洲成av人片无码迅雷下载 | 高清有码国产一区二区| 亚洲午夜精品国产电影在线观看| 无码人妻精品一区二区三区下载| 国产成人人综合亚洲欧美丁香花 | 视频网站在线观看不卡| 亚洲欧洲日韩国内高清| 亚洲成aⅴ人在线电影| 两个人的视频www免费| 99RE6在线观看国产精品| 国产精品一区二区久久毛片 | 山东省| 亚洲精品国产第一区二区| 福利一区二区在线视频| 施秉县| 中文字幕日韩一区二区不卡| 少妇无套内谢免费视频| 奶头好大揉着好爽视频| 99久久婷婷国产综合精品青草漫画| 国产精品午夜福利91| 综合色一色综合久久网| 国产高清一区二区三区视频| 日韩成人无码影院| 亚洲国产成人资源在线| 无码视频一区二区三区|