不知不觉,Google已经正式推出其Native Client (NaCl)过去约7个月之久。而目前国内似乎还没有多少关于NaCl的资料,所以在这里面向Web开发者做一下简单的介绍,希望能够起到一个抛砖引玉的效果。
本文的所有代码均来自于https://developers.google.com/native-client/devguide/tutorial,如果您对其中的任何技术细节存在疑问,请以原文为准。
何谓NaCl
NaCl是一项能让C/C++代码运行在浏览器当中的技术。这是一个最通俗的说法,但不够精确。严格来说,NaCl技术在理论上能够实现任何编译型语言都在其之上运行。
但是目前由于技术上的原因,NaCl还做不到任何语言任何平台的编译型语言支持。
因为NaCl所憧憬的实际是LLVM技术,LLVM技术的要点即在于能将编译型语言转化为一个统一的中间语言,NaCl通过对这个中间语言的执行,即可达成任何编译型语言的运行。换句话说,NaCl实际上希望搭建一个虚拟机。
不过LLVM现在还不够成熟,NaCl不得不先使用GNU的编译套件,使用LLVM技术的版本被称为了PNaCl,目前还没有正式推出。同时也因为这个原因,ARM架构没能正式支持。
为什么NaCl
在开发层面上,NaCl希望解决一个问题:JavaScript的低效率。当然,从经营策略上来说,Google可能还希望籍此将桌面领域的成熟软件快速移植到其Chrome OS当中,不过这不是我们讨论的重点。
JavaScript毕竟是一门解释型语言,只有当浏览器执行到代码的时刻才能够看到代码,因此在执行优化上力度非常小。
但是Web应用发展至今,效率已经必须拿到桌面上考虑,如果你还想在浏览器里面看到更多优质的游戏的话。
有关限制
- 缺乏能够切合的IDE
- 不支持硬件异常
- 不支持创建子进程
- 不支持原生TCP/UDP操作(但已提供了websocket支持)
- 不支持同步I/O
- 不支持内存剩余查询
- 内联汇编代码必须通过NaCl验证
- NaCl的Pepper API必须通过主线程使用
如何使用
上面那些对于行动主义来说其实都是P,真正需要聚焦的还是如何使用。
NaCl的典型项目由三个部分组成:
- 网页(
*.html
)。这里所指的网页是一个泛指,它包括JS代码、CSS样式表已经HTML代码。 - NaCl模块(
*.c;*.cc
)。这是C/C++代码的文件。 - 清单(
*.nmf
)。这份清单类似于Chrome Extension的清单,主要用于指明在不同架构的机器上调用什么模块。
在真正开始之前,我们还需要安装一个NaCl的SDK。这个SDK当中主要包含了NaCl的模块编译工具链。大家可以从这里下载:https://developers.google.com/native-client/sdk/download
安装之前,确保一下机器上有一个可用的Python 2.7,并加入到环境变量当中。
而SDK的安装则相当简单,只需要使用naclsdk update
命令即可。
下面,创建一个名为hello_tutorial的目录,我们来搭建一个简单的demo。
网页
hello_tutorial Native Client Module hello_tutorial
Status
NO-STATUS
NaCl模块
/// @file hello_tutorial.cc /// 载入NaCl模块时,浏览器首先将搜索CreateModule()方法,CreateModule()会返回一个对象实例, /// 之后浏览器会调用该实例的CreateInstance()方法,这时浏览器每遇到一次相应的
Makefile
Makefile是C\C++编译指令的存放文件,这份文件将指引编译器、链接器如何工作。因为我们现在所处情况特殊,所以Makefile需要自己编写。
# Copyright (c) 2012 The Native Client Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # # GNU Make based build file. For details on GNU Make see: # http://www.gnu.org/software/make/manual/make.html # # # Project information # # 这里的变量将指出每个项目的编译信息,如项目名、编译标志等等。 # 通常每个项目都将有所不同。这里只是作为一个demo,因此只有一些最简单的信息。 # 注意,编辑这里的内容需要你对编译器有足够的了解 # PROJECT:=hello_tutorial LDFLAGS:=-lppapi_cpp -lppapi CXX_SOURCES:=$(PROJECT).cc # # 设置pepper目录 # THIS_MAKEFILE:=$(abspath $(lastword $(MAKEFILE_LIST))) NACL_SDK_ROOT?=$(abspath $(dir $(THIS_MAKEFILE))../..) # Project Build flags WARNINGS:=-Wno-long-long -Wall -Wswitch-enum -pedantic -Werror CXXFLAGS:=-pthread -std=gnu++98 $(WARNINGS) # # 设置工具路径 # # OSNAME:=$(shell python $(NACL_SDK_ROOT)/tools/getos.py) TC_PATH:=$(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_x86_newlib) CXX:=$(TC_PATH)/bin/i686-nacl-g++ # # Cygwin专用设置 # CYGWIN ?= nodosfilewarning export CYGWIN # Declare the ALL target first, to make the 'all' target the default build all: $(PROJECT)_x86_32.nexe $(PROJECT)_x86_64.nexe # 32位文件生成规则 x86_32_OBJS:=$(patsubst %.cc,%_32.o,$(CXX_SOURCES)) $(x86_32_OBJS) : %_32.o : %.cc $(THIS_MAKE) $(CXX) -o $@ -c $< -m32 -O0 -g $(CXXFLAGS) $(PROJECT)_x86_32.nexe : $(x86_32_OBJS) $(CXX) -o $@ $^ -m32 -O0 -g $(CXXFLAGS) $(LDFLAGS) # 64位文件生成规则 x86_64_OBJS:=$(patsubst %.cc,%_64.o,$(CXX_SOURCES)) $(x86_64_OBJS) : %_64.o : %.cc $(THIS_MAKE) $(CXX) -o $@ -c $< -m64 -O0 -g $(CXXFLAGS) $(PROJECT)_x86_64.nexe : $(x86_64_OBJS) $(CXX) -o $@ $^ -m64 -O0 -g $(CXXFLAGS) $(LDFLAGS) # Define a phony rule so it always runs, to build nexe and start up server. .PHONY: RUN RUN: all python ../httpd.py
清单文件
清单中指出了不同架构所使用的模块。
{ "program": { "x86-64": {"url": "hello_tutorial_x86_64.nexe"}, "x86-32": {"url": "hello_tutorial_x86_32.nexe"} } }
所有这些文件齐全之后,只需要make
即可完成自动编译。
如何运行
在编译之后,双击html页面打开其实并不会载入模块运行,这是由于浏览器的访问域规则不允许直接在用户的本地读取文件。因此,我们需要让本机成为一个服务器,以远程服务器的身份来读取模块最终传送给浏览器。
这很容易,SDK当中已经包含了提供http服务的python脚本:
cd pepper_18/examples #注意,pepper的版本号应该依据你现有的情况来定 python httpd.py
这样,http://localhost:5103
就成为了我们的服务器地址。注意,http服务的根目录的位置位于examples目录。
现在,我们在浏览器的chrome://flags
和chrome://plugins
页面中打开NaCl的几个相关选项,就可以成功运行了。
Pingback: 剑走偏锋的 Native Client | 谷奥——探寻谷歌的奥秘
Pingback: 谷奥: 剑走偏锋的 Native Client | The World of Yesterday
Pingback: Definite Digest » 谷奥: 剑走偏锋的 Native Client