第二章: 学习Emscripten

Emscripten简介及初体验 文章目录1. Emscripten简介1.1 诞生背景1.2 什么是Emscripten2. 安装Emscripten2.1 前置条件2.2 下载安装过程3. 示例4. 参考资料 1. Emscripten简介 1.1 诞生背景 Web 技术突飞猛进,但是有一个领域一直无法突破 ---- 游戏。 游戏的性能要求非常高,一些大型游戏连 PC 跑起来都很吃力,更不要提在浏览器的沙盒模型里跑了!但是,尽管很困难,许多开发者始终没放弃,希望让浏览器运行 3D 游戏。 2012年,Mozilla 的工程师 Alon 阅读详情
AI摘要

本文介绍了将C/C++代码转换为WebAssembly模块的工具链Emscripten。涵盖其安装方法,包括使用emsdk安装;展示了如何用它生成asm.js,以及在Node.js和浏览器中运行WebAssembly模块。还探索了emsdk管理工具和SDK的选项,以及Emscripten提供的不同优化级别。

在本章中,我们将学习 Emscripten,这是一个将 C/C++ 代码转换为 WebAssembly 模块的工具链。

Emscripten 由两部分组成:

  • Emscripten 编译器前端
  • Emscripten SDK(emsdk)

Clang 编译器前端将 C/C++ 代码编译成LLVM 中间表示(LLVM IR),然后使用 LLVM 后端将 LLVM IR 转换成原生代码。Clang 编译器速度快,使用的内存少,且与GNU 编译器集合(GCC)兼容。Emscripten 类似于 Clang;前者生成 wasm 二进制文件,而后者生成 原生 二进制文件。Emscripten 编译器前端(emcc)是将 C/C++ 转换成 LLVM IR(二进制和人类可读形式)以及 WebAssembly 二进制或 asm.js 的编译器前端,如 JavaScript。

Figure 2.1 – Emscripten compiler frontend

图2.1 – Emscripten 编译器前端

emsdk 帮助管理和维护 Emscripten 工具链组件,并设置运行时/终端环境以运行 emcc。

在本章中,我们将学习如何安装 Emscripten。然后,我们将使用 Emscripten 生成 asm.js,一个可以在 Node.js 和浏览器上运行的 WebAssembly 模块。之后,我们将探索 emsdk 工具。最后,我们将探索 Emscripten 提供的各种优化。我们将在本章中涵盖以下主题:

  • 使用 emsdk 安装 Emscripten

  • 使用 Emscripten 生成 asm.js

  • 在 Node.js 中运行 Emscripten 的 Hello World

  • 在浏览器中运行 Emscripten 的 Hello World

  • 探索 emsdk 中的其他选项

  • 理解各种级别的优化

    您可能不知道的是

    asm.js 是 JavaScript 的一个子集,优化后可以在浏览器中以接近原生的性能运行。asm.js 规范并没有被所有浏览器厂商接受。asm.js 已经发展成了 WebAssembly。

技术要求

我们将在本章中展示如何设置 Emscripten,您将需要在您的系统上安装以下内容:

  • Python >= 3.7

  • Node.js > 12.18

    注意

    emsdk 自带一个兼容的 Node.js 版本。

技术要求

本章将展示如何设置Emscripten,为此您需要在您的系统上安装以下内容:

  • Python >= 3.7

  • Node.js > 12.18

    注意

    emsdk预装了兼容的Node.js版本。

使用emsdk安装Emscripten

emsdk提供了一种简单的方法来安装、管理以及切换Emscripten工具链的版本。emsdk负责设置编译C/C++到LLVM IR,然后到JavaScript(以asm.js或WebAssembly二进制格式)所需的环境、工具和SDK。

现在让我们安装Emscripten并开始入手:

  1. 克隆emsdk仓库并进入emsdk文件夹:

    $ git clone https://github.com/emscripten-core/emsdk
    $ cd emsdk 
    
  2. 要在机器上安装emsdk,请运行以下命令:

对于*nix用户,请使用以下命令:

$ ./emsdk install latest

对于Windows用户,请使用以下命令:

$ emsdk install latest

注意

前述命令可能需要一些时间来运行;它将构建并设置整个工具链。

接下来,我们将激活最新版本的emsdk。激活将更新本地shell,添加所需的环境引用,并使当前shell中的用户使用最新的SDK。它会将Emscripten工具链的路径和其他必要信息写入用户主目录下名为.emscripten的文件:

  1. 要激活已安装的emsdk,请运行以下命令:

对于*nix用户,请使用以下命令:

 $ ./emsdk activate latest

对于Windows用户,请使用以下命令:

 $ emsdk activate latest
  1. 现在,是时候确保配置和路径被激活,通过运行以下命令:

对于*nix用户,请使用以下命令:

 $ source ./emsdk_env.sh

对于Windows用户,请使用以下命令:

 $ emsdk_env.bat

恭喜,Emscripten工具链已安装!使用emsdk更新工具链就像安装一样简单。

要进行更新,请运行以下命令:

对于*nix用户,请使用以下命令:

$ ./emsdk update

对于Windows用户,请使用以下命令:

$ emsdk update

emsdk在Emscripten配置文件中设置了以下路径。Emscripten配置文件(.emscripten)位于家目录中。它包含以下内容:

  • LLVM_ROOT – 指定LLVM Clang编译器的路径
  • NODE_JS – 指定Node.js的路径
  • BINARYEN_ROOT – 指定Emscripten编译器的优化器
  • EMSCRIPTEN_ROOT – 指定Emscripten编译器的路径

我们可以通过使用以下命令来检查emcc的安装是否成功:

 $ emcc --version

现在我们已经完成了Emscripten编译器的安装,让我们继续使用它。

使用Emscripten生成asm.js

我们将使用Emscripten将C/C++程序移植到asm.js或WebAssembly二进制格式,然后在JavaScript引擎中运行它们。

注意

像Lua和Python这样的编程语言具有C/C++运行时。借助Emscripten,我们可以将运行时作为WebAssembly模块移植,并在JavaScript引擎中执行它们。这使得在JavaScript引擎上运行Lua/Python代码变得容易。因此,Emscripten和WebAssembly允许在JavaScript引擎中运行原生代码。

首先,让我们创建一个sum.cpp文件:

 // sum.cpp
extern "C" {
  unsigned sum(unsigned a, unsigned b) {
      return a + b;
  }
} 

将extern "C"视为一种类似导出机制。其中的所有函数都可以作为导出函数而不改变它们的名称。然后,我们定义了正常的sum函数,它接受两个数字并返回一个数字。

为了从sum.cpp生成类似asm.js的JavaScript代码,请使用以下命令:

$ emcc -O1 ./sum.cpp -o sum.html -sWASM=0 -sEXPORTED_FUNCTIONS='["_sum"]' 

注意

如果这是您第一次运行emcc,它可能需要几秒钟才能完成。后续运行将会更快。

我们向emcc编译器传递-O1选项,指示编译器产生较少优化的代码(我们将在本章后面看到更多优化选项)。接下来,我们传递要转换的文件,即sum.cpp。然后,使用-o标志,我们提供输出的期望名称,即sum.html。

最后,我们使用-s标志向emcc编译器发送更多信息。-s标志以键值对的形式接受参数。emcc编译器默认生成WebAssembly模块。WASM=0指示编译器生成类似asm.js的JavaScript,而不是WebAssembly。

然后,我们使用EXPORTED_FUNCTIONS选项指定导出的函数。EXPORTED_FUNCTIONS选项接受一个参数数组。为了导出sum函数,我们指定_sum。

这将生成以下代码:

/// $1 映射到 _sum 
function $1($0_1, $1_1) { 
    $0_1 = $0_1|0; 
    $1_1 = $1_1|0; 
   return $0_1 + $1_1 | 0; 
}  

注意

|0指定类型为数字。

现在在浏览器中打开sum.html并打开开发者控制台。为了调用导出的函数,我们将在控制台中运行以下表达式:

 ccall("sum", "number", "number, number", [10, 20])
// 输出 30 

ccall是从JavaScript通过C/C++代码调用导出函数的方式。该函数接受函数名称、返回值类型、参数类型,然后作为数组输入参数。这将调用sum函数以产生结果。我们将在后面的章节中了解更多关于ccall和cwrap的信息。但就目前而言,可以将ccall视为调用C函数的方式。

更多关于Emscripten源代码的信息,请访问 https://github.com/emscripten-core/emscripten。

到目前为止,我们已经看到了如何使用emscripten生成asm.js文件。现在,让我们使用emscripten创建一个在Node.js上运行的WebAssembly模块。

在Node.js中使用Emscripten运行Hello World

在本节中,我们将看到如何通过Emscripten将C/C++代码转换为WebAssembly二进制文件,并与Node.js一起运行它。

注意

如果终端报错显示emcc command not found,您的终端环境可能已被重置。要设置环境,请在emsdk文件夹内运行以下命令:

source ./emsdk_env.sh

让我们遵循Brian Kernighan的传统,写一个“Hello, world”程序,但稍作变化。我们来做一个“Hello, Web”:

  1. 首先,我们创建一个hello_web.c文件:

    $ touch hello_web.c
    
  2. 打开您喜欢的编辑器并添加以下代码:

     #include <stdio.h>
     
    int main() {
        printf("Hello, Web!\n");
        return 0;
    } 
    

这是一个简单的C程序,包含一个main函数。main函数是运行时的入口点。当使用Clang(clang sum.c && ./a.out)编译并执行这段代码时,会打印“Hello, Web!”。现在,让我们使用emcc而不是Clang(或其他编译器)来编译这段代码。

  1. 我们输入以下命令用emcc来编译代码:

     $ emcc hello_web.c
    

完成后,将生成以下文件:

  • a.out.js
  • a.out.wasm

生成的JavaScript文件非常庞大。它有2000多行,大小为109 KB。我们将在本章后面学习如何优化文件大小。

  1. 让我们使用Node运行生成的JavaScript文件,它将打印出“Hello, Web!”:

    $ node a.out.js
    Hello, Web! 
    

恭喜您!您刚刚运行了您的第一个WebAssembly二进制文件!

注意

在浏览器的世界里,二进制大小很重要。如果您的代码很庞大,即使您的算法以纳秒速度运行,也没有意义。浏览器在开始解析和编译之前,需要等待接收到所有必要的信息。因此,检查文件大小是必须的。Closure Compiler有助于进一步减小字节码大小。Closure Compiler不仅减小了代码大小,还试图使代码更高效。

生成的JavaScript文件包含了自己的运行时和配置,这些是JavaScript引擎执行JavaScript引擎内的WebAssembly模块所需的。生成的JavaScript文件为浏览器和Node.js创建了一个JavaScript模块并初始化代码:

  • 在Node.js中,生成的JavaScript文件通过从本地文件系统读取文件来创建模块。它获取传递给node命令的参数,并在创建的模块中设置它们。
  • 在浏览器中,生成的JavaScript文件通过构建请求并从URL获取字节来创建模块。浏览器从托管服务器或位置获取WebAssembly二进制文件,然后实例化模块。

生成的JavaScript文件还创建了堆栈、内存、导入和导出部分。我们将在本书后面深入了解这些部分。

这个生成的JavaScript文件被称为绑定文件。绑定文件的主要功能是创建或设置一个环境,使得JavaScript引擎内可以执行WebAssembly模块。绑定文件充当JavaScript和WebAssembly之间的翻译者。所有的值都通过这个绑定文件传入和传出。

当通过node执行JavaScript文件时,它会做以下事情。

JavaScript引擎首先加载模块,然后设置WebAssembly执行所需的常量和各种函数。然后,模块检查代码执行的位置,无论模块是在浏览器内还是在Node环境中。基于此,它获取文件。由于我们在这里通过node运行WebAssembly模块,因此它从本地文件系统获取文件。然后,模块检查调用是否提供了任何参数。如果没有,JavaScript引擎将检查是否有任何未处理/未捕获的异常。JavaScript引擎然后将print out/print err函数映射到控制台。JavaScript引擎检查模块是否加载了所有执行所需的访问权限和全局变量和导入。

模块接着初始化堆栈和其他所需常量,以及用于分别解码和编码缓冲区的解码器和编码器。编码器负责将JavaScript值转换为WebAssembly能够理解的值。解码器负责将WebAssembly值转换为JavaScript能够理解的值。

Node.js运行时然后检查文件的可用性,然后初始化文件。模块检查所有与WebAssembly相关的函数的可用性。一旦一切都初始化完毕,且模块包含所有所需函数,我们将调用run函数。

run函数实例化WebAssembly二进制文件。在这种情况下,由于我们在C中定义了main函数,因此绑定文件在实例化时直接调用main函数。

绑定文件包含ccall函数。ccall函数是对C中定义的底层函数的接口:

function ccall(ident, returnType, argTypes, args, opts)  {
  // 代码已省略
} 

ccall函数接受以下参数:

  • ident – 要调用的函数;它是在C中定义的函数标识符。
  • returnType – 函数的返回类型。
  • argTypes – 参数类型。
  • args – 随函数调用传递的参数。
  • opts – 任何其他所需的选项。

JavaScript模块除了ccall外还导出了cwrap函数。cwrap是ccall函数的封装函数。虽然ccall是函数调用,但cwrap提供了一个调用ccall的函数:

 function cwrap(ident, returnType, argTypes, opts) {
    return function() {
        return ccall(ident, returnType, argTypes,
          arguments, opts);
    }
} 

生成的WebAssembly文件包含二进制操作码,指示运行时打印“Hello, Web!”。WebAssembly文件以00 61 73 6d 01 00 00 00开头。

有关WebAssembly规范的更多信息,请访问 https://webassembly.github.io/spec/。

到目前为止,我们已经看到了如何生成一个在Node.js上运行的WebAssembly模块。让我们使用emscripten在浏览器中创建一个WebAssembly模块来运行。

在浏览器中使用Emscripten运行Hello World

在本节中,我们将看到如何通过Emscripten将C/C++代码转换为WebAssembly二进制文件,并在浏览器中运行它。

注意

如果终端显示找不到emcc命令,那么您可能忽略了设置环境变量。要设置环境变量,请在emsdk文件夹内运行以下命令:source ./emsdk_env.sh

让我们使用使用Emscripten生成asm.js部分中使用的同样的代码示例。现在,我们不仅运行emcc,还传递-o选项并指示emcc生成.html文件:

$ emcc hello_web.c -o helloweb.html

完成后,将生成以下文件:

  • helloweb.js
  • helloweb.wasm
  • helloweb.html

类似于Node示例,生成的JavaScript文件非常庞大。我们将在本章后面学习如何优化文件大小。

注意

-o选项确保所有生成的文件都具有名称helloweb。

为了在浏览器中运行生成的HTML文件,我们需要一个Web服务器。Web服务器通过HTTP协议提供HTML文件。解释Web服务器及其工作原理超出了本书的范围;有关更多详细信息,请参阅Web服务器 - 维基百科。

Python提供了一个简单的方法来运行Web服务器。为了使用Python运行Web服务器,请运行以下命令:

$ python -m http.server <端口号>

打开http://localhost:<端口号>/helloweb.html在浏览器中查看WebAssembly的运行情况。

Figure 2.2 – Browser running WebAssembly

图 2.2 - 运行 WebAssembly 的浏览器

当通过浏览器执行 JavaScript 文件时,它会输出 Hello, Web!。唯一的区别在于,它不是从文件系统加载 WASM 文件,而是通过 XHR 加载。一旦一切初始化完成,模块包含了所有所需的函数,我们将调用 run 函数。run 函数会实例化 WebAssembly 二进制文件。在这个案例中,由于我们用 C 语言定义了 main 函数,所以绑定文件在实例化时直接调用 main 函数。

Emscripten 还提供了 emrun 来运行 HTML 文件。更多信息请查看。

有关部署 Emscripten 编译页面的更多信息,请访问 https://emscripten.org/docs/compiling/Deploying-Pages.html。

我们已经使用 Emscripten 生成了 WebAssembly 模块。让我们继续探索 emsdk 还能做些什么。

探索 emsdk 中的其他选项

emsdk 是一个一站式的工具,用于安装、维护和管理使用 Emscripten 所需的所有工具和工具链。emsdk 使得引导环境、升级到最新版本、切换到不同版本、更改或配置各种工具等变得更加简单。

emsdk 命令位于 emsdk 文件夹中。进入 emsdk 文件夹并运行 emsdk 命令。

注意

在本章节中的所有命令,对于 *nix 系统,使用 ./emsdk,对于 Windows,使用 emsdk。

要找出 emsdk 命令中可用的各种选项,请运行以下命令:

$ ./emsdk --help
emsdk: 可用命令:
emsdk list [--old] [--uses] - 列出工具
emsdk update - 将 emsdk 更新到最新版本。
emsdk update-tags - 从 GitHub 仓库获取最新标签。
emsdk install - 安装工具和 SDK。
emsdk uninstall - 卸载先前安装的工具和 SDK。
emsdk activate - 激活当前安装的版本。

一个 emsdk 命令的格式如下:

emsdk <option> <工具/SDK> --<flags>

emsdk 命令包括以下内容:

  • <option>

这可以是以下之一:list、update、update-tags、install、uninstall 或 activate。

  • <工具/SDK>

这指的是库,包括 Emscripten 和 LLVM。SDK 指的是 emsdk 本身。

  • --<flags>

这指的是各种配置选项。

让我们探索 emsdk 命令支持的每一个选项和标志。

列出工具和 SDK

在这里,我们展示如何列出 emsdk 中可用的工具和 SDK。运行以下命令:

$ ./emsdk list
 
The *recommended* precompiled SDK download is 2.0.6 
  (4ba921c8c8fe2e8cae071ca9889d5c27f5debd87).
 
To install/activate it, use one of:
        latest                  [default (llvm) backend]
        latest-fastcomp         [legacy (fastcomp) backend]
 
Those are equivalent to installing/activating the following:
         2.0.6             INSTALLED
         2.0.6-fastcomp
 
All recent (non-legacy) installable versions are:
         2.0.6    INSTALLED
         ...
 
The additional following precompiled SDKs are also available 
  for download:
         sdk-fastcomp-1.38.31-64bit
 
The following SDKs can be compiled from source:
         sdk-upstream-master-64bit
          ...
The following precompiled tool packages are available for 
  download:
        ...
     *     node-12.18.1-64bit         INSTALLED
     *     python-3.7.4-2-64bit       INSTALLED
           emscripten-1.38.30
        ...
The following tools can be compiled from source:
           llvm
           clang
           emscripten
           binaryen
 
Items marked with * are activated for the current user.
 
To access the historical archived versions, type 'emsdk list 
  --old'
 
Run "git pull" followed by "./emsdk update-tags" to pull 
  in the latest list. 
 open_url("file-tL0suvKqhxGxCrTb2bA9LZZ7")

emsdk list 命令列出了所有可用的工具包和 SDK。这些工具和 SDK 的列表包括 LLVM、Clang、Emscripten 和 Binaryen 的最近几个版本。它们甚至包括了 Node 版本 8 和 12,以及 Python 3.7。emsdk 负责维护和管理 emsdk。这意味着我们需要了解我们正在使用的当前版本的信息以及如何更新它。emsdk list 命令还提供了关于 SDK 组件的更多详细信息,以及那些从源代码编译的列表。

管理工具和 SDK

emsdk 提供了安装、更新和卸载工具和 SDK 的选项。

为了安装工具、SDK 或 emsdk 本身,请使用以下命令:

$ ./emsdk install <要安装的工具/SDK>

要安装 SDK 的最新版本,可以运行以下命令:

./emsdk install latest

注意

latest 指的是 emsdk 的最新版本。

要使用 emsdk install 命令安装多个工具,请使用以下命令:

./emsdk install <tool1> <tool2> <tool3>

您也可以为 install 命令指定多个选项。您可以这样传递选项给 install 命令:

 ./emsdk install [options] <tools / SDK>

可用的各种 options 有:

  • 构建所用的核心数
  • 构建类型
  • 工具和 SDK 的激活
  • 卸载

构建所用的核心数

初次设置将花费很长时间来构建和安装所需的工具和 SDK。根据您的需求,您可以控制构建和安装所需工具和 SDK 的核心数:

./emsdk install -j<用于构建的核心数> <tools 
  / SDK> 

构建类型

您可以指导 emsdk 使用什么类型的构建来使 LLVM 表现出来:

./emsdk install --build=<type> <tools / SDK>

type 接受以下选项:

  • 调试

    • 用于调试。
    • 生成符号文件。
    • 最终构建不会产生优化、快速代码。
  • 发布

    • 这种类型将生成优化、快速代码。
  • MinSizeRel

    • 与发布相同。
    • 这种类型将最小化大小并最大化速度。
    • 使用优化选项,如 -O1(最小化大小)和 -O2(最大化速度)。
  • RelWithDebInfo

    • 与发布相同。
    • 这种类型还会生成符号文件,有助于调试。

激活工具和 SDK

工具和 SDK 安装后,我们可以激活不同的版本来使用它们。activate 命令生成必要的配置文件,将路径映射到构建的可执行文件。

要激活工具和 SDK,请运行以下命令:

./emsdk activate <要激活的工具/SDK>

activate 命令接受一些选项,如下:

  • --embedded – 这个选项确保所有构建的文件、配置、缓存和临时文件都位于 emsdk 命令所在的目录内。

如果没有指定,这个命令会将配置文件移动到用户的主目录。

  • --build=<type> – 类似于 LLVM 支持的构建类型。例如,调试、发布、MinSizeRel、RelWithDebInfo。

卸载工具和 SDK

要卸载工具和 SDK,我们可以运行以下命令:

./emsdk uninstall <要卸载的工具/SDK> 

有关工工具的更多信息请访问 Emscripten 文档。

我们已经探讨了如何使用 emsdk 来管理工具和 SDK;接下来让我们探索由 Emscripten 提供的各种优化功能。

理解不同级别的优化

C/C++ 程序通过 Clang 或 GCC 编译器编译并转换为本地代码。Clang 或 GCC 编译器根据目标将 C/C++ 程序转换。这里的目标指的是代码执行的最终机器。emcc 内置了 Clang 编译器。emcc 编译器负责将 C 或 C++ 源代码转换为 LLVM 字节码。

在本节中,我们将看到如何提高生成的 WebAssembly 二进制代码的优化和代码大小。

为了提高效率和生成的代码大小,Emscripten 编译器提供了以下选项:

  • 优化
  • 闭包编译器

首先讨论优化。

优化

编译器的目标是减少编译成本,即编译时间。使用 -O 优化标志,编译器试图在牺牲编译时间的情况下改进代码大小和/或性能。在编译器优化方面,代码大小和性能是相互排斥的。编译时间越快,优化程度越低。要指定优化,我们使用 -O<0/1/2/3/s/z> 标志。每个选项包括各种断言、代码大小优化和代码性能优化等。

以下是各种优化选项:

  • -O0 – 这是默认选项,是实验的完美起点。这个选项意味着“无优化”。这个优化级别编译最快,生成最可调试的代码。这是基本的优化级别。这个选项试图内联函数。
  • -O1 – 这个选项添加简单的优化,并试图生成最小的代码大小。这个选项删除了生成代码中的运行时断言,并且比 -O0 选项构建得更慢。这个选项还试图简化循环。
  • -O2 – 这个选项添加比 -O1 更多的优化。它比 -O1 慢,但生成的代码比 -O1 选项更优化。这个选项基于 JavaScript 优化优化代码,并删除不属于 JavaScript 模块的代码。这个选项删除内联函数,vectorize-loop 选项被设置。这个选项添加适度的优化。这个选项还增加了死代码消除。

向量化将指示处理器分块执行操作,而不是一次一个。

  • -O3 – 这个选项添加更多选项,编译时间更长,并生成比 -O2 选项更优化的代码。

这个选项生成最佳的生产就绪代码。这个选项就像 -O2,除了它启用了更长时间执行的优化,或可能生成更大的代码(试图使程序运行得更快)。

  • -Os – 这个选项类似于 -O2。它增加了额外的优化并减少了代码大小。减少代码大小反过来会降低性能。这个选项生成的代码比 -O2 小。
  • -Oz – 这个选项类似于 -Os,但进一步减少了代码大小。这个选项需要更长的编译时间来生成二进制代码。

现在我们将探索 Emscripten 提供的各种优化选项:

  1.  open_url("file-4WE3SZEZqZrx3gAR8Aj5Svir")
    

    好的,让我们继续对您提供的内容进行润色翻译。


    1. 首先,我们创建一个名为 optimization_check 的 C 文件:

      $ touch optimization_check.c
      
    2. 然后,打开您最喜欢的编辑器并添加以下代码。以下是一个简单的 C 文件,包含一个 main 函数和其他几个函数:

      #include <stdio.h>
       int addSame(int a) {
          return a + a;
      }
       
      int add(int a, int b) {
          return a + b;
      }
       
      int main() {
          printf("Hello, Web!\n");
       
          int a;
          int sum = 0;
          /* for 循环执行 */
          for( a = 0; a < 20; a = a + 1 ){
             sum = sum + a;
          }
           addSame(sum);
           add(1, 2);
           return 0;
      } 
      
    3. 接着我们使用 emcc 将其编译为 WebAssembly 代码:

      $ time emcc optimization_check.c
      emcc optimization_check.c  0.32s user 0.14s system 
        90% cpu 0.514 total 
      
    4. 然后,检查生成的文件大小:

       $ l
      324B optimization_check.c
      13K a.out.wasm
      109K a.out.js 
      

    我们可以看到生成的 WebAssembly 文件约为 13 KB,编译总共用时 0.514 秒。这是快速的编译,但代码大小却很大。

    在编译器的世界里,编译越快,代码大小越大,执行速度越慢。

    1. 现在,让我们使用 -O1 选项进一步优化它:

      $ time emcc -O1 optimization_check.c
      emcc -O1 optimization_check.c  0.31s user 0.13s system
        86% cpu 0.519 total 
      

    检查生成的文件大小:

    $ l
    324B optimization_check.c
    3.4K a.out.wasm
    59K a.out.js 
    

    生成的 WebAssembly 文件约为 3.4 KB(比 -O0 版本小 3.8 倍),用时几乎相同,约为 0.519 秒。

    1. 现在,让我们使用 -O2 选项进一步优化它:

      $ time emcc -O2 optimization_check.c
      emcc -O2 optimization_check.c  0.53s user 0.16s system
        111% cpu 0.620 total 
      

    检查生成的文件大小:

    $ l
    324B optimization_check.c
    2K a.out.wasm
    20K a.out.js 
    

    生成的 WebAssembly 文件约为 2 KB(比 -O0 小约 6.5 倍),用时约为 0.62 秒。

    1. 现在,让我们使用 -O3 选项进一步优化它:

      $ time emcc -O3 --profiling optimization_check.c
      emcc -O3 --profiling optimization_check.c  1.03s user
        0.21s system 110% cpu 1.117 total 
      

    有关 --profiling 标志的更多信息,请访问 https://emscripten.org/docs/tools_reference/emcc.html#emcc-profiling。

    检查生成的文件大小:

    $ l
    324B optimization_check.c
    2.0K a.out.wasm
    17K a.out.js 
    

    生成的 WebAssembly 文件大小与 -02 相同,但生成的 JavaScript 文件少了 3 KB,编译用时约为 1.117 秒。

    1. 现在,让我们使用 -Os 选项进一步优化它:

      $ time emcc -Os optimization_check.c
      emcc -Os optimization_check.c  1.03s user 0.22s system
        46% cpu 2.655 total 
      

    检查生成的文件大小:

    $ l
    324B optimization_check.c
    1.7K a.out.wasm
    14K a.out.js 
    

    生成的 WebAssembly 文件约为 1.7 KB(比 -O0 小约 7.5 倍),用时几乎为 2.655 秒。

    1. 现在,让我们使用 -Oz 选项进一步优化它:

      $ time emcc -Oz optimization_check.c
      emcc -Oz optimization_check.c  1.03s user 0.21s system
        110% cpu 1.123 total 
      

    检查生成的文件大小:

    $ l
    324B optimization_check.c
    1.7K a.out.wasm
    14K a.out.js 
    

    生成的 WebAssembly 文件约为 1.7 KB(比 -O0 小约 7.5 倍),用时约为 1.123 秒。

    接下来,我们将看到 Emscripten 编译器提供的另一种提高效率和减小生成代码大小的方法:闭包编译器(Closure Compiler)。

    闭包编译器(Closure Compiler)

    闭包编译器是一种将 JavaScript 编译为更好 JavaScript 的工具。它解析、分析、移除死代码、重写并缩小 JavaScript。使用闭包编译器对生成的绑定 JavaScript 文件和 WebAssembly 模块进行进一步优化。使用闭包编译器,我们可以对 Emscripten 代码进行更好的优化。为了进一步优化 WebAssembly 模块和 JavaScript,我们可以使用 --closure <optimization type>。

    optimization 类型有以下选项:

    • --closure 0 – 这个选项不添加闭包编译器优化。
    • --closure 1 – 这个选项减少了生成的 JavaScript 代码大小。这个选项不优化 asm.js 和 WebAssembly 二进制文件。这增加了额外的编译步骤,从而增加了编译时间。
    • --closure 2 – 这个选项优化 JavaScript、asm.js,但不是 WebAssembly 二进制文件,并大幅减少 asm.js 文件的代码大小。

    我们将使用 –closure 1 选项与 –O3/s Emscripten 优化选项一起优化 WebAssembly 二进制文件:

    $ time emcc -O3 --closure 1 optimization_check.c
    emcc -O3 --closure 1 optimization_check.c  2.40s user 0.42s 
      system 105% cpu 2.681 total 
    

    生成的文件大小如下:

     $ l
    324B optimization_check.c
    1.8K a.out.wasm
    6.5K a.out.js 
    

    与 emcc –O3 一起,我们传递 –closure 1 来进一步优化生成的文件。闭包编译器将 JavaScript 文件大小与 emcc -O3 选项相比减少了 50%,编译用时为 2.681 秒:

    time emcc -Os --closure 1 optimization_check.c
    emcc -Os --closure 1 optimization_check.c  2.53s user 0.42s 
      system 106% cpu 2.778 total 
    

    让我们列出当前文件夹中的文件,以检查生成的文件及其大小:

    $ l
    324B optimization_check.c
    1.7K a.out.wasm
    6.5K a.out.js 
    

    与 emcc –Os 一起,我们传递 –closure 1 来进一步优化生成的二进制文件。闭包编译器在 emcc -Os 选项下将 .wasm 文件大小减小了一点,编译用时为 2.778 秒。

    注意

    在为大小优化时,尝试同时使用 -O3 或 -Os 与 --closure 1 来优化 JavaScript 和 WebAssembly 模块。

    有关各种选项和标志的更多信息,请访问 https://emscripten.org/docs/tools_reference/emcc.htmlhttps://clang.llvm.org/docs/CommandGuide/clang.html。

    有关可用优化选项的更多信息,请访问 https://docs.microsoft.com/en-us/cpp/build/reference/o-options-optimize-code?view=vs-2017。

    了解更多关于闭包编译器的信息,请访问 https://developers.google.com/closure/compiler。

    了解更多关于使用 Emscripten 优化大型代码库的信息,请访问 https://emscripten.org/docs/optimizing/Optimizing-Code.html#very-large-codebases。

    总结

    在本章中,我们学习了如何安装和使用 Emscripten 将 C/C++ 编译成 WebAssembly 模块。我们还探讨了 emsdk 工具和在生成 WebAssembly 模块时的各种优化级别。在下一章中,我们将探索 WebAssembly 模块。

windows下和linux 安装emscripten 1.下载emsdk git clone https://github.com/emscripten-core/emsdk.git 2.进入emsdk目录 cd emsdk 3.更新emsdk,确保是最新版 emsdk update 4.安装 emsdk install latest报错(因为从谷歌中下载,cmd中命令形式可能链接不到吧) 4.1解决方法:修改emsdk/emsdk.... 阅读详情

相关推荐

Emscripten之基础使用

一、前言 随着WebAssembly技术的发展,asm.js的竞争力已经逐渐被削弱了,所以Emscripten进一步与Binaryen结合,形成基于LLVM构建的WebAssembly后端。现如今,我们已经可以通过Emscripten工具链直接构建Wasm应用了。 有兴趣了解WebAssembly与asm.js的可以参考以下资料: asm.js 阮一峰《asm.js和Emscripten入...

可乐林的博客 5374

Emscripten的研究与学习 --- 初探Emscripten

该篇文章主要记录Emscripten开发环境的搭建,包括windows、linux(ubuntu14);记录环境搭建过程中遇到的各种坑。

VitalityShow(网络通讯) 5088

Emscripten之安装SDK

一、Emscripten简介 Emscirpten是一套基于LLVM构建的编译器工具链,通过该工具链我们可以将基于C/C++语言编写的传统应用程序源代码编译成asm.js或者WebAssembly模块等,可以供Web浏览器使用。 二、安装依赖 这里介绍的是在Ubuntu16.04 X64系统下安装Emscripten SDK的方法。Emscripten SDK(以下称emsdk)中已经集成了cla...

可乐林的博客 4947

Emscripten 指南:概念与使用

Emscripten是将C/C++代码编译为WebAssembly和JavaScript的开源工具链。它支持将现有C/C++应用移植到Web环境,提供文件系统模拟和OpenGL转换功能。安装需要Python、Git和CMake等工具,通过emsdk进行安装管理。基础使用包括编译C程序为可运行的网页,生成Wasm二进制和JS加载器。进阶功能包含多种编译优化选项、C与JS互调,以及项目集成方案。常见问题的解决方案涉及虚拟文件系统访问、内存检测和调试技巧。

xiaobangkeji的博客 800

WebAssembly和Emscripten工作整理

作者/云荒杯倾 写在前面 之前做过一段时间的WebAssembly的研究,写过几个WebAssembly Demo,并且阅读并翻译了很多篇Emscripten官方文档,今天对这些东西做一个总结。 如果有需要对这块知识了解的同学,就可以按照这篇文章里的资料顺序来学习。 主要是以链接形式提供,并附上简短的说明。 WebAssembly方面 1.WebAssembly入门 这是...

林飞叶 2498

基于4G cat.1的低功耗车牌识别摄像头模组介绍

在消费类摄像头领域,4G低功耗相机已经非常普遍,在可视门锁,婴儿看护,户外监控等领域都获得了很好的应用.但是在工业领域,低功耗相机的应用还不是那么广泛.这里要介绍一款基于4G cat.1的低功耗车牌识别摄像头模组,在待机状态只有MCU和毫米波雷达以1Hz的频率工作,功耗低至500uA,并可以通过4G模块远程唤醒模组.

bindaz的专栏 1647

Emscripten - Emscripten 运行时环境

Emscripten运行时环境摘要:Emscripten为C/C++代码在浏览器环境运行提供兼容层,通过虚拟文件系统实现文件访问,支持SDL等API处理输入输出。浏览器主循环需特殊处理,推荐使用emscripten_set_main_loop()实现异步循环而非传统无限循环。应用加载时先预加载资源,依赖完成后才执行main()。开发者应注意浏览器环境限制,如异步文件访问、主线程协作等特性。

696

从入门到精通:dirmap 高级 Web 目录扫描实战指南

本文提供了一份从环境搭建到高级配置的dirmap Web目录扫描实战指南。详细解析了工具安装、核心配置文件dirmap.conf的深度调优,包括递归扫描、四种扫描模式(字典、爆破、爬虫、Fuzz)的实战应用,并演示了分阶段资产发现的完整工作流程,帮助安全人员高效发现隐藏目录与敏感文件。

rnn9storyteller的博客 479

Emscripten - Emscripten 教程

Emscripten 简明教程 本教程介绍了 Emscripten 的基本使用方法,这是一个将 C/C++ 代码编译为 JavaScript/WebAssembly 的工具链。主要内容包括: 安装与验证:确保正确安装 Emscripten 并通过 emcc -v 验证环境 基础编译:展示如何将简单的 C 程序(hello_world.c)编译为 JavaScript/WebAssembly 生成 HTML:使用 -o 参数生成可直接在浏览器中运行的 HTML 文件 文件操作:说明如何在虚拟文件系统中访问文件

1272

光模块的封装工艺有哪些?

COB封装传统的单路10Gb/s或25Gb/s速率的光模块采用SFP封装将电芯片和TO封装的光收发组件焊接到PCB板上组成光模块。但对于40G及以上速率的高速光模块,受激光器速率限制(多为25G),主要通过多通道并行实现,如40G由4×10G实现,而100G则由4×25G实现。蝶形封装:壳体通常为长方体,结构及实现功能通常比较复杂,可以内置制冷器、热沉、陶瓷基块、芯片、热敏电阻、背光监控,并且可以支持所有以上部件的键合引线。BOX封装属于蝶形封装的一种,用于多通道并行封装。

WaytoICT- Explore ICT Technology, Build Your Tech Path 3806

CrackerXI+脱壳实战:解决iOS应用逆向中的加密文件问题

本文详细介绍了如何使用CrackerXI+工具对iOS应用进行脱壳,解决App Store应用因FairPlay DRM加密而无法进行静态分析的难题。通过图形化界面一键操作,CrackerXI+能高效获取解密后的可执行文件,为逆向工程奠定基础。文章涵盖工具选型、实战步骤及常见问题排查,是iOS逆向入门与进阶的实用指南。

seed的博客 256

Emscripten运行main和Emscripten_set_main_loop

一、main()函数与生命周期 对于Emscripten来说,main()函数既不是必需的,也不控制运行时生命周期。 1、test.c #include <stdio.h> #include <emscripten.h> //extern "C" { EMSCRIPTEN_KEEPALIVE int show_answer() { return 42; } int main() { printf("hello world\n"); return 1; } //}

qq_34754747的博客 1699

机器视觉工程师如何进行高速运动物体捕获

硬件方面使用高帧率相机(如工业相机、高速摄像机)确保充足的光照条件使用高性能计算平台减少处理延迟软件方面背景减除技术快速分离运动物体卡尔曼滤波预测物体轨迹ROI技术减少计算量多线程处理提高实时性实际应用中的关键考量针对特定场景调整参数(如阈值、滤波器参数等)平衡计算资源与实时性要求结合特定领域知识优化算法(如物体运动特性)上述示例代码实现了一个基础的高速物体跟踪系统,通过背景减除和卡尔曼滤波实现对高速物体的检测和跟踪。

zhangzhechun_02的博客 624

Windows下安装 Emscripten 详细过程

Windows下安装 Emscripten 详细过程

世界那么大,我想去看看~【随心更新,看世界去了😄】 7176

【Java基础篇】Java重要特性,JDK,JRE,JVM区别和联系,环境变量

JDK使用时的执行流程: • 开发者视角(需要开发java程序):需要安装JDK a. 首先使用JDK调用Tools&Tool APIs(开发者工具)编写好Java程序--xxx.java b. 再次调用Tools&Tool APIs中的javac.exe(编译程序)来编译.java文件(将java文件编译成字节码.class文件) c. 调用java.exe来启动JRE d. 在JRE上运行JAVA字节码(加载特定的.class文件,调用这个class文件中的main方法

Yaoyao2024的博客 2163

第4章:外包接单全攻略——Upwork/电鸭/猪八戒从0到第一单

> - 三个外包平台的详细对比(适合人群、抽成、防骗) > - 每个平台的Profile优化模板(可直接复制修改) > - 用AI写Proposal的3个Prompt模板(我实测回复率提升50%) > - 报价策略与防骗指南(附5个危险信号) > - 我的第一单复盘:从注册到收款的全过程(含聊天记录脱敏)

sfishfly的博客 574

Windows下安装Emscripten教程

首先要安装Emscripten环境需要先安装python和git环境;python和git环境安装简单自行百度下。 安装完成python和git置好环境变量后就可以开始安装Emscripten了,首先需要将emsdk的git项目克隆到本地。 Emscripten SDK的git地址:https://github.com/emscripten-core/emsdk,自行下载; 也可以用cmd执行如下命令: git clone https://github.com/juj/emsdk.git 当拷贝

wangx893175022的博客 7646

CAPL编程规范与最佳实践

通过本文的学习,读者应该对CAPL编程规范与最佳实践有了初步的了解,并能够编写高质量的CAPL脚本。在实际项目中,CAPL的应用非常广泛,希望读者能够通过不断的学习和实践,掌握更多的CAPL技巧,提高自己的开发能力。

闲人编程的博客 1747

Emscripten - 与代码交互

Emscripten JavaScript与C/C++交互方法 Emscripten提供了多种方式实现JavaScript与编译后的C/C++代码相互调用: JavaScript调用C/C++: 使用ccall/cwrap调用C函数 直接调用编译后的函数(需处理类型转换) 通过Embind/WebIDL绑定调用C++类 C/C++调用JavaScript: 使用emscripten_run_script() 通过EM_JS/EM_ASM内联调用 实现JavaScript版本的C API 使用函数指针或Emb

924

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Emscripten大项目构建:CMake与Emscripten集成方案

你是否在为C/C++项目编译到WebAssembly(WASM,网页汇编)时遇到构建流程复杂、工具链配置繁琐的问题?本文将详解如何通过CMake与Emscripten的无缝集成,实现跨平台项目的高效构建,让你轻松掌握大项目的WebAssembly化方案。读完本文,你将获得从环境配置到高级优化的完整实践指南,以及解决常见构建难题的实用技巧。 ## 准备工作:环境配置与工具链安装 在开始集成前,需...

gitblog_01024的博客 455

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

从Native到Web(五), emscripten学习笔记: 初体验

在《传统3D游戏引擎的Web化》中, 当时我还说emscripten不够成熟, 可是短短几个月它就有了很大的进步, 可用性甚至超过了flascc!在GDC2013上, Unreal发布了基于emscripten的移植Demo, 据说只用了4天时间, 足以看出这个移植过程的平滑floh前几天发布了一个PPT: 《C++ on the Web: Run your big 3D game in the

逍遥剑客 1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Emscripten中的WebAssembly系统接口:WASI扩展

WebAssembly系统接口(WASI,发音为"wasi")是一套标准化的系统调用API,旨在为WebAssembly(Wasm)提供安全、可移植的系统访问能力。作为WebAssembly生态系统的重要组成部分,WASI定义了文件系统、网络、时钟等核心系统功能的抽象接口,使Wasm模块能够在各种环境中一致地运行,而不仅仅局限于浏览器。 Emscripten作为WebAssembly的主要编译器...

gitblog_00993的博客 1111

Emscripten - Pthreads 支持

Emscripten通过SharedArrayBuffer支持WebAssembly多线程编程,实现了POSIX threads API。编译时需添加-pthread参数,并可选设置线程池大小。需要注意主线程阻塞问题,建议使用PROXY_TO_PTHREAD模式或异步化处理。由于浏览器限制,存在线程创建延迟、信号不支持等行为差异,且内存增长与多线程组合时性能可能下降。推荐使用mimalloc分配器优化多线程性能。测试需在Firefox Nightly等支持SharedArrayBuffer的浏览器中进行。

884

WebAssembly002 emcc Emscripten js端传入数组给c++

【代码】WebAssembly002 emcc Emscripten js端传入数组给c++

ResumeProject的博客 1211

Emscripten - Emscripten 测试套件

Emscripten提供了全面的测试套件和基准测试工具,帮助开发者验证功能。测试分为核心测试(多种优化配置)和其他专用测试套件(浏览器、网络等)。可通过runner脚本运行特定测试或模式,支持通配符匹配和跳过测试。测试失败时可使用EMCC_DEBUG调试模式获取详细信息。基准测试套件包含多种现实应用案例和标准基准,可评估性能和代码大小。测试套件提供了丰富的调试选项,如保存临时文件、设置运行时长等,便于问题排查。

1018

Emscripten - 音频

Emscripten 内置了 OpenAL 1.1 API 的实现,后端使用 Web Audio API。移植到 OpenAL 的应用基本都能“开箱即用”,无需额外操作。只需在链接时加上-lopenal参数即可。不过,有一些实现相关的细节需要注意,这里会进行说明。过去使用 OpenAL 时不需要给编译器加额外参数,但现在必须显式指定-lopenal,未来这将!

1107
上一篇: 第一章: 理解 LLVM
下一篇: 第 6 章:并发系统编程与C++
段舸
博客等级 码龄3年 533粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值