【node阅读-0】下载编译node

一、下载编译-windows build

工具 要求 安装方式
Visual Studio 2022 版本 17.13 或更高必须选 "Desktop development with C++" workload必须安装 ClangCL 组件:- C++ Clang Compiler for Windows (Microsoft.VisualStudio.Component.VC.Llvm.Clang)- MSBuild support for LLVM toolset (Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset) 下载地址:https://visualstudio.microsoft.com/downloads/安装时勾选 "C++ 桌面开发"如果已装,打开 Visual Studio Installer → 修改 → 单个组件 → 搜索 "Clang" 勾选上面两个
Python 3 3.12+(推荐 Microsoft Store 版) Microsoft Store 搜索 "Python" 安装最新版,确保在 PATH 中(命令行能运行 python --version)
Git for Windows 包含 Git Bash 和 Unix tools(必须加到 PATH) https://git-scm.com/download/win
NASM(可选,但推荐) 用于 OpenSSL 汇编优化(如果不装,加 --openssl-no-asm 参数) 下载 https://www.nasm.us/ ,解压后加到 PATH 这个我最开始没有设置path ,就默认装c盘了

常见坑:如果缺少 ClangCL,编译会直接报错"missing components"。解决:卸载重装上面两个 Clang 组件。2. 进入源码目录并切换分支(你已经好了这一步)

powershell

powershell 复制代码
git clone https://github.com/nodejs/node.git
cd node  # 进入你 clone 的目录
git checkout v25.x  # 推荐这个最新 Current 分支
git pull    # 拉取最新代码

注意:源码路径不能有空格或中文(比如别放在 C:\Users\你的名字\),否则编译失败!建议放在 C:\node 或 D:\node。3. 编译命令(核心步骤)打开 x64 Native Tools Command Prompt for VS 2022(开始菜单搜索 "x64 Native"),或者用 Git Bash/PowerShell。最简单命令(Release 模式,默认):

powershell

powershell 复制代码
.\vcbuild.bat
  • 编译成功后,可执行文件在:out\Release\node.exe

先贴一个git的链接 https://github.com/theanarkh/understand-nodejs/blob/master/docs/chapter01-Node.js组成和原理.md

二、基本路径

node/src/node_main.cc

python 复制代码
int main(int argc, char* argv[]) {
  return node::Start(argc, argv);
}
#endif

======>

libnode/src/node.cc

python 复制代码
int Start(int argc, char** argv) {
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
  std::tie(argc, argv) = sea::FixupArgsForSEA(argc, argv);
#endif
  return static_cast<int>(StartInternal(argc, argv));
}

int Stop(Environment* env, StopFlags::Flags flags) {
  env->ExitEnv(flags);
  return 0;
}

}  // namespace node

#if !HAVE_INSPECTOR
void Initialize() {}

NODE_BINDING_CONTEXT_AWARE_INTERNAL(inspector, Initialize)
#endif  // !HAVE_INSPECTOR
解析:
  • SEA (Single Executable Applications)
    • 这是 Node.js 较新的功能(实验性或刚稳定),允许你把 Node.js 二进制文件和你的 JS 代码打包成一个单独的可执行文件(类似 pkg 或 deno compile)。
    • #ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION:如果编译 Node.js 时没有禁用 SEA 功能,就会执行里面的代码。
    • sea::FixupArgsForSEA(argc, argv)
      • 如果是普通启动(node script.js),参数就是系统传递的参数。
      • 如果是 SEA 启动(运行打包后的 myapp.exe),系统传递的 argv[0] 是你的程序名,后面可能没有 js 文件名。这个函数负责**"欺骗""修正"**传入的参数,让 Node.js 内核知道"哦,我要运行嵌入在二进制里的那个脚本,而不是去磁盘找文件"。
      • std::tie(...) = ...:这是一个 C++ 语法,用于将 FixupArgsForSEA 返回的一对值(新的 argc 和 argv)批量赋值给当前的 argc 和 argv 变量。
  • StartInternal
    • 这才是真正干活的地方。Start 只是个"前台接待",处理完特殊的参数修正后,把任务交给 StartInternal 去初始化 V8 引擎、加载 libuv 事件循环、运行 JS 代码等。

StartInternal 其他的看不懂不要紧 ,反正就知道这里是入口了

===>

python 复制代码
static ExitCode StartInternal(int argc, char** argv) {
  CHECK_GT(argc, 0);

  // Hack around with the argv pointer. Used for process.title = "blah".
  argv = uv_setup_args(argc, argv);
  // uv_setup_args 是 libuv 的经典函数。
  // 作用:在 Unix-like 系统上,进程的 argv 内存区域紧挨着环境变量(envp),修改 argv 可能覆盖环境变量导致崩溃。
  // libuv 这里会重新分配一块内存,深拷贝 argv 字符串,并返回新指针。
  // 这样后续 JS 中修改 process.title 时,就可以安全地在新内存里改,而不会破坏环境变量。
  // Windows 上这个函数基本是 no-op(直接返回原 argv)。

  std::shared_ptr<InitializationResultImpl> result =
      InitializeOncePerProcessInternal(
          std::vector<std::string>(argv, argv + argc));
  // 这里调用 InitializeOncePerProcessInternal。
  // 它的主要职责:
  // 1. 解析 Node.js 自身的命令行参数(如 --inspect、--title、--experimental-sea 等)
  // 2. 解析并分离 V8 参数(如 --harmony、--max-old-space-size 等,交给 V8 处理)
  // 3. 处理特殊参数:--version、--help、--v8-options 等,会导致程序立即退出
  // 4. 填充 per_process::cli_options(全局选项对象)
  // 5. 返回一个 InitializationResultImpl,包含:
  //    - 处理后的 args 和 exec_args(传给脚本的参数)
  //    - 解析过程中遇到的错误信息
  //    - 是否需要 early return(比如 --version)
  //    - 最终退出码

  // 如果解析参数时有错误(如非法选项),在这里打印出来
  for (const std::string& error : result->errors()) {
    FPrintF(stderr, "%s: %s\n", result->args().at(0).c_str(), error.c_str());
  }

  // 如果是 --version、--help、--v8-options 或其他只需打印信息就退出的选项
  // early_return() 会返回 true,直接退出,不启动 V8 引擎
  if (result->early_return()) {
    return result->exit_code_enum();
  }

  DCHECK_EQ(result->exit_code_enum(), ExitCode::kNoFailure);

  const SnapshotData* snapshot_data = nullptr;

  // 保证函数退出时一定调用 TearDownOncePerProcess() 清理资源
  auto cleanup_process = OnScopeLeave([&]() {
    TearDownOncePerProcess();

    if (snapshot_data != nullptr &&
        snapshot_data->data_ownership == SnapshotData::DataOwnership::kOwned) {
      delete snapshot_data;
    }
  });

  uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);

  // 处理 Single Executable Application (SEA) 功能
  std::string sea_config = per_process::cli_options->experimental_sea_config;
  if (!sea_config.empty()) {
#if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)
    return sea::BuildSingleExecutableBlob(
        sea_config, result->args(), result->exec_args());
#else
    fprintf(stderr, "Single executable application is disabled.\n");
    return ExitCode::kGenericUserError;
#endif
  }

  // --build-snapshot:生成快照模式(用于打包成单可执行文件)
  if (per_process::cli_options->per_isolate->build_snapshot) {
    if (per_process::cli_options->per_isolate->build_snapshot_config.empty() &&
        result->args().size() < 2) {
      fprintf(stderr,
              "--build-snapshot must be used with an entry point script.\n"
              "Usage: node --build-snapshot /path/to/entry.js\n");
      return ExitCode::kInvalidCommandLineArgument;
    }
    return GenerateAndWriteSnapshotData(&snapshot_data, result.get());
  }

  // 普通模式:尝试加载内置快照(blob)
  if (!LoadSnapshotData(&snapshot_data)) {
    return ExitCode::kStartupSnapshotFailure;
  }

  // 创建主 Node 实例,进入事件循环并执行用户脚本
  NodeMainInstance main_instance(snapshot_data,
                                 uv_default_loop(),
                                 per_process::v8_platform.Platform(),
                                 result->args(),
                                 result->exec_args());
  return main_instance.Run();  // 启动 REPL 或运行脚本,直到进程退出
}

三、kale

从第一个词看起

什么是shared_ptr

std::shared_ptr 是 C++ 标准库( 头文件)提供的智能指针之一,用于自动管理动态分配对象的生命周期,支持多个指针共享同一个对象的所有权。

  • 共享所有权:多个 shared_ptr 可以指向同一个对象,当所有 shared_ptr 都销毁或重新指向其他对象时,才会自动删除底层对象。
  • 引用计数:内部使用一个引用计数器(reference count)记录有多少个 shared_ptr 共享这个对象。
  • 拷贝/赋值时:计数 +1
  • 析构或 reset 时:计数 -1
  • 计数降为 0 时:自动 delete 管理的对象
python 复制代码
class Myclass{
public:
    Myclass(int value):data(value) {
        std::cout << "MyClass 构造: " << data << std::endl;
    }
    ~Myclass(){
        std::cout << "MyClass 销毁: " << data << std::endl;

    }
    void print() const {
        std::cout << "值: " << data << std::endl;
    }

    void set(int value) {
        data = value;
    }

private:
    int data;
};


int main() {
    // ============ 彻底解决中文乱码神级代码(Windows 专用)===========
    SetConsoleOutputCP(CP_UTF8);           // 让 printf / cout 输出用 UTF-8
    setvbuf(stdout, nullptr, _IOFBF, 4096);


    std::shared_ptr<Myclass> sp1(new Myclass(11));
    std::cout << "sp1 use_count: " << sp1.use_count() << std::endl;  // 1
    auto sp2 = std::make_shared<Myclass>(22);
    auto sp3=sp2;

    std::cout << "sp2 use_count: " << sp2.use_count() << std::endl;  // 2
    std::cout << "sp1 use_count: " << sp1.use_count() << std::endl;  // 1
    std::cout << "sp3 use_count: " << sp3.use_count() << std::endl;  // 2

    Myclass sp5 = Myclass(55);
    sp5.print();

    sp1->print();
    sp2->print();
    (*sp2).print();

经过一通查概念,其实就是类似python的浅拷贝 ,通过它赋值的新对象,实际上和它是一个引用。

(*sp2).print()

这里怎么怪怪的 , sp5.print(); 是实例对象方法,但是后面两种是什么鬼

写法 含义 等价于 使用场景
sp1->print(); shared_ptr 重载了 operator->,直接返回内部裸指针 sp1.get()->print(); 最常用、最推荐
sp2->print(); 同上,和 sp1 完全一样 同上 同上
(*sp2).print(); 先用 operator* 解引用得到 MyClass& 引用,再用 . 调用 MyClass& obj = *sp2; obj.print(); 想强调"得到对象本身"时

**简单理解 不是普通的箭头 ,而是 sp3-> (注意停顿) print(); **

*sp3-> 这个 是一个整体 ,等于 解引用,****(sp2) 就是它管理的对象 。

  • shared_ptr 提供了一个成员函数叫 .get()。
  • 返回值:返回底层管理的裸指针(raw pointer),类型是 MyClass*。

拿数组类比一下:

cpp 复制代码
int arr[5] = {10, 20, 30, 40, 50};

std::cout << *arr << "\n";      // 输出 10,等价于 arr[0]
std::cout << *(arr + 1) << "\n"; // 输出 20,等价于 arr[1]
std::cout << arr[2] << "\n";     // 输出 30(最常用的下标方式)

好了下篇继续第二行

更多文章,敬请关注gzh:零基础爬虫第一天

相关推荐
Data_agent19 小时前
Python编程实战:从类与对象到设计优雅
爬虫·python
艾上编程21 小时前
第三章——爬虫工具场景之Python爬虫实战:学术文献摘要爬取,助力科研高效进行
开发语言·爬虫·python
失败又激情的man1 天前
爬虫逆向之云片滑块验证码
爬虫
深蓝电商API1 天前
从数据采集到商业变现:网络爬虫技术的实战与边界
android·爬虫
小裴(碎碎念版)1 天前
文件读写常用操作
开发语言·爬虫·python
艾上编程1 天前
第三章——爬虫工具场景之Python爬虫实战:行业资讯爬取与存储,抢占信息先机
开发语言·爬虫·python
Pyeako1 天前
网络爬虫相关操作--selenium库(超详细版)
爬虫·python·selenium
袁袁袁袁满1 天前
基于selenium和亮数据爬取海外电商平台
爬虫·selenium·网络爬虫·数据采集·爬虫实战·电商采集·自动化采集
深蓝电商API1 天前
从 “能爬” 到 “稳爬”:Python 爬虫中级核心技术实战
开发语言·爬虫·python