<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>绿色记忆 &#187; Chrome</title>
	<atom:link href="https://blog.gmem.cc/tag/chrome/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Tue, 21 Apr 2026 10:40:56 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.14</generator>
	<item>
		<title>NaCl学习笔记</title>
		<link>https://blog.gmem.cc/chrome-native-client-study-note</link>
		<comments>https://blog.gmem.cc/chrome-native-client-study-note#comments</comments>
		<pubDate>Tue, 30 Sep 2014 06:33:48 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[FAQ]]></category>
		<category><![CDATA[NaCl]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=3650</guid>
		<description><![CDATA[<p>基础知识 Chrome Chrome是一个多进程（multi-process）架构的浏览器，相比起Firefox之类的单进程浏览器，其提供额外的完全特性。 Chrome包含一个称为“browser”的主进程，其负责运行UI界面、管理标签页（Tabs）和插件进程，具有当前用户所有的访问权限（文件、网络等），并且能够fork出子进程。 标签页被分配到单独的“renderer”进程中，通常每个domain会共享一个进程。展示进程运行在沙盒（Sandbox）中，不能打开文件、网络。展示进程负责渲染HTML布局、处理页面展示。 插件 插件指外部的二进制文件，插件为浏览器添加额外的功能。插件可以随着浏览器一起安装，例如 Adobe Flash、Adobe Reader，也可以是用户自行安装的。一般来说，现有的大部分插件由于需要网络、文件系统的访问权限，而不能在沙盒内运行，因此Chrome提供了进程外插件机制（out of process plugins），在独立进程中以完整访问权限运行插件，并且使用进程间通信（IPC）机制来与browser、renderer进程通信。 Chrome也支持进程内插件（in process plugins），其运行于renderer进程内部，不需要使用IPC机制进行通信。 Netscape Plugin API (NPAPI) NPAPI是一个跨浏览器的插件框架，除了微软使用ActiveX技术以外，其他主要浏览器均支持。Chrome使用进程外插件的方式来支持NPAPI。Chrome 目前已经不再支持NPAPI。 <a class="read-more" href="https://blog.gmem.cc/chrome-native-client-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/chrome-native-client-study-note">NaCl学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">基础知识</span></div>
<div class="blog_h3"><span class="graybg">Chrome</span></div>
<p>Chrome是一个多进程（multi-process）架构的浏览器，相比起Firefox之类的单进程浏览器，其提供额外的完全特性。 Chrome包含一个称为“browser”的主进程，其负责运行UI界面、管理标签页（Tabs）和插件进程，具有当前用户所有的访问权限（文件、网络等），并且能够fork出子进程。</p>
<p>标签页被分配到单独的“renderer”进程中，通常每个domain会共享一个进程。展示进程运行在沙盒（Sandbox）中，不能打开文件、网络。展示进程负责渲染HTML布局、处理页面展示。</p>
<div class="blog_h3"><span class="graybg">插件</span></div>
<p style="text-align: justify;">插件指外部的二进制文件，插件为浏览器添加额外的功能。插件可以随着浏览器一起安装，例如 Adobe Flash、Adobe Reader，也可以是用户自行安装的。一般来说，现有的大部分插件由于需要网络、文件系统的访问权限，而不能在沙盒内运行，因此Chrome提供了进程外插件机制（out of process plugins），在独立进程中以完整访问权限运行插件，并且使用进程间通信（IPC）机制来与browser、renderer进程通信。</p>
<p style="text-align: justify;">Chrome也支持进程内插件（in process plugins），其运行于renderer进程内部，不需要使用IPC机制进行通信。</p>
<div class="blog_h3"><span class="graybg">Netscape Plugin API (NPAPI) </span></div>
<p>NPAPI是一个跨浏览器的插件框架，除了微软使用ActiveX技术以外，其他主要浏览器均支持。Chrome使用进程外插件的方式来支持NPAPI。Chrome 目前已经不再支持NPAPI。</p>
<div class="blog_h3"><span class="graybg">Pepper Plugin API (PPAPI)</span></div>
<p>PPAPI是谷歌提出的开源、跨平台插件框架，其主要目的是解决NPAPI的性能、可移植性问题。PPAPI的初期设计曾考虑尽可能保持与NPAPI的接口风格一致性，但是这一设计原则逐渐被放弃。</p>
<p>PPAPI允许C/C++模块与浏览器交互、以安全可移植方式来访问系统级函数。PPAPI不支持操作系统调用，但是它提供了类似的API。</p>
<p>PPAPI支持以下操作：</p>
<ol>
<li>与JavaScript的双向通信</li>
<li>进行文件I/O操作</li>
<li>播放音频</li>
<li>渲染3D图形</li>
</ol>
<p>Google没有提供自动化安装第三方的PPAPI插件的方式。使用类似下面的命令行参数启动Chrome，可以手工加载PPAPI插件：</p>
<pre class="crayon-plain-tag">chrome --disable-sandbox --register-pepper-plugins="&lt;plugin_dll_path&gt;;mime/type"</pre>
<div class="blog_h2"><span class="graybg">NaCl技术概览</span></div>
<p>NaCl是一种在浏览器中安全执行平台无关的、不受信任代码的开源沙盒技术，它允许计算密集型、交互性的实时Web应用有效的利用机器的物理性能，并同时保证安全性。<span style="background-color: #c0c0c0;">NaCl本质上是一个进程内PPAPI插件</span>。</p>
<p>一个NaCl应用程序包含：JavaScript、HTML、CSS、以及一个NaCl模块。目前NaCl SDK支持的语言主要是C和C++。</p>
<p>NaCl SDK是用于开发NaCl可执行文件（nexe）的工具包。由一系列GNU工具链组成，包括 gcc, binutils、gdb等。</p>
<p>Portable Native Client(PNacl)则是在NaCl的基础上支持硬件架构的无关性，可以在任何支持AOT（ahead-of-time）的平台下运行，必须在Chrome 31+才能支持。Chrome负责把pexe格式的中间代码翻译成客户端本地代码。PNacl可以在<span style="background-color: #c0c0c0;">不依赖Google Web Store的情况下进行部署</span>。在Chrome://flags中开启Native Client标记可以运行任意NaCl。</p>
<p>应当尽可能使用PNacl，而不是NaCl，除非：</p>
<ol>
<li>程序需要平台相关的指令，例如内联汇编</li>
<li>程序使用动态链接，PNacl仅支持与newlib C标准库的naclport静态链接，对glibc的静态链接、以及动态链接尚不支持</li>
<li>程序使用了某些PNaCl的LLVM工具链所不支持的GNU扩展</li>
</ol>
<p>&nbsp;</p>
<div class="blog_h3"><span class="graybg">NaCl工作机制示意图</span></div>
<p><img class="aligncenter  wp-image-3662" src="https://blog.gmem.cc/wp-content/uploads/2014/09/nacl_diagram.png" alt="nacl_diagram" width="564" height="677" /></p>
<p><img class="aligncenter  wp-image-3669" src="https://blog.gmem.cc/wp-content/uploads/2014/09/nacl-pnacl-component-diagram.png" alt="nacl-pnacl-component-diagram" width="526" height="471" /></p>
<div class="blog_h3"><span class="graybg">NaCl工具链</span></div>
<ol>
<li>PNaCl工具链：基于LLVM工具链。使用newlib库，生成单个pexe文件，在运行时，浏览器内置的AOT转换器负责将其转换为本地代码</li>
<li>NaCl工具链：基于GCC，包含x86_newlib、x86_glibc、arm_newlib三个工具链，生成多个架构相关的nexe文件，并打包到一个应用，浏览器负责决定使用哪个nexe</li>
</ol>
<p>不能在一个应用里混合使用多个工具链。下表列出这些工具链使用的C标准库、目录名称，其中platform可能是win或者linux</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">目标架构 </td>
<td style="text-align: center;">C标准库</td>
<td style="text-align: center;">工具链目录 </td>
</tr>
<tr>
<td style="text-align: center;">x86</td>
<td style="text-align: center;">newlib</td>
<td style="text-align: left;">toolchain/&lt;platform&gt;_x86_newlib</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">x86</td>
<td style="text-align: center;">glibc</td>
<td>toolchain/&lt;platform&gt;_x86_glibc</td>
</tr>
<tr>
<td style="text-align: center;">ARM</td>
<td style="text-align: center;">newlib</td>
<td>toolchain/&lt;platform&gt;_arm_newlib</td>
</tr>
<tr>
<td style="text-align: center;">PNaCl</td>
<td style="text-align: center;">newlib</td>
<td>toolchain/&lt;platform&gt;_pnacl</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<div class="blog_h3"><span class="graybg">NaCl的安全性</span></div>
<ol>
<li>NaCl沙盒确保代码只能通过安全的、白名单中的API来访问系统资源，并且确保代码不能干扰其它浏览器内外代码的运行</li>
<li>NaCl验证器在运行前静态分析代码，确保只包含允许的代码和数据图式（pattern）</li>
</ol>
<div class="blog_h3"><span class="graybg">基于NaCl的Web应用的结构</span></div>
<p>至少包含HTML代码、Manifest文件和NaCl模块3部分内容。</p>
<p>HTML代码中需要包含embed标签，用于定位manifest文件：</p>
<pre class="crayon-plain-tag">&lt;embed width="300" height="150" type="application/x-pnacl" src="helloworld.nmf" name="mygame"&gt;
&lt;/embed&gt;</pre>
<p>Manifest文件以nmf为扩展名，定义了需要加载的NaCl模块以及选项，形式如下：</p>
<pre class="crayon-plain-tag">{
  "url": "helloworld.pexe"
}</pre>
<p>NaCl模块是编译好的pexe文件，其使用Pepper API作为本地代码与JavaScript、其它浏览器资源的桥梁。</p>
<div class="blog_h2"><span class="graybg">NaCl的劣势以及其替代技术</span></div>
<p>NaCl具有以下缺点：</p>
<ol>
<li>不能直接访问硬件，相比之下WebRTC之类的技术允许访问音视频捕获设备</li>
<li>没有完整的OpenGL特性支持</li>
<li>不允许原始TCP/UDP</li>
<li>其它浏览器厂商对其缺乏兴趣</li>
<li>不支持同步化的JavaScript调用，所有NaCl与JavaScript的交互均是异步的</li>
</ol>
<div class="blog_h3"><span class="graybg">替代技术</span></div>
<p><span style="background-color: #c0c0c0;"><strong>PPAPI (without NaCL) </strong></span></p>
<p>本文上面已经提到过，PPAPI插件无法方便的安装，只能使用命令行参数</p>
<p><span style="background-color: #c0c0c0;"><strong>Google Native Messaging</strong></span></p>
<p>该技术允许Chrome插件与本地程序进行消息交互。</p>
<p>优势：</p>
<ol>
<li>支持运行本地代码，可以进行完整的硬件访问、原生TCP/UDP访问</li>
<li>支持从Chrome启动本地程序</li>
</ol>
<p>劣势：</p>
<ol>
<li>两个单独的安装程序：本地程序的安装、Chrome扩展的安装</li>
<li>难以获取视频数据返回给浏览器，不适合密集的数据传输</li>
</ol>
<div class="blog_h2"><span class="graybg">NaCl SDK安装步骤</span></div>
<div class="blog_h3"><span class="graybg">Windows</span></div>
<ol>
<li>到https://developer.chrome.com/native-client/sdk/download下载SDK</li>
<li>解压到D:\CPP\tools\Chromium\nacl_sdk</li>
<li>运行以下脚本：<br />
<pre class="crayon-plain-tag">cd nacl_sdk
naclsdk update --force</pre>
</li>
<li>安装Python 2.7.x，并添加到PATH环境变量</li>
</ol>
<div class="blog_h3"><span class="graybg">Linux</span></div>
<ol>
<li>下载SDK并解压到~/CPP/tools/Chromium/nacl_sdk</li>
<li>运行脚本：<br />
<pre class="crayon-plain-tag">sudo apt-get install libc6:i386

cd ~/CPP/tools/Chromium/nacl_sdk
./naclsdk update

vim ~/.bashrc
#添加以下内容
export PATH="$PATH":/home/alex/CPP/tools/Chromium/depot_tools
export NACL_SDK_ROOT=/home/alex/Chromium/nacl_sdk/pepper_39</pre>
</li>
<li>如果没有安装Python 2.x，则apt-get安装</li>
</ol>
<div class="blog_h2"><span class="graybg">NaCl HelloWorld</span></div>
<div class="blog_h3"><span class="graybg">开发环境准备</span></div>
<p><strong><span style="background-color: #c0c0c0;">环境变量：</span></strong></p>
<p>NACL_SDK_ROOT=D:\CPP\tools\nacl_sdk\pepper_39</p>
<p>如果安装了Cygwin，需要把Cygwin的bin目录从PATH中排除掉（可以通过Eclipse工程右键，Properties - C/C++ Build Environment设置），否则构建时可能收到类似“/x86_64-nacl-ld: cannot find -lppapi_gles2”的错误</p>
<p><strong><span style="background-color: #c0c0c0;">IDE设置（Eclipse CDT）：</span></strong></p>
<ol>
<li>File - New - Makefile Project with existing Code，工程名称设置为nacl-helloworld，Existing Code Location定位到准备存放代码的目录，Toolchain for Indexer Settings选择Cross GCC</li>
<li>工程点右键 - Properties - C/C++ General - Paths and Symbols - Source Location，删除默认，与Makefile设置保持一致</li>
<li>工程点右键 - Properties - C/C++ General - Paths and Symbols - Output Location，删除默认，添加/project-root/***，***可以是glibc、newlib、pnacl等，根据Makefile中设置的工具链（VALID_TOOLCHAINS）来设置</li>
<li>工程点右键 - Properties - C/C++ General - Paths and Symbols - Includes - GNU C++，添加：${NACL_SDK_ROOT}/include、${NACL_SDK_ROOT}/toolchain/win_***/x86-64_bc-nacl/include，根据Makefile中设置的工具链（VALID_TOOLCHAINS）来设置</li>
<li>工程点右键 - Properties - C/C++ Build，取消勾选“Use default build command”，设置为make.bat</li>
<li>工程点右键 - Make Targets - Create，创建名为serve的构建目标</li>
</ol>
<div class="blog_h3"><span class="graybg">源代码列表</span></div>
<pre class="crayon-plain-tag">@%NACL_SDK_ROOT%\tools\make.exe %*</pre><br />
<pre class="crayon-plain-tag">CONFIG = Debug

VALID_TOOLCHAINS := newlib glibc pnacl win

NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)

include $(NACL_SDK_ROOT)/tools/common.mk

TARGET = hello_world
LIBS = ppapi_cpp ppapi

CFLAGS = -Wall
SOURCES = hello_world.cc

$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))

ifneq (,$(or $(findstring pnacl,$(TOOLCHAIN)),$(findstring Release,$(CONFIG))))
$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
else
$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
endif

$(eval $(call NMF_RULE,$(TARGET),))</pre><br />
<pre class="crayon-plain-tag">#include &lt;string&gt;

#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"


/**
 * NaCl实例类
 * 浏览器端的每一个embed标签对应了一个实例
 * 指定embed标签的属性：
 * src="hello_world.nmf"
 * type="application/x-pnacl"
 */
class HelloWorldInstance : public pp::Instance
{
    public:

        explicit HelloWorldInstance( PP_Instance instance ) :
                pp::Instance( instance )
        {
        }
        virtual ~HelloWorldInstance()
        {
        }

        /**
         * 处理浏览器端通过postMessage()调用传入的消息
         * @param var_message 浏览器传入的消息
         */
        virtual void HandleMessage( const pp::Var&amp; var_message )
        {
            // 处理传入消息
            if ( !var_message.is_string() ) return;
            std::string message = var_message.AsString();
            pp::Var var_reply;
            if ( message == "hello" )
            {
                var_reply = pp::Var( "hello from NaCl" );
                PostMessage( var_reply );
            }
        }
};

/**
 * NaCl模块类
 */
class HelloWorldModule : public pp::Module
{
    public:
        HelloWorldModule() :
                pp::Module()
        {
        }
        virtual ~HelloWorldModule()
        {
        }

        /**
         * 在模块加载完成后，浏览器即调用此函数创建实例。
         * @param in 浏览器端的实例对象句柄
         * @return 插件端的实例对象
         */
        virtual pp::Instance* CreateInstance( PP_Instance instance )
        {
            return new HelloWorldInstance( instance );
        }
};

namespace pp
{
    /**
     * 该工厂函数在NaCl模块在加载时被浏览器调用一次，不会多次调用
     * 浏览器维持模块的单例
     *
     */
    Module* CreateModule()
    {
        return new HelloWorldModule();
    }
}</pre><br />
<pre class="crayon-plain-tag">{
  "program": {
    "portable": {
      "pnacl-translate": {
        "url": "hello_world.pexe"
      }
    }
  }
}</pre>
<div> <br />
<pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;hello World&lt;/title&gt;
&lt;script type="text/javascript"&gt;
    HelloWorldModule = null; // 全局模块对象
    statusText = 'NO-STATUS';

    function moduleDidLoad()
    {
        HelloWorldModule = document.getElementById( 'hello_world' );
        updateStatus( 'SUCCESS' );
        HelloWorldModule.postMessage('hello');
    }

    //处理NaCl模块发送的消息
    function handleMessage( message_event )
    {
        alert( message_event.data );
    }

    function pageDidLoad()
    {
        if ( HelloWorldModule == null )
        {
            updateStatus( 'LOADING...' );
        }
        else
        {
            updateStatus();
        }
    }

    function updateStatus( opt_message )
    {
        if ( opt_message ) statusText = opt_message;
        var statusField = document.getElementById( 'statusField' );
        if ( statusField )
        {
            statusField.innerHTML = statusText;
        }
    }
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload="pageDidLoad()"&gt;

    &lt;div id="listener"&gt;
        &lt;script type="text/javascript"&gt;
            var listener = document.getElementById( 'listener' );
            listener.addEventListener( 'load', moduleDidLoad, true );
            listener.addEventListener( 'message', handleMessage, true );
        &lt;/script&gt;
        &lt;embed id="hello_world" width=0 height=0 src="newlib/Debug/hello_world.nmf" type="application/x-nacl" /&gt;
    &lt;/div&gt;
    &lt;div&gt;
        Status &lt;code id="statusField"&gt;NO-STATUS&lt;/code&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<div class="blog_h3"><span class="graybg">构建与运行</span></div>
<ol>
<li>Project - Build Project，会生成hello_world.pexe文件</li>
<li>鼠标选中工程根目录，Shift + F9，选择serve</li>
<li>使用Chrome打开http://localhost:5103/，可以看到弹出消息框，显示来自NaCl模块的消息文本：“hello from NaCl”，运行成功</li>
</ol>
<div class="blog_h3"><span class="graybg">远程调试</span></div>
<ol>
<li>在源代码hello_world.cc的79行，设置一个断点</li>
<li>修改Makefile，以Debug方式编译，并设置工具链把newlib置为默认：<br />
<pre class="crayon-plain-tag">CONFIG = Debug
VALID_TOOLCHAINS := newlib glibc pnacl win</pre>
</li>
<li>Run - Debug Configurations，在C/C++ Remote Application目录下创建新的Debug配置</li>
<li>Main 选项卡 
<ol>
<li>Name设置为nacl-helloworld newlib；Project选择nacl-helloworld</li>
<li>C/C++ Application填写：D:\CPP\projects\eclipse\4.3.2\nacl-helloworld\newlib\Debug\hello_world_x86_64.nexe</li>
<li>底部的链接Select Other，点击后选择GDB(DSF) Manual Remote Debugging Launcher</li>
<li>点选Disable auto build</li>
</ol>
</li>
<li>Debugger选项卡
<ol>
<li>Stop on startup at设置为：Instance_DidCreate，或者取消勾选</li>
<li>GDB Debugger选择：%NACL_SDK_ROOT%\toolchain\win_x86_newlib\bin\x86_64-nacl-gdb.exe</li>
<li>切换到子选项卡Connection，端口设置为4014</li>
</ol>
</li>
<li>Source选项卡，点击Add - Path Mapping，Name设置为pepper_mapping，添加一个映射条目：\cygdrive\s\src\out 对应D:\CPP\tools\Chromium\nacl_sdk，可以在调试无法找到源代码时再行设置</li>
<li>点击Apply保存设置，然后点击Run，Eclipse Debugger开始等待连接到Chrome</li>
<li>在客户端设置以下环境变量：<br />
<pre class="crayon-plain-tag">rem 重定向stderr、stdout
set NACL_EXE_STDERR=F:\Temp\Chrome\nacl_stderr.log
set NACL_EXE_STDOUT=F:\Temp\Chrome\nacl_stdout.log
rem 重定向NaCl内部生成的消息，默认至stderr
set NACLLOG=F:\Temp\Chrome\nacl.log
rem 控制警告、错误信息的显示
set NACL_PLUGIN_DEBUG=1
rem 1-255，越高则信息越详细
set NACL_SRPC_DEBUG=255
set NACLVERBOSITY=255</pre>
</li>
<li>运行make serve启动HTTP服务器</li>
<li>以参数--no-sandbox --enable-nacl-debug启动Chrome，如果使用ChromiumPortable，可以修改ChromiumPortable.ini：<br />
<pre class="crayon-plain-tag">[GoogleChromePortable]    
;--vmodule=ppb*=4 --enable-logging=stderr用于记录NaCl模块对Pepper API的调用
AdditionalParameters=--no-sandbox --enable-nacl-debug --disable-hang-monitor --vmodule=ppb*=4 --enable-logging=stderr</pre>
</li>
<li>Chrome暂停运行，Eclipse自动停止在断点处，调试成功</li>
</ol>
<div class="blog_h2"><span class="graybg">编译NaClPorts</span></div>
<p>NaCl提供了一种跨平台的类POSIX环境，很多Linux下开源项目都可以在此环境下运行，但是需要特殊的编译过程（port to nacl），在Windows下，需要Cygwin才能编译ports。</p>
<div class="blog_h3"><span class="graybg">Linux下NaclPorts编译举例：ffmpeg</span></div>
<ol>
<li>安装需要的工具<br />
<pre class="crayon-plain-tag">sudo apt-get install curl sed git cmake texinfo gettext pkg-config autoconf automake libtool xsltproc
sudo apt-get install libglib2.0-dev</pre>
</li>
<li>安装depot_tools，depot_tools是一个脚本工具包，用于管理代码的签出、review，包含gclient, gcl, git-cl, repo等工具<br />
<pre class="crayon-plain-tag">cd ~/CPP/tools/Chromium
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

vim ~/.bashrc
#添加
export PATH=`pwd`/depot_tools:"$PATH"</pre>
</li>
<li>签出naclports源代码<br />
<pre class="crayon-plain-tag">cd ~/CPP/tools/Chromium
mkdir naclports
cd naclports
gclient config --name=src  https://chromium.googlesource.com/external/naclports.git
gclient sync</pre>
</li>
<li>进入/home/alex/CPP/tools/Chromium/naclports/src，可以看到若干Ports的源代码，每个子目录通常包含以下文件：
<ol>
<li>pkg_info：port的描述</li>
<li>build.sh：用于构建此port的脚本</li>
<li> nacl.patch：一个可选的补丁文件</li>
</ol>
</li>
<li>构建port的工具位于naclports/bin/naclports，执行下面的脚本即可下载、打补丁、构建、安装目标应用或者库<br />
<pre class="crayon-plain-tag">naclports install &lt;package_dir&gt; </pre></p>
<p>注意NaCl模块可以在四种架构下构建（i686,x86_64, arm, pnacl），每次构建只会使用其中一种架构。某些架构下有多个Toolchain（例如x86有newlib、glibc），可以通过环境变量选择：</p>
<pre class="crayon-plain-tag">NACL_ARCH=i686 TOOLCHAIN=glibc make ffmpeg</pre>
<p>如果要为某个port编译所有架构下所有工具链的版本，可以运行：</p>
<pre class="crayon-plain-tag">./make_all.sh ffmpeg</pre>
<p> 头文件、库被安装到对应工具链的目录下，使用这些库不需要额外的-I、-L参数。源码和编译的输出文件位于out/build/&lt;PACKAGE_NAME&gt;目录下。默认的，所有编译都是以RELEASE方式进行的，可以设置环境变量NACL_DEBUG=1来改变此行为，或者给naclports 传递 --debug参数。naclports会优先尝试直接从Google下载二进制包，如果要强制从源代码编译，可以传递--from-source参数</p>
</li>
<li>使用如下命令构建ffmpeg：<br />
<pre class="crayon-plain-tag">cd ~/CPP/tools/Chromium/naclports/src
NACL_ARCH=pnacl make ffmpeg</pre>
</li>
</ol>
<div class="blog_h2"><span class="graybg">FAQ</span></div>
<div class="blog_h3"><span class="graybg">如何让多个版本的Chrome共存</span></div>
<p>可以下载便携版（Portable）的Chromium：http://sourceforge.net/projects/crportable/</p>
<p>类似的，便携版的Chrome也有，可以到网上搜索并下载。</p>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/chrome-native-client-study-note">NaCl学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/chrome-native-client-study-note/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基于Chrome Developer Tools的JavaScript开发与调试</title>
		<link>https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools</link>
		<comments>https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools#comments</comments>
		<pubDate>Sun, 06 Jul 2014 03:24:28 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Chrome]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=3771</guid>
		<description><![CDATA[<p>Chrome DevTools代码修改持久化（Persistent authoring）配置 Chrome 28的配置方式 输入chrome://flags，启用：Developer Tools experiments（开发者工具实验） 重启Chrome，按F12，点击设置按钮，切换至Experiments，勾选 File system folder in Source Panel 重启Chrome，按F12，点击设置按钮，切换至Workspace，添加文件系统与URL的映射关系 找到需要支持双向同步的Eclipse Maven项目的webapp目录，例如：D:\JavaEE\projects\eclipse\3.7.2\sshe-static\src\main\webapp 打开CMD窗口，依次执行： [crayon-69e9a92b88d92216567092/] 确认.allow-devtools-edit已经加入到svn:ignore中，不能提交到代码库 在Chrome <a class="read-more" href="https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools">基于Chrome Developer Tools的JavaScript开发与调试</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">Chrome DevTools代码修改持久化（Persistent authoring）配置</span></div>
<div class="blog_h3"><span class="graybg">Chrome 28的配置方式</span></div>
<ol>
<li>输入chrome://flags，启用：Developer Tools experiments（开发者工具实验）</li>
<li>重启Chrome，按F12，点击设置按钮，切换至Experiments，勾选 File system folder in Source Panel</li>
<li>重启Chrome，按F12，点击设置按钮，切换至Workspace，添加文件系统与URL的映射关系
<ol>
<li>找到需要支持双向同步的Eclipse Maven项目的webapp目录，例如：D:\JavaEE\projects\eclipse\3.7.2\sshe-static\src\main\webapp</li>
<li>打开CMD窗口，依次执行：<br />
<pre class="crayon-plain-tag">PUSHD D:\JavaEE\projects\eclipse\3.7.2\sshe-static\src\main\webapp
ECHO  &gt; .allow-devtools-edit</pre>
</li>
<li>确认.allow-devtools-edit已经加入到svn:ignore中，不能提交到代码库</li>
<li>在Chrome Workspace设置中，添加File Systems：D:\JavaEE\projects\eclipse\3.7.2\sshe-static\src\main\webapp，注意结尾不能有斜杠</li>
<li>在Chrome Workspace设置中，添加Mappings，左侧输入服务器URL，该URL与上述文件系统目录正好要对应，例如http://localhost:8080/sshe-static，右侧填写与上一步File Systems一致的内容。点击加号保存</li>
<li>重启Chrome DevTools</li>
</ol>
</li>
<li>测试文件系统——URL映射是否配置成功
<ol>
<li>打开Eclipse，启动一个Server，用Chrome打开某个页面</li>
<li>点击F12，按Ctrl+O，输入某个映射的JavaScript文件的名字，如果映射成功，<span style="background-color: #c0c0c0;">那么只会显示一个本地文件</span>，否则显示一个本地文件、一个服务器文件</li>
<li>在Chrome的源代码编辑器里，对上述的本地文件进行修改，立即反馈到Eclispe</li>
<li>在Eclipse中，对上述本地文件进行修改，立即反馈到Chrome中，并自动加载脚本到Chrome内存</li>
</ol>
</li>
<li>设置Eclipse -  General - Workspace ，勾选Refresh on access</li>
<li>如果觉得Chrome源代码编辑器字体太小，可以编辑：C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Default\User StyleSheets\Custom.css文件，添加代码：<br />
<pre class="crayon-plain-tag">body.platform-windows .monospace, body.platform-windows .source-code {
    font-size: 10pt !important;
    font-family: Consolas, Lucida Console, monospace;
}</pre>
</li>
</ol>
<div class="blog_h3"><span class="graybg">Chrome 36的配置方式</span></div>
<ol>
<li>打开目标网页，按F12，点击设置</li>
<li>切换到Workspaces面板，点击Add folder，输入Eclipse Maven项目的webapp目录，例如：D:\JavaEE\projects\eclipse\4.3.2</li>
<li>选中刚刚添加的目录，点击Edit按钮，进行文件系统与URL的映射，例如：http://192.168.0.89:6060/sshe-static/映射到sshe-static\src\main\webapp</li>
<li>关闭设置弹出框，切换到Sources面板，可以看到URL 192.168.0.89:6060下sshe-static目录消失了</li>
<li>陆续完成所有URL的映射</li>
<li>分别在Eclipse、Chrome DevTools里面修改JS文件进行测试，确认修改可以双向自动同步</li>
</ol>
<div class="blog_h2"><span class="graybg">常见问题</span></div>
<div class="blog_h3"><span class="graybg">调试时代码行数不对应</span></div>
<p>注意勾选Call Stack面板的Async复选框。</p>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools">基于Chrome Developer Tools的JavaScript开发与调试</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/javascript-dev-and-debug-with-chrome-devtools/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
