欢迎光临散文网 会员登陆 & 注册

nodejs源码解析之一 (windows 编译脚本 vcbuild.bat)

2023-05-06 23:20 作者:二次元阿饭  | 我要投稿

vcbuild.bat 是一个 Windows 平台下的批处理脚本,用于构建 Node.js 源代码。它使用 Visual Studio 的命令行工具 msbuild 来编译和链接 Node.js 的 C++ 模块,生成可执行文件和库文件等。

在 Windows 环境下,如果要自己编译 Node.js 的源代码,需要先安装 Visual Studio,并设置好环境变量。然后,可以运行 vcbuild.bat 脚本来编译源代码,生成 Node.js 可执行文件和库文件等。这个脚本会自动检测操作系统版本和 Visual Studio 的版本,并选择合适的编译选项。


1.试运行


为了追踪 vcbuild.bat 的执行流程,而不实际进行编译(实际编译太费时间),我们需要对脚本做一个修改

首先找到下面这行,在它前面加上 echo,这样就不会进行实际的编译了


执行 vcbuild.bat,观察输出结果

可以看到,vcbuild.bat 的执行过程大概分为下面几步:

  1. 查找 python,找到3.10.2版本

  2. 查找 NASM,用于汇编编译

  3. 查找 Visual Studio 2022,使用 msbuild 编译c++

  4. 调用 Visual Studio 的命令提示符脚本,它初始化了x64环境变量

  5. 执行 python configure 脚本,传入各种 flags

  6. 最后对 node.sln 执行 msbuild

其实脚本还有个初始化过程,不过没有任何输出。下面我们来弄清楚每一步都发生了什么


2.初始化


2.1 help命令


检测第一个参数,如果是 help,跳转到帮助内容

2.2 测试参数


cd到当前文件目录,设置传递给 tools\test.py 的测试参数

2.3 递归处理参数


递归处理脚本参数,设置各种flags

  • :next-arg:处理下一个参数,即参数移位之后的 %1,如果不存在则跳转到 args-done

  • :arg-ok:当前参数%1对应的 flag 设置成功,使用 shift 进行参数移位,将 %2 移动到 %1

  • :arg-ok-2:它的不同在于,%1 和 %2 都被使用之后,需要调用两次 shift,进行两次参数移位

  • :args-done:当 %1 为空时,参数处理完毕

  • 如果 %1 不正确,抛出无效参数错误


2.4 参数后处理


执行参数后处理,设置 configure_flags

  • build_release:构建发布版本

  • msi:使用 msbuild 构建 .msi 安装包

  • package:将编译结果打包为 zip 文件

  • node_exe:设置编译结果的 node / npm / node_gyp 的执行路径

  • lint:执行 js 和 cpp 代码lint

  • configure_flags:传递给 configure python 脚本的 flags

  • deps\icu:如果 icu 库已经存在,则需要先删除它,后面会下载 icu 库

  • TestClean:清理临时测试文件


3.查找python


调用查找 python 的脚本,如果出错则离开

下面查看 tools\msvs\find_python.cmd 的内容


设置脚本

  • DEBUG_HELPER:如果没有开启 debug,则不输出执行的命令

  • enabledelayedexpansion:启用延迟扩展,变量将在每次执行该行时扩展,默认情况下扩展只发生一次


在 PATH 环境变量里查找 python

  • need_path:如果python不在 PATH 环境变量里,则为1,代表需要将其加入 PATH 环境变量

  • for /f:for代表循环,/f 指对结果进行文件解析,将其分解为单独的文本行并将每一行解析为零或多个标记

  • "delims=":指定分隔符,此处分隔符为空

  • %%a:变量名,代表每一行的文本

  • ('where python.exe 2^> nul'):使用 where 命令查找 python 的位置,2^> nul 指重定向错误输出

  • set p=%%~dpa:设置 p 为当前行中的 python 路径

  • :found-python:已经找到 python,跳转到指定 label


在注册表里查找 python 安装路径

  • need_path:python 不在 PATH 环境变量里,如果找到了,需要将其加入 PATH

  • %%k:代表指定的注册表路径

  • :find-versions:调用标签,在指定的注册表路径中查找 python 版本

  • :found-python:如果错误码不是1,则找到 python


  • for /f "delims=" %%a in:遍历命令执行结果的每一行,每行内容保存在 %%a 中

  • %~1\Python\PythonCore:使用第一个参数组成注册表的键,也就是上面传递的注册表路径

  • reg query:查询注册表的命令

  • /f *: 查找指定键下与通配符匹配的项

  • /k:只查找键,不包括值数据

  • 2^> nul:错误输出重定向到空设备

  • ^|:管道,将前面命令的输出作为后面命令的输入

  • findstr /r ^^HK:在命令结果中查找包含指定字符串的行,^^代表^的转义

  • :read-installpath:将读取到的完整注册表路径传递给标签,用于获取安装路径

  • exit /b 0:如果错误码不是1,则查找成功

  • exit /b 1:如果查找失败,向上级返回错误码 1

  • "skip=2 tokens=1* delims=)":跳过命令结果前两行,使用')'作为分隔符,只获取第一部分

  • /ve:对值为空的进行查询,即查询默认值

  • /t REG_SZ:值类型为字符串

  • %%b:在 %%a 后面的第二部分,')'是分隔符

  • %%c:将 %%b 按空格分割后的字符串,

  • "%%c"=="REG_SZ":如果类型不是字符串,则报错

  • %%d:在 %%c 后面的第二部分,空格是分隔符


已经找到 python

  • :check-python:检查 python 版本

  • pt=%p%:设置 python 的路径

  • need_path_ext=%need_path%:是否需要把 python 路径加入 PATH 环境变量里


检查 python 版本

4.查找NASM


nasm用于编译 openssl 里的汇编语言,在arm64架构下需要

查找方式和 python 基本一样

5.查找node版本


调用获取node版本的label

  • || exit /b 1:如果标签执行成功,则后面的exit不会执行,如果失败则退出


调用获取 node 版本的python脚本,输出类似 21.0.0

  • for /F:逐行读取脚本输出

  • usebackq:开启反引号包含的命令行模式

  • tokens=*:读取整行并存储在 %%i 中

  • 如果 NODE_VERSION 不存在则返回错误码 1


下面看下 getnodeversion.py ,它主要从 node_version.h 源码中读取当前源码的版本

然后需要决定打包名称 TARGET_NAME,里面包含了 node 版本和系统架构

6.查找 visual studio 工具链


6.1 msvs架构


首先设置 msbuild 环境变量

  • msvs_host_arch:msvs宿主架构,x86 或者 amd64

  • vcvarsall_arg:传递给 vcvarsall.bat 脚本的架构参数,在我的64位系统上是 amd64


6.2 查找 vs2022


首先查找 visual studio 2022

  • target_env:可以设置为 vs2022 或 vs2019


  • VCINSTALLDIR:visual studio安装目录

  • vswhere_usability_wrapper.cmd:查找 vs installer 目录,目的是使用 vswhere 程序


下面查看 vswhere_usability_wrapper.cmd 脚本

  • 首先在 %ProgramFiles(x86)% 中查找 visual studio installer 目录

  • 然后在 %ProgramFiles% 中查找

  • 将 installer 目录加入 PATH 环境变量

  • where vswhere:在 PATH 环境变量中查找 vswhere ,如果没找到返回错误码1

  • vswhere %VSWHERE_ARGS%:执行 vswhere 查找,返回值只有一行vs的安装目录

  • VCINSTALLDIR:设置 VC 安装目录

  • VS150COMNTOOLS:设置工具目录


  • VSINSTALLDIR:清理它的值,让叫不能按照预期工作

  • VSCMD_START_DIR:防止更改当前工作目录

  • vcvarsall.bat:配置 Visual C++ 环境的批处理脚本,初始化了 x64 架构下的环境变量


6.3 查找 vs2019


基本过程和查找 vs2022 相同


7.执行 configure


7.1 处理configure参数


  • noprojgen:跳过项目生成,直接构建

  • projgen:项目生成,run configure

  • .tmp_gyp_configure_stamp:将 configure_flags 和 .gyp 文件的路径写入临时文件中

  • .gyp_configure_stamp:如果与临时文件不一致,则 run configure


7.2 运行 configure


  • .tmp_gyp_configure_stamp:删除临时文件

  • configure:运行 configure python 脚本

  • create-msvs-files-failed:项目生成失败

  • project_generated:项目生成成功


8.msbuild 构建


8.1 执行构建


  • nobuild:如果不需要构建,直接跳过

  • msbcpu:设置msbuild 构建使用的 cpu 数量

  • msbplatform:msbuild 构建的目标平台

  • msbuild node.sln:对解决方案执行构建


8.2 构建后处理


  • rd %config%:删除配置目录

  • mklink /J:创建符号链接, out\%config% 到 %config%


9.签名


签名是对可执行文件进行数字签名,以证明文件的来源和完整性,确保文件未被篡改,从而提高文件的安全性。

下面查看 tools/sign.bat 脚本

  • timeservers:多个时间戳服务器的地址

  • signtool sign:使用签名工具对输入文件进行数字签名


10.小结


大致的构建过程就是这样,vcbuild.bat 里还包含了其他的功能,可以被各种参数打开

后面有机会再进行梳理


nodejs源码解析之一 (windows 编译脚本 vcbuild.bat)的评论 (共 条)

分享到微博请遵守国家法律