0

0

C++ WebAssembly编译 Emscripten工具链安装

P粉602998670

P粉602998670

发布时间:2025-08-27 14:36:01

|

556人浏览过

|

来源于php中文网

原创

答案:通过emscripten工具链可将c++代码编译为webassembly,实现浏览器中高效运行。安装使用emsdk脚本管理工具链,经安装、激活、环境配置后,用emcc编译c++代码并生成html、js、wasm文件,借助本地服务器运行,实现c++与javascript交互。

c++ webassembly编译 emscripten工具链安装

将C++代码带入Web浏览器,听起来像是魔法,但通过WebAssembly和Emscripten工具链,这已经成为现实。简单来说,Emscripten就是一座桥梁,它能把你的C++代码编译成浏览器能理解的WebAssembly模块,同时生成必要的JavaScript胶水代码,让一切在Web环境中顺畅运行。

解决方案

Emscripten工具链的安装,说实话,比我想象中要简单不少,但也有一些小坑需要注意。我个人建议使用

emsdk
这个官方提供的脚本来管理,因为它能帮你处理版本、依赖等问题,省心很多。

  1. 获取

    emsdk
    : 首先,你需要从GitHub克隆
    emsdk
    仓库。打开你的终端或命令行工具,输入:

    git clone https://github.com/emscripten-core/emsdk.git
    cd emsdk

    这一步其实就是把管理脚本和相关配置拉到本地,不涉及实际的工具链文件。

  2. 安装与激活最新工具链: 进入

    emsdk
    目录后,运行以下命令来安装最新的Emscripten工具链。这会下载并安装所有必需的组件,包括LLVM、Clang、Binaryen等。

    ./emsdk install latest
    ./emsdk activate latest

    install
    命令负责下载,
    activate
    命令则会将相应的工具链版本设置为当前活跃版本,并配置好环境。这个过程可能需要一些时间,取决于你的网络状况,毕竟要下载不少东西。

    立即学习C++免费学习笔记(深入)”;

  3. 配置环境: 为了让你的系统能够找到

    emcc
    (Emscripten的编译器驱动)等命令,你需要将Emscripten的环境变量添加到你的shell配置中。
    emsdk
    已经为你准备好了脚本:

    • Linux/macOS:
      source ./emsdk_env.sh
    • Windows (PowerShell):
      .\emsdk_env.ps1
    • Windows (cmd):
      emsdk_env.bat

      为了让这些环境变量永久生效,你可能需要将

      source ./emsdk_env.sh
      (或其他对应脚本)添加到你的
      .bashrc
      ,
      .zshrc
      .profile
      文件中。我通常会选择在需要使用时手动
      source
      一下,避免全局环境被不必要的变量污染,但对于频繁开发者来说,自动加载更方便。

  4. 验证安装: 安装完成后,简单地运行

    emcc -v
    来检查Emscripten是否正确安装并被系统识别。如果一切顺利,你会看到Emscripten的版本信息以及它所使用的Clang版本。

    emcc -v

    如果出现

    command not found
    ,那多半是环境配置没生效,或者你忘记了
    source
    脚本。

为什么选择Emscripten进行C++到WebAssembly的编译?

在我看来,Emscripten之所以成为C++到WebAssembly编译的黄金标准,并非偶然。它不仅仅是一个编译器前端,更是一个成熟的生态系统。首先,它的历史悠久,从asm.js时代就开始耕耘,积累了大量的经验和优化策略。这意味着它在处理复杂的C++项目、链接各种库方面,有着无与伦比的稳定性和兼容性。

其次,Emscripten提供了非常全面的API模拟层。你可能会想,浏览器环境哪有文件系统、线程这些概念?但Emscripten通过其运行时库(

emscripten.h
)和JavaScript胶水代码,巧妙地模拟了POSIX文件系统、OpenGL/WebGL图形接口,甚至多线程(基于Web Workers和SharedArrayBuffer),这让许多原生的C++应用几乎无需修改就能移植到Web上。我个人就曾用它将一个基于SDL2的桌面游戏移植到浏览器,那种“几乎不用改代码”的体验,真是让人印象深刻。

最后,它生成的JavaScript胶水代码非常智能,不仅负责加载和实例化WebAssembly模块,还处理了C++和JavaScript之间的数据类型转换、函数调用等繁琐细节。这大大降低了开发者将C++逻辑与前端JavaScript界面集成的门槛。虽然有时候这些胶水代码看起来有点复杂,但它确实把最难的部分给抽象掉了。

Emscripten编译流程中的常见挑战与应对策略

使用Emscripten进行编译,虽然强大,但也并非一帆风顺,总会遇到一些让我挠头的问题。

一个常见的挑战是依赖管理。如果你的C++项目依赖了多个第三方库,尤其是那些本身就比较复杂的原生库(比如OpenCV、Boost等),那么将它们一起编译到WebAssembly可能会很棘手。你可能需要手动编译这些库的Emscripten版本,或者使用Emscripten提供的

port
系统。
port
系统是一个预编译的库集合,能帮你省去不少麻烦,但并非所有库都有现成的
port
。当遇到没有
port
的库时,我通常会尝试阅读其构建系统(CMake、Autotools)的文档,并用
emconfigure
emmake
来驱动编译,这相当于在Emscripten的环境下运行原生的构建命令。

性能优化也是一个需要持续关注的点。WebAssembly虽然快,但与原生执行还是有差距。特别是内存使用,浏览器环境对内存的限制比桌面应用更严格。我发现,过度使用C++标准库中的某些容器(如

std::map
)或频繁的堆内存分配,可能会导致性能下降。这时候,就需要更细致地分析内存分配模式,甚至考虑使用Emscripten提供的
EM_ASM
宏直接在C++中嵌入JavaScript代码,进行一些浏览器特有的优化。调试性能问题时,浏览器的开发者工具(尤其是Memory和Performance面板)是我的好帮手,它们能帮你看到WebAssembly模块的内存占用和函数执行时间。

Reachout.ai
Reachout.ai

一个AI驱动的视频开发平台,专为忙碌的企业家和销售团队打造

下载

调试WebAssembly代码,刚开始也让我有点摸不着头脑。直接调试

.wasm
文件几乎不可能。Emscripten支持生成DWARF调试信息,配合浏览器(如Chrome)的开发者工具,你可以在源代码级别进行调试,设置断点、查看变量。这需要你在编译时加上
-g
-g4
等调试选项。虽然不如原生IDE那么流畅,但至少能让你一步步跟踪代码执行,找出问题所在。

Emscripten工具链安装后如何进行简单的C++项目编译与运行?

既然工具链已经就绪,我们不妨来跑一个最简单的“Hello, WebAssembly!”例子。这能让你对整个流程有个直观的感受。

首先,创建一个名为

hello.cpp
的C++源文件,内容如下:

#include <iostream>
#include <emscripten.h> // 引入Emscripten特有的头文件

// 一个简单的C++函数,会被导出到JavaScript
extern "C" {
    EMSCRIPTEN_KEEPALIVE
    void greet(int times) {
        for (int i = 0; i < times; ++i) {
            std::cout << "Hello from C++ WebAssembly!" << std::endl;
        }
    }

    EMSCRIPTEN_KEEPALIVE
    int add(int a, int b) {
        return a + b;
    }
}

int main() {
    std::cout << "C++ main function started." << std::endl;
    // 在这里调用greet,但通常我们更倾向于从JS调用导出的函数
    // greet(1);
    return 0;
}

这里有几个关键点:

  • #include <emscripten.h>
    :这是Emscripten特有的头文件,提供了像
    EMSCRIPTEN_KEEPALIVE
    这样的宏。
  • extern "C"
    :确保C++函数以C语言的调用约定导出,避免名字修饰(name mangling),这样JavaScript才能更容易地找到它们。
  • EMSCRIPTEN_KEEPALIVE
    :这个宏告诉Emscripten编译器,即使某个函数在C++代码中没有被直接调用,也要保留它,并将其导出到WebAssembly模块中,以便JavaScript可以调用。

接下来,我们用

emcc
来编译它。在终端中,进入
hello.cpp
所在的目录,执行:

emcc hello.cpp -o hello.html -s EXPORTED_FUNCTIONS="['_greet', '_add']" -s EXPORT_NAME="MyModule" -s MODULARIZE=1 -s WASM=1

让我们分解一下这个命令:

  • emcc hello.cpp
    :指定要编译的源文件。
  • -o hello.html
    :这是个很方便的选项。Emscripten不仅会生成WebAssembly模块(
    .wasm
    文件)和JavaScript胶水代码(
    .js
    文件),还会自动生成一个包含这些文件并能直接运行的HTML页面。
  • -s EXPORTED_FUNCTIONS="['_greet', '_add']"
    :明确告诉编译器,我们希望从JavaScript中调用
    greet
    add
    这两个函数。注意函数名前面的下划线,这是Emscripten在导出C函数时的一个约定。
  • -s EXPORT_NAME="MyModule"
    :指定生成的JavaScript模块的全局名称,这样在HTML中就能通过
    MyModule
    来访问它。
  • -s MODULARIZE=1
    :将生成的JavaScript胶水代码封装成一个模块,避免污染全局命名空间,这是现代Web开发的推荐做法。
  • -s WASM=1
    :明确启用WebAssembly输出(虽然现在是默认行为,但明确指定总没错)。

编译成功后,你会得到

hello.html
hello.js
hello.wasm
三个文件。

要运行它,你不能直接在浏览器中打开

hello.html
,因为浏览器出于安全考虑,不允许本地文件直接加载WebAssembly模块。你需要一个本地的Web服务器。最简单的方法是使用Python:

python -m http.server 8000

或者,Emscripten也自带了一个简单的服务器:

emrun hello.html

然后,在浏览器中访问

http://localhost:8000/hello.html
。打开浏览器的开发者工具(F12),切换到Console标签页。你会看到“C++ main function started.”这条输出。

在Console中,你可以尝试调用导出的C++函数:

// MyModule是我们在编译时通过EXPORT_NAME指定的模块名
MyModule().then(function(module) {
    // 调用C++的greet函数
    module._greet(3); // 会在控制台输出3次"Hello from C++ WebAssembly!"

    // 调用C++的add函数
    let result = module._add(10, 20);
    console.log("Result of add:", result); // 输出 "Result of add: 30"
});

通过这个简单的例子,你应该能体会到C++代码如何在Web浏览器中被编译、加载并与JavaScript交互。这开启了一个全新的可能性,让那些性能敏感或已有大量C++代码的应用,也能在Web上焕发新生。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

407

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

632

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

362

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

263

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

625

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

557

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

668

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

616

2023.09.22

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

24

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.5万人学习

C 教程
C 教程

共75课时 | 5.1万人学习

C++教程
C++教程

共115课时 | 20万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号