编译nodejs及其源码研究

本文将从 源码 研究nodejs 的原理、本质,探讨nodejs的应用场景,以及高性能开发实践指南。

目录:

第一节:编译node.js

第二节:源码分析

进入主题:以下是在win7 64 下进行,其他平台编译 ,请参见官网。

第一节:编译node.js,过程很简单

1、下载源码。  git clone https://github.com/joyent/node

如果没有安装git客户端,可以在打开https://github.com/joyent/node  点击 Download ZIP,进行下载

2、安装 Python 2.6 or 2.7 和 Visual Studio 2010 or 2012,我这里是 Python
2.7.8  和 Visual Studio 2012

3、进入node目录
 执行 vcbuild release

大概
10多分钟 就可以编译成功,在Release目录下会生成node.exe。下面是我编译成功的图。

第二节:源码分析

我们在IDE 中 打开刚才的node目录,方便我们看源码。我这里是Idea查看。

benchmark : 一些nodejs 性能测试 代码

build:编译nodejs 生成目录

Debug:编译nodejs 生成目录

Release:编译nodejs 生成目录

deps:nodejs依赖 的工具包,包括 v8、http_parser、opensslzlib、zlib、uv。。。

doc:文档

lib:包含JavaScript源码

src:包含C++源码

test:测试代码

tools:编译时用到的工具

这里我们只需关注 src 和lib 文件夹。

1、从node.cc 文件 看 node进程 启动过程的

int Start(int argc, char** argv) {
  const char* replaceInvalid = getenv("NODE_INVALID_UTF8");

  if (replaceInvalid == NULL)
    WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8;

#if !defined(_WIN32)
  // Try hard not to lose SIGUSR1 signals during the bootstrap process.
  InstallEarlyDebugSignalHandler();
#endif

  assert(argc > 0);

  // Hack around with the argv pointer. Used for process.title = "blah".
  argv = uv_setup_args(argc, argv);

  // This needs to run *before* V8::Initialize().  The const_cast is not
  // optional, in case you're wondering.
  int exec_argc;
  const char** exec_argv;
  Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

#if HAVE_OPENSSL
  // V8 on Windows doesn't have a good source of entropy. Seed it from
  // OpenSSL's pool.
  V8::SetEntropySource(crypto::EntropySource);
#endif

  int code;
  V8::Initialize();
  {
    Locker locker(node_isolate);
    Isolate::Scope isolate_scope(node_isolate);
    HandleScope handle_scope(node_isolate);
    Local<Context> context = Context::New(node_isolate);
    Environment* env = CreateEnvironment(
        node_isolate, context, argc, argv, exec_argc, exec_argv);
    // Assign env to the debugger's context
    if (debugger_running) {
      HandleScope scope(env->isolate());
      env->AssignToContext(v8::Debug::GetDebugContext());
    }
    // This Context::Scope is here so EnableDebug() can look up the current
    // environment with Environment::GetCurrent().
    // TODO(bnoordhuis) Reorder the debugger initialization logic so it can
    // be removed.
    {
      Context::Scope context_scope(env->context());
      bool more;
      do {
        more = uv_run(env->event_loop(), UV_RUN_ONCE);
        if (more == false) {
          EmitBeforeExit(env);

          // Emit `beforeExit` if the loop became alive either after emitting
          // event, or after running some callbacks.
          more = uv_loop_alive(env->event_loop());
          if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
            more = true;
        }
      } while (more == true);
      code = EmitExit(env);
      RunAtExit(env);
    }
    env->Dispose();
    env = NULL;
  }

  CHECK_NE(node_isolate, NULL);
  node_isolate->Dispose();
  node_isolate = NULL;
  V8::Dispose();

  delete[] exec_argv;
  exec_argv = NULL;

  return code;
}
Environment* CreateEnvironment(Isolate* isolate,
                               Handle<Context> context,
                               int argc,
                               const char* const* argv,
                               int exec_argc,
                               const char* const* exec_argv) {
  HandleScope handle_scope(isolate);

  Context::Scope context_scope(context);
  Environment* env = Environment::New(context);

  uv_check_init(env->event_loop(), env->immediate_check_handle());
  uv_unref(
      reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
  uv_idle_init(env->event_loop(), env->immediate_idle_handle());

  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
  // but not all samples are created equal; mark the wall clock time spent in
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
  // probably fortify in the API contract, namely that the last started prepare
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
  // a prepare or check watcher after us, any samples attributed to its callback
  // will be recorded with state=IDLE.
  uv_prepare_init(env->event_loop(), env->idle_prepare_handle());
  uv_check_init(env->event_loop(), env->idle_check_handle());
  uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()));
  uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));

  if (v8_is_profiling) {
    StartProfilerIdleNotifier(env);
  }

  Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate);
  process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process"));

  Local<Object> process_object = process_template->GetFunction()->NewInstance();
  env->set_process_object(process_object);

  SetupProcessObject(env, argc, argv, exec_argc, exec_argv);
  Load(env);

  return env;
}
void SetupProcessObject(Environment* env,
                        int argc,
                        const char* const* argv,
                        int exec_argc,
                        const char* const* exec_argv) {
  HandleScope scope(env->isolate());

  Local<Object> process = env->process_object();

  process->SetAccessor(env->title_string(),
                       ProcessTitleGetter,
                       ProcessTitleSetter);

  // process.version
  READONLY_PROPERTY(process,
                    "version",
                    FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION));

  // process.moduleLoadList
  READONLY_PROPERTY(process,
                    "moduleLoadList",
                    env->module_load_list_array());

  // process.versions
  Local<Object> versions = Object::New(env->isolate());
  READONLY_PROPERTY(process, "versions", versions);

  const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
                                     "."
                                     NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR);
  READONLY_PROPERTY(versions,
                    "http_parser",
                    FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version));

  // +1 to get rid of the leading 'v'
  READONLY_PROPERTY(versions,
                    "node",
                    OneByteString(env->isolate(), NODE_VERSION + 1));
  READONLY_PROPERTY(versions,
                    "v8",
                    OneByteString(env->isolate(), V8::GetVersion()));
  READONLY_PROPERTY(versions,
                    "uv",
                    OneByteString(env->isolate(), uv_version_string()));
  READONLY_PROPERTY(versions,
                    "zlib",
                    FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));

  const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION);
  READONLY_PROPERTY(
      versions,
      "modules",
      FIXED_ONE_BYTE_STRING(env->isolate(), node_modules_version));
void Load(Environment* env) {
  HandleScope handle_scope(env->isolate());

  // Compile, execute the src/node.js file. (Which was included as static C
  // string in node_natives.h. 'natve_node' is the string containing that
  // source code.)

  // The node.js file returns a function 'f'
  atexit(AtExit);

  TryCatch try_catch;

  // Disable verbose mode to stop FatalException() handler from trying
  // to handle the exception. Errors this early in the start-up phase
  // are not safe to ignore.
  try_catch.SetVerbose(false);

  Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(), "node.js");
  Local<Value> f_value = ExecuteString(env, MainSource(env), script_name);
  if (try_catch.HasCaught())  {
    ReportException(env, try_catch);
    exit(10);
  }
  assert(f_value->IsFunction());
  Local<Function> f = Local<Function>::Cast(f_value);

  // Now we call 'f' with the 'process' variable that we've built up with
  // all our bindings. Inside node.js we'll take care of assigning things to
  // their places.

  // We start the process this way in order to be more modular. Developers
  // who do not like how 'src/node.js' setups the module system but do like
  // Node's I/O bindings may want to replace 'f' with their own function.

  // Add a reference to the global object
  Local<Object> global = env->context()->Global();

大致的过程是这样的 :

加载 V8 、OpenSSL ...

创建 Environment 环境

设置 Process 进程对象

执行 node.js 文件

2、从 node.js 文件 看 global 配置过程,吐槽一下,nodejs的源码写的太搓了,C系语言出生的风格?

这个文件大致是 是配置 全局变量、配置process、定义模块对象。

后面将深入 讲解
node.js 这个文件 、以及结合 src 的C++类,与lib 下的 js代码 讲解nodejs。

我们可以得出一个结论: nodejs  = node API + V8;

时间: 2024-08-05 11:08:12

编译nodejs及其源码研究的相关文章

express中使用 connect-flash 及其源码研究

刚开始摸node.js, 在用express 4.x 的过程中 有一个connect-flash的玩意 如上图, 在 /reg 页面提交注册信息的时候 如若两次输入的密码不匹配则调用请求对象req的flash方法写入提示消息: 然后 在展示 /reg 页面的时候取出抛给视图模版: 看起来就像个字典对象 这个包必须在引用 express-session 包的前提下才能使用 why1 ,并且写入的值 在取出一次后即销毁 why2. 这非常像asp.net mvc里边的 tempdata对象 开源的东

使用VS2005安装和编译QT4.53源码

学习Qt,当然是QT4好.可是装了4.86以后,网上下载的书中的例子大多无法直接用VS执行(个人不喜欢用QT Creator),即打开pro转换的时候出错(我也懒的研究为什么出错了).看了一下发布时间,觉得4.53时间比较合适,是2009年末发布的.也许能运行书上的例子. 因为很懒,所以不想编译QT源代码,最好装上就能用.所以下载了qt-win-opensource-4.5.3-mingw.exe,安装报错,说找不到mingw.所以又下了MinGW-5.1.4.exe,这是个在线安装版本,我非常

Chrome自带恐龙小游戏的源码研究(完)

在上一篇<Chrome自带恐龙小游戏的源码研究(七)>中研究了恐龙与障碍物的碰撞检测,这一篇主要研究组成游戏的其它要素. 游戏分数记录 如图所示,分数及最高分记录显示在游戏界面的右上角,每达到100分就会出现闪烁特效,游戏第一次gameover时显示历史最高分.分数记录器由DistanceMeter构造函数实现,以下是它的全部代码: 1 DistanceMeter.dimensions = { 2 WIDTH: 10, //每个字符的宽度 3 HEIGHT: 13, //每个字符的高 4 DE

Chrome自带恐龙小游戏的源码研究(七)

在上一篇<Chrome自带恐龙小游戏的源码研究(六)>中研究了恐龙的跳跃过程,这一篇研究恐龙与障碍物之间的碰撞检测. 碰撞盒子 游戏中采用的是矩形(非旋转矩形)碰撞.这类碰撞优点是计算比较简单,缺点是对不规则物体的检测不够精确.如果不做更为精细的处理,结果会像下图: 如图所示,两个盒子虽然有重叠部分,但实际情况是恐龙和仙人掌之间并未发生碰撞.为了解决这个问题,需要建立多个碰撞盒子: 不过这样还是有问题,观察图片,恐龙和仙人掌都有四个碰撞盒子,如果每次Game Loop里都对这些盒子进行碰撞检测

使用makefile编译nodejs模块

使用过node-gyp编译nodejs的addon插件的人,一定很好奇,node-gyp到底帮你做了什么事情,还有,如果我们自己做,难度到底如何.本文不作makefile文件语法的讲解,如果你不懂, 没关系,能看懂基本流程就好.抛开node-gyp,你会发现,有些复杂的东西其实是基于很简单的原理. 环境 操作系统为centos7,已经安装了nodejs,版本为0.10.36,其实差不多新的版本就行.编译链也已经准备好,g++命令啦. 编写代码 源文件hello.cc,很简单,基本和官网的hell

Redis源码研究—哈希表

Redis源码研究-哈希表 Category: NoSQL数据库 View: 10,980 Author: Dong 作者:Dong | 新浪微博:西成懂 | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明 网址:http://dongxicheng.org/nosql/redis-code-hashtable/ 本博客的文章集合:http://dongxicheng.org/recommend/ 本博客微信公共账号:hadoop123(微信号为:hadoop-123),分享

ubuntu12.04 编译android4.2源码 gcc: fatal error: no input files错误

============问题描述============ 最近在ubuntu12.04 编译android4.2源码时遇到一个编译错误,错误如下: host C++: libhost <= build/libs/host/pseudolocalize.cpp gcc: fatal error: no input files compilation terminated. make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libhost_inte

使用vs2010编译lua5.1源码生成lua.lib

一.打开vs2010 二.创建项目 新建项目->win32控制台应用程序->下一步->应用程序设置中选择静态库,不勾选预编译头->完成.具体如下图: 三.拷贝源码 将lua源码中的*.h文件拷贝到项目的头文件文件夹下,将lua源码中的*.c文件拷贝到项目的源文件文件夹下. 四.生成lua.lib 项目右键->生成.此时即可在项目的Debug文件夹下看到生成的 lua.lib了. 使用vs2010编译lua5.1源码生成lua.lib,布布扣,bubuko.com

Chrome自带恐龙小游戏的源码研究(五)

在上一篇<Chrome自带恐龙小游戏的源码研究(四)>中实现了障碍物的绘制及移动,从这一篇开始主要研究恐龙的绘制及一系列键盘动作的实现. 会眨眼睛的恐龙 在游戏开始前的待机界面,如果仔细观察会发现恐龙会时不时地眨眼睛.这是通过交替绘制这两个图像实现的: 可以通过一张图片来了解这个过程: 为实现图片的切换,需要一个计时器timer,并且需要知道两张图片切换的时间间隔msPerFrame.当计时器timer的时间大于切换的时间间隔msPerFrame时,将图片切换到下一张,到达最后一张时又从第一张