aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/webassembly/c_to_wasm/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-cn/webassembly/c_to_wasm/index.html')
-rw-r--r--files/zh-cn/webassembly/c_to_wasm/index.html252
1 files changed, 252 insertions, 0 deletions
diff --git a/files/zh-cn/webassembly/c_to_wasm/index.html b/files/zh-cn/webassembly/c_to_wasm/index.html
new file mode 100644
index 0000000000..afcdbbc3e1
--- /dev/null
+++ b/files/zh-cn/webassembly/c_to_wasm/index.html
@@ -0,0 +1,252 @@
+---
+title: 编译 C/C++ 为 WebAssembly
+slug: WebAssembly/C_to_wasm
+tags:
+ - C
+ - C++
+ - Emscripten
+ - WebAssembly
+ - wasm
+ - 编译
+translation_of: WebAssembly/C_to_wasm
+---
+<div>{{WebAssemblySidebar}}</div>
+
+<p class="summary">当你在用C/C++之类的语言编写模块时,你可以使用<a href="/en-US/docs/Mozilla/Projects/Emscripten">Emscripten</a>来将它编译到WebAssembly。让我们来看看它是如何工作的。</p>
+
+<h2 id="Emscripten_环境安装">Emscripten 环境安装</h2>
+
+<p>首先,让我们来配置所需要的开发环境。</p>
+
+<h3 id="所需条件">所需条件</h3>
+
+<p>你需要将下列工具安装在您的电脑上,首先让我们确认下都有哪些。</p>
+
+<ul>
+ <li><a href="https://git-scm.com/">Git</a> — Linux和OS X的机器一般已经预装了,在Windows下您可以从这里下载<a href="https://git-scm.com/download/win">Git for Windows installer</a>。</li>
+ <li>CMake — 在Linux或者OS X上,使用类似 apt-get 或 <a href="http://brew.sh/">brew</a> 这样的包管理器来安装它,请确保依赖以及路径是否正确。在Windows上,使用<a href="https://cmake.org/download/">CMake installer</a>。</li>
+ <li>主系统编译器 — 在Linux下,<a href="http://askubuntu.com/questions/154402/install-gcc-on-ubuntu-12-04-lts">安装 GCC</a>。在OS X下,<a href="https://itunes.apple.com/us/app/xcode/id497799835">安装 Xcode</a>。在Windows下,安装<a href="https://www.microsoft.com/en-us/download/details.aspx?id=48146">Visual Studio Community 2015 with Update 3 or newer</a>。</li>
+ <li>Python 2.7.x — On Linux and OS X, this is most likely provided out of the box. 从 <a href="https://wiki.python.org/moin/BeginnersGuide/Downloadhere">初学者指南</a> 获取帮助。 在 Windows 上, 从 <a href="https://www.python.org/downloads/">Python 主页</a>获取安装包。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意: </strong>在Windows下您可能需要<a href="https://sourceforge.net/projects/pywin32/files/pywin32/">pywin32</a>,为了降低安装pywin32可能遇到的错误,请使用管理员权限在cmd内运行安装程序。</p>
+</div>
+
+<h3 id="编译Emscripten">编译Emscripten</h3>
+
+<p>接下来,您需要通过源码自己编译一个Emscripten。运行下列命令来自动化地使用Emscripten SDK。(在你想保存Emscripten的文件夹下运行)。</p>
+
+<pre class="brush: bash notranslate">git clone https://github.com/juj/emsdk.git
+cd emsdk
+
+# 在 Linux 或者 Mac OS X 上
+./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
+./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
+# 如果在你的macos上获得以下错误
+Error: No tool or SDK found by name 'sdk-incoming-64bit'
+# 请执行
+<code>./emsdk install latest
+</code># 按照提示配置环境变量即可
+./emsdk activate latest
+
+
+# 在 Windows 上
+emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
+emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
+
+# 注意:Windows 版本的 Visual Studio 2017 已经被支持,但需要在 emsdk install 需要追加 --vs2017 参数。
+</pre>
+
+<p> 安装过程可以会花上一点时间,是时候去休息一下。安装程序会设置所有Emscripten运行所需要的环境变量。</p>
+
+<div class="note">
+<p><strong>注意: </strong>--global标识会让PATH变量在全局被设置,所以接下来所打开的终端或者命令行窗口都会被设置。如果您仅仅想让Emscripten在当前窗口生效,就删掉这个标识。</p>
+</div>
+
+<div class="note">
+<p><strong>注意</strong>: 每当您想要使用Emscripten时,尝试从远程更新最新的emscripten代码是个很好的习惯(运行 git pull)。如果有更新,重新执行 install 和 activate 命令。这样就可以确保您使用的Emscripten一直保持最新。</p>
+</div>
+
+<p>现在让我们进入emsdk文件夹,输入以下命令来让你进入接下来的流程,编译一个样例C程序到asm.js或者wasm。</p>
+
+<pre class="brush: bash notranslate"># on Linux or Mac OS X
+source ./emsdk_env.sh
+
+# on Windows
+emsdk_env.bat
+</pre>
+
+<h2 id="编译样例代码">编译样例代码</h2>
+
+<p>现在环境配置完毕,让我们看看如何使用它把C代码编译到Emscripten。当使用Emscripten来编译的时候有很多种不同的选择,我们介绍其中主要的2种:</p>
+
+<ul>
+ <li>编译到 wasm 并且生成一个用来运行我们代码的HTML,将所有 wasm 在web环境下运行所需要的 “胶水” JavaScript代码都添加进去。</li>
+ <li>编译到 wasm 然后仅仅生成 JavaScript。</li>
+</ul>
+
+<p>让我们一个一个看看。</p>
+
+<h3 id="生成_HTML_和_JavaScript">生成 HTML 和 JavaScript</h3>
+
+<p>我们先来看一个最简单的例子,通过这个,你可以使用Emscripten来将任何代码生成到WebAssembly,然后在浏览器上运行。</p>
+
+<ol>
+ <li>首先我们需要编译一段样例代码。将下方的C代码复制一份然后命名为hello.c保存在一个新的文件夹内。
+ <pre class="brush: cpp notranslate">#include &lt;stdio.h&gt;
+
+int main(int argc, char ** argv) {
+ printf("Hello World\n");
+}</pre>
+ </li>
+ <li>现在,转到一个已经配置过Emscripten编译环境的终端窗口中,进入刚刚保存hello.c文件的文件夹中,然后运行下列命令:
+ <pre class="brush: bash notranslate">emcc hello.c -s WASM=1 -o hello.html</pre>
+ </li>
+</ol>
+
+<p>下面列出了我们命令中选项的细节:</p>
+
+<ul>
+ <li><code>-s WASM=1</code> — 指定我们想要的wasm输出形式。如果我们不指定这个选项,Emscripten默认将只会生成<a href="http://asmjs.org/">asm.js</a>。</li>
+ <li><code>-o hello.html</code> — 指定这个选项将会生成HTML页面来运行我们的代码,并且会生成wasm模块,以及编译和实例化wasm模块所需要的“胶水”js代码,这样我们就可以直接在web环境中使用了。</li>
+</ul>
+
+<p>这个时候在您的源码文件夹应该有下列文件:</p>
+
+<ul>
+ <li><code>hello.wasm</code>     二进制的wasm模块代码</li>
+ <li><code>hello.js</code>         一个包含了用来在原生C函数和JavaScript/wasm之间转换的胶水代码的JavaScript文件</li>
+ <li><code>hello.html</code>     一个用来加载,编译,实例化你的wasm代码并且将它输出在浏览器显示上的一个HTML文件</li>
+</ul>
+
+<h3 id="运行你的例子">运行你的例子</h3>
+
+<p>现在使用一个支持 WebAssembly 的浏览器,加载生成的 <code>hello.html</code> 。</p>
+
+<div class="note">
+<p>提示 :Firefox 52+ 和 Chrome 57+ 和最新版本的 Opera 已经默认启用,你也可以在 Firefox 47+ 中通过在 <em>about:config</em> 页面启用 <code>javascript.options.wasm</code> 字段获得支持,Chrome 51+ 和 Opera 38+ 可以在 <em>chrome://flags 页面启用 Experimental WebAssembly 选项以支持 </em>WebAssembly<em>。</em></p>
+</div>
+
+<p>如果一切顺利,你应该可以在页面上的 <code>Emscripten 控制台</code>和 <code>浏览器控制台</code> 中看到 "Hello World" 的输出。</p>
+
+<p>恭喜!你已经成功将 C 代码编译成 JavaScript 并且在浏览器中执行了!</p>
+
+<h2 id="使用自定义HTML模板">使用自定义HTML模板</h2>
+
+<p>有些时候你可能想要使用一个自定义的 HTML 模板。让我们看看怎么实现。</p>
+
+<ol>
+ <li>
+ <p>首先,在一个新文件夹中保存以下 C 代码到 hello2.c 中:</p>
+
+ <pre class="brush: cpp notranslate">#include &lt;stdio.h&gt;
+
+int main(int argc, char ** argv) {
+ printf("Hello World\n");
+}</pre>
+ </li>
+ <li>
+ <p>在  emsdk 中搜索一个叫做 <code>shell_minimal.html</code> 的文件,然后复制它到刚刚创建的目录下的 <code>html_template</code> 文件夹。</p>
+
+ <pre class="brush: bash notranslate">mkdir html_template
+cp ~/emsdk/emscripten/1.38.15/src/shell_minimal.html html_template</pre>
+ </li>
+ <li>
+ <p>现在使用你的Emscripten编译器环境的终端窗口进入你的新目录, 然后运行下面的命令:</p>
+
+ <pre class="brush: bash notranslate">emcc -o hello2.html hello2.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html</pre>
+
+ <p>这次使用的选项略有不同:</p>
+
+ <ul>
+ <li>我们使用了 <code>-o hello2.html</code> ,这意味编译器将仍然输出 js 胶水代码 和 html 文件。</li>
+ <li>我们还使用了 <code>--shell-file html_template/shell_minimal.html</code> ,这指定了您要运行的例子使用 HTML 页面模板。</li>
+ </ul>
+ </li>
+ <li>
+ <p>下面让我们来运行这个例子。上面的命令已经生成了 hello2.html,内容和我们使用的模板非常相像,只不过多加了一些 js 胶水和加载wasm文件的代码。 在浏览器中打开它,你会看到与上一个例子相同的输出。</p>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>通过用.js取代.htm(l)作为文件后缀名,你就可以得到只有JavaScript的输出文件,而不再是完整的HTML文件。例如:<code>emcc -o hello2.js hello2.c -O3 -s WASM=1</code>. 你可以完全从零开始创建你自己的HTML文件。尽管如此,不推荐这样做。因为Emscripten需要大量的JavaScript“胶水”代码从而能够 处理内存分配、内存泄漏以及大量的其他问题。这些问题都已经在提供的模板中得到了处理。使用模板要比自己编写模板要容易得多。不过,当对模板所做的事情越来越熟悉的时候,你就能够按照自己的需要创建定制化的模板了。</p>
+</div>
+
+<h2 id="调用一个定义在C中的自定义方法">调用一个定义在C中的自定义方法</h2>
+
+<p>如果需要调用一个在 C 语言自定义的函数,你可以使用  Emscripten 中的 <code>ccall()</code> 函数,以及 <code>EMSCRIPTEN_KEEPALIVE</code> 声明 (将你的函数添加到导出函数列表中(详见 <a href="https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html#why-do-functions-in-my-c-c-source-code-vanish-when-i-compile-to-javascript-and-or-i-get-no-functions-to-process">Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?</a>))。</p>
+
+<p>接下来让我们看看这是怎么实现的。</p>
+
+<ol>
+ <li>
+ <p>首先,将以下代码在新目录中保存为 <code>hello3.c</code> :</p>
+
+ <pre class="brush: cpp notranslate">#include &lt;stdio.h&gt;
+#include &lt;emscripten/emscripten.h&gt;
+
+int main(int argc, char ** argv) {
+ printf("Hello World\n");
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) {
+ printf("我的函数已被调用\n");
+}
+
+#ifdef __cplusplus
+}
+#endif</pre>
+
+ <p>默认情况下,Emscripten 生成的代码只会调用 <code>main()</code> 函数,其它的函数将被视为无用代码。在一个函数名之前添加 <code>EMSCRIPTEN_KEEPALIVE</code> 能够防止这样的事情发生。你需要导入 <code>emscripten.h</code> 库来使用 <code>EMSCRIPTEN_KEEPALIVE</code>。</p>
+
+ <div class="note">
+ <p><strong>注意</strong>: 为了保证万一你想在 C++ 代码中引用这些代码时代码可以正常工作,我们添加了 <code>#ifdef</code> 代码块。由于 C 与 C++ 中名字修饰规则的差异,添加的代码块有可能产生问题,但目前我们设置了这一额外的代码块以保证你使用 C++ 时,这些代码会被视为外部 C 语言函数。</p>
+ </div>
+ </li>
+ <li>
+ <p>为了方便起见,现在将 <code>html_template/shell_minimal.html</code> 也添加到这一目录(但在实际开发环境中你肯定需要将其放到某一特定位置)。</p>
+ </li>
+ <li>
+ <p>运行以下命令编译:(注意由于使用ccall函数,需要添加指定参数)</p>
+
+ <pre class="brush: bash notranslate">emcc -o hello3.html hello3.c -O3 -s WASM=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" --shell-file html_template/shell_minimal.html</pre>
+ </li>
+ <li>
+ <p>如果你在浏览器中在此加载实例,你将看到和之前相同的结果。</p>
+ </li>
+ <li>
+ <p>现在我们需要运行新的 <code>myFunction()</code> JavaScript 函数。首先,按照以下实例添加一个 {{htmlelement("button")}} ,就在 <code>&lt;script type='text/javascript'&gt;</code> 开头标签之前。</p>
+
+ <pre class="brush: html notranslate">&lt;button class="mybutton"&gt;运行我的函数&lt;/button&gt;</pre>
+ </li>
+ <li>
+ <p>现在在最后一个 {{htmlelement("script")}} 元素 (就在 <code>&lt;/script&gt;</code> 关闭标签之前)中添加以下代码:</p>
+
+ <pre class="brush: js notranslate">document.querySelector('.mybutton').addEventListener('click', function(){
+ alert('检查控制台');
+ var result = Module.ccall('myFunction', // name of C function
+ null, // return type
+ null, // argument types
+ null); // arguments
+});</pre>
+ </li>
+</ol>
+
+<p>以上就是如何使用 <code>ccall()</code> 调用导出的函数的方式。</p>
+
+<h2 id="另请参见">另请参见</h2>
+
+<ul>
+ <li><a href="http://emscripten.org/">emscripten.org</a> — 了解更多 Emscripten 以及它的多种设置</li>
+ <li><a href="https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#calling-compiled-c-functions-from-javascript-using-ccall-cwrap">Calling compiled C functions from JavaScript using ccall/cwrap</a></li>
+ <li><a href="https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html#why-do-functions-in-my-c-c-source-code-vanish-when-i-compile-to-javascript-and-or-i-get-no-functions-to-process">Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?</a></li>
+ <li><a href="https://research.mozilla.org/webassembly/">WebAssembly on Mozilla Research</a></li>
+ <li>
+ <p><a href="https://wiki.developer.mozilla.org/en-US/docs/WebAssembly/existing_C_to_wasm">Compiling an Existing C Module to WebAssembly</a></p>
+ </li>
+</ul>