編譯nodejs及其源碼研究

來源:互聯網
上載者:User

標籤:node nodejs 編譯node n

本文將從 源碼 研究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;




編譯nodejs及其源碼研究

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.