# Options should be in alphabetical order but keep --prefix at the top,
# that's arguably the one people will be looking for most.
parser.add_option('--prefix',
action='store',
dest='prefix',
default='/usr/local',
help='select the install prefix [default: %default]')
parser.add_option('--coverage',
action='store_true',
dest='coverage',
help='Build node with code coverage enabled')
parser.add_option('--debug',
action='store_true',
dest='debug',
help='also build debug build')
......
(options, args) = parser.parse_args()
CXX = os.environ.get('CXX', 'c++' if sys.platform == 'darwin' else 'g++')
在OSX中,GYP的Makefile底层依赖的的c++,其他操作系统都是g++。
run_gyp
最后执行了run_gyp(gyp_args)
在run_gyp中又做了什么呢?
output_dir = os.path.join(os.path.abspath(node_root), 'out')
def run_gyp(args):
# GYP bug.
# On msvs it will crash if it gets an absolute path.
# On Mac/make it will crash if it doesn't get an absolute path.
a_path = node_root if sys.platform == 'win32' else os.path.abspath(node_root)
args.append(os.path.join(a_path, 'node.gyp'))
common_fn = os.path.join(a_path, 'common.gypi')
options_fn = os.path.join(a_path, 'config.gypi')
options_fips_fn = os.path.join(a_path, 'config_fips.gypi')
if os.path.exists(common_fn):
args.extend(['-I', common_fn])
if os.path.exists(options_fn):
args.extend(['-I', options_fn])
if os.path.exists(options_fips_fn):
args.extend(['-I', options_fips_fn])
args.append('--depth=' + node_root)
# There's a bug with windows which doesn't allow this feature.
if sys.platform != 'win32' and 'ninja' not in args:
# Tell gyp to write the Makefiles into output_dir
args.extend(['--generator-output', output_dir])
# Tell make to write its output into the same dir
args.extend(['-Goutput_dir=' + output_dir])
args.append('-Dcomponent=static_library')
args.append('-Dlibrary=static_library')
# Don't compile with -B and -fuse-ld=, we don't bundle ld.gold. Can't be
# set in common.gypi due to how deps/v8/build/toolchain.gypi uses them.
args.append('-Dlinux_use_bundled_binutils=0')
args.append('-Dlinux_use_bundled_gold=0')
args.append('-Dlinux_use_gold_flags=0')
rc = gyp.main(args)
if rc != 0:
print 'Error running GYP'
sys.exit(rc)
# do_cmd: run a command via the above cmd_foo names, if necessary.
# Should always run for a given target to handle command-line changes.
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
# Third argument, if non-zero, makes it do POSTBUILDS processing.
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
# spaces already and dirx strips the ? characters.
define do_cmd
$(if $(or $(command_changed),$(prereq_changed)),
@$(call exact_echo, $($(quiet)cmd_$(1)))
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
$(if $(findstring flock,$(word 2,$(cmd_$1))),
@$(cmd_$(1))
@echo " $(quiet_cmd_$(1)): Finished",
@$(cmd_$(1))
)
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
@$(if $(2),$(fixup_dep))
$(if $(and $(3), $(POSTBUILDS)),
$(call do_postbuilds)
)
)
endef
前言
编译node源码主要有三个步骤
./configue
主要用来生成与操作平台相关的编译配置,比如软件装到哪里、什么参数等信息,执行过后在./out目录生成如下文件:make
指令根据Makefile的配置对node源码进行编译(包括预编译、编译、链接)生成可执行文件,感兴趣的可以参考刨根问底之node-gypmake install
根据配置将其安装到系统路径下,我们一般自己看源码调试是用不上的编译过程详解
./configue
收集命令行参数
收集到的参数是一个map,如下所示:
当然最终版的参数信息原本也会打印出来。
其中要注意的是在调试时别忘了加上prefix和debug。如果不定义prefix的话,执行make install会安装到默认的local/user/目录下;定义debug会按照调试的配置编译,最终会编译到out/Debug目录下(下述./makefile中有描述),同时增加一些配置方便大家调试(打断点等)。
收集编译器和以下library的参数
check_compiler
在这里我们简单看下python是如何检查编译器的
其实就是新开了一个子进程,在其上执行
CXX
,然后获取版本信息。在OSX中,GYP的Makefile底层依赖的的c++,其他操作系统都是g++。
run_gyp
最后执行了
run_gyp(gyp_args)
在run_gyp中又做了什么呢?
主要做了两件事:
比较重要的也是两点:
node.gyp
我们继续深入,看下node.gyp。
node.gyp是一个python的数据结构,打眼看上去似乎很多,容易看着看着就乱了,我们其实可以从target_name入手。这里就不贴代码了,大家感兴趣的可以顺着target_name一个个顺下去。比较重要的是以下几个:
make
Makefile
执行make的话实际上就是按照当前目录下的makefile执行动作,我们看一下makefile。
如果是debug模式,则多执行了
$(NODE_G_EXE)
,$(NODE_G_EXE)
将BUILDTYPE设置为debug,不同之处在于BUILDTYPE=Debug
和out/Debug/$(NODE_EXE)
。随后两个命令都对out/Debug/node做了一个软链,如果是第一次编译,会建立一个软链,链接到node_g。out/Makefile
我们再接着看
out/makefile
。执行编译
这里执行do_cmd将所有源文件进行编译。
do_cmd
接下来我们看下do_cmd做了什么?
其实就是根据参数(源文件类型),执行不同的指令,比如.cc文件就是利用CXX进行编译。
监听所有.mk文件
这里监听了所有.mk文件,相当于这里监听了所有的node相关的文件,只要include的关联文件有改动,在make的时候都会造成out/Makefile的重新编译。
make install
make install用于将可执行文件安装到./configue中的prefix文件中,我们看源码调试过程中用不上。
总结
本问介绍了node源码编译的大致过程,至于调试的话,用clion ide即可,网上有很多文章都介绍过,大家试着配一下就好了。
本文可能有很多不准确的地方,欢迎大家纠正。