diff --git a/common.gypi b/common.gypi index b372b252045e38..8c1d737f81142c 100644 --- a/common.gypi +++ b/common.gypi @@ -66,9 +66,9 @@ ['build_v8_with_gn == "true"', { 'conditions': [ ['GENERATOR == "ninja"', { - 'v8_base': '<(PRODUCT_DIR)/obj/deps/v8/gypfiles/v8_monolith.gen/gn/obj/libv8_monolith.a', + 'v8_base': '<(PRODUCT_DIR)/obj/deps/v8/gypfiles/v8_monolith.gen/gn/obj/<(STATIC_LIB_PREFIX)v8_monolith<(STATIC_LIB_SUFFIX)', }, { - 'v8_base': '<(PRODUCT_DIR)/obj.target/v8_monolith/geni/gn/obj/libv8_monolith.a', + 'v8_base': '<(PRODUCT_DIR)/obj.target/v8_monolith/geni/gn/obj/<(STATIC_LIB_PREFIX)v8_monolith<(STATIC_LIB_SUFFIX)', }], ], }], diff --git a/configure b/configure index 0cc267558bf39c..71851dc562f833 100755 --- a/configure +++ b/configure @@ -557,6 +557,28 @@ parser.add_option('--build-v8-with-gn', dest='build_v8_with_gn', default=False, help='build V8 using GN instead of gyp') +parser.add_option('--build-v8-with-gn-max-jobs', + dest='build_v8_with_gn_max_jobs', + default='', + help='Value for the -j parameter for the ninja invocation.') +parser.add_option('--build-v8-with-gn-max-load', + dest='build_v8_with_gn_max_load', + default='', + help='Value for the -l parameter for the ninja invocation.') +parser.add_option('--build-v8-with-gn-extra-gn-args', + dest='build_v8_with_gn_extra_gn_args', + default='', + help='Extra gn args to pass add to the "gn gen --args "..." invocation') +parser.add_option('--use-clang-cl', + action='store_true', + dest='use_clang_cl', + default=False, + help='On Windows, build using clang-cl. By default, uses the copy of ' + 'clang-cl that is bundled with V8. Requires --ninja.') +parser.add_option('--clang-cl-base-path', + dest='clang_cl_base_path', + help='Absolute path to a directory containing a bin\\clang-cl.exe ' + '(requires --use-clang-cl).') # Create compile_commands.json in out/Debug and out/Release. parser.add_option('-C', @@ -572,7 +594,6 @@ options.prefix = os.path.expanduser(options.prefix or '') # set up auto-download list auto_downloads = nodedownload.parse(options.download_list) - def warn(msg): warn.warned = True prefix = '\033[1m\033[93mWARNING\033[0m' if os.isatty(1) else 'WARNING' @@ -581,6 +602,22 @@ def warn(msg): # track if warnings occurred warn.warned = False +if options.use_clang_cl: + if not options.use_ninja: + warn('--use-clang-cl requires --ninja') + if options.clang_cl_base_path: + clang_base_path = options.clang_cl_base_path + else: + clang_base_path = os.path.abspath(os.path.join( + 'deps', 'v8', 'third_party', 'llvm-build', 'Release+Asserts')) + # CC sets the path for GYP-compiled files. + os.environ['CC'] = os.path.join(clang_base_path, 'bin', 'clang-cl.exe') + # GN arg sets the path for --build-v8-using-gn. + if options.build_v8_with_gn_extra_gn_args: + options.build_v8_with_gn_extra_gn_args += ' ' + options.build_v8_with_gn_extra_gn_args += 'clang_base_path="{}"'.format( + clang_base_path) + def b(value): """Returns the string 'true' if value is truthy, 'false' otherwise.""" if value: @@ -1049,11 +1086,24 @@ def configure_v8(o): if options.without_bundled_v8 and options.build_v8_with_gn: raise Exception( '--build-v8-with-gn is incompatible with --without-bundled-v8.') + o['variables']['build_v8_with_gn'] = b(options.build_v8_with_gn) if options.build_v8_with_gn: v8_path = os.path.join('deps', 'v8') print('Fetching dependencies to build V8 with GN') - options.build_v8_with_gn = FetchDeps(v8_path) - o['variables']['build_v8_with_gn'] = b(options.build_v8_with_gn) + # Default to non-Googler configuration. + if 'DEPOT_TOOLS_WIN_TOOLCHAIN' not in os.environ: + os.environ['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0' + depot_tools = FetchDeps(v8_path) + + o['variables']['build_v8_with_gn_extra_gn_args'] = ( + options.build_v8_with_gn_extra_gn_args) + o['variables']['build_v8_with_gn_max_jobs'] = ( + options.build_v8_with_gn_max_jobs) + o['variables']['build_v8_with_gn_max_load'] = ( + options.build_v8_with_gn_max_load) + o['variables']['build_v8_with_gn_bundled_win_toolchain'] = ( + os.environ['DEPOT_TOOLS_WIN_TOOLCHAIN']) + o['variables']['build_v8_with_gn_depot_tools'] = depot_tools def configure_openssl(o): diff --git a/deps/v8/gypfiles/v8-monolithic.gyp b/deps/v8/gypfiles/v8-monolithic.gyp index b5ca0ad150b7a6..a93e00752b2120 100644 --- a/deps/v8/gypfiles/v8-monolithic.gyp +++ b/deps/v8/gypfiles/v8-monolithic.gyp @@ -23,19 +23,32 @@ 'include_dirs': [ '../include/', ], + 'link_settings': { + 'conditions': [ + ['OS=="win"', { + 'libraries': ['-ldbghelp.lib', '-lshlwapi.lib', '-lwinmm.lib', '-lws2_32.lib'], + }], + ['OS=="linux"', { + 'libraries': ['-ldl', '-lrt'], + }], + ], + }, }, 'actions': [ { - 'action_name': 'build_with_gn', + 'action_name': 'build_with_gn_generate_build_files', + # No need to list full set of inputs because after the initial + # generation, ninja (run by the next action), will check to see + # if build.ninja is stale. 'inputs': [ - '../tools//node/build_gn.py', + '../tools/node/build_gn.py', ], 'outputs': [ - '<(INTERMEDIATE_DIR)/gn/obj/libv8_monolith.a', - '<(INTERMEDIATE_DIR)/gn/args.gn', + '<(INTERMEDIATE_DIR)/gn/build.ninja', ], 'action': [ - '../tools//node/build_gn.py', + 'python', + '../tools/node/build_gn.py', '--mode', '<(CONFIGURATION_NAME)', '--v8_path', '../', '--build_path', '<(INTERMEDIATE_DIR)/gn', @@ -49,7 +62,53 @@ '--flag', 'v8_optimized_debug=<(v8_optimized_debug)', '--flag', 'v8_enable_disassembler=<(v8_enable_disassembler)', '--flag', 'v8_postmortem_support=<(v8_postmortem_support)', + '--bundled-win-toolchain', '<(build_v8_with_gn_bundled_win_toolchain)', + '--depot-tools', '<(build_v8_with_gn_depot_tools)', + ], + 'conditions': [ + ['build_v8_with_gn_extra_gn_args != ""', { + 'action': [ + '--extra-gn-args', '<(build_v8_with_gn_extra_gn_args)', + ], + }], + ], + }, + { + 'action_name': 'build_with_gn', + 'inputs': [ + '../tools/node/build_gn.py', + '<(INTERMEDIATE_DIR)/gn/build.ninja', + ], + # Specify a non-existent output to make the target permanently dirty. + # Alternatively, a depfile could be used, but then two dirty checks + # would run: one by the outer build tool, and one by build_gn.py. + 'outputs': [ + '<(v8_base)', + 'does-not-exist', + ], + 'action': [ + 'python', + '../tools/node/build_gn.py', + '--build_path', '<(INTERMEDIATE_DIR)/gn', + '--v8_path', '../', + '--bundled-win-toolchain', '<(build_v8_with_gn_bundled_win_toolchain)', + '--depot-tools', '<(build_v8_with_gn_depot_tools)', + '--build', + ], + 'conditions': [ + ['build_v8_with_gn_max_jobs!=""', { + 'action': [ + '--max-jobs', '<(build_v8_with_gn_max_jobs)', + ], + }], + ['build_v8_with_gn_max_load!=""', { + 'action': [ + '--max-load', '<(build_v8_with_gn_max_load)', + ], + }], ], + # Allows sub-ninja's build progress to be printed. + 'ninja_use_console': 1, }, ], }, diff --git a/deps/v8/tools/node/build_gn.py b/deps/v8/tools/node/build_gn.py index e95c3491e74802..2faf5ab1124e61 100755 --- a/deps/v8/tools/node/build_gn.py +++ b/deps/v8/tools/node/build_gn.py @@ -25,15 +25,20 @@ import node_common GN_ARGS = [ - "v8_monolithic = true", - "is_component_build = false", - "v8_use_external_startup_data = false", - "use_custom_libcxx = false", - "use_sysroot = false", + "v8_monolithic=true", + "is_component_build=false", + "v8_use_external_startup_data=false", + "use_custom_libcxx=false", ] BUILD_TARGET = "v8_monolith" +def FindTargetOs(flags): + for flag in flags: + if flag.startswith("target_os="): + return flag[len("target_os="):].strip('"') + raise Exception('No target_os was set.') + def FindGn(options): if options.host_os == "linux": os_path = "linux64" @@ -46,57 +51,85 @@ def FindGn(options): return os.path.join(options.v8_path, "buildtools", os_path, "gn") def GenerateBuildFiles(options): - print "Setting GN args." gn = FindGn(options) - gn_args = [] - gn_args.extend(GN_ARGS) + gn_args = list(GN_ARGS) + target_os = FindTargetOs(options.flag) + if target_os != "win": + gn_args.append("use_sysroot=false") + for flag in options.flag: flag = flag.replace("=1", "=true") flag = flag.replace("=0", "=false") flag = flag.replace("target_cpu=ia32", "target_cpu=\"x86\"") gn_args.append(flag) if options.mode == "DEBUG": - gn_args.append("is_debug = true") + gn_args.append("is_debug=true") else: - gn_args.append("is_debug = false") + gn_args.append("is_debug=false") + + flattened_args = ' '.join(gn_args) + if options.extra_gn_args: + flattened_args += ' ' + options.extra_gn_args - if not os.path.isdir(options.build_path): - os.makedirs(options.build_path) - with open(os.path.join(options.build_path, "args.gn"), "w") as args_file: - args_file.write("\n".join(gn_args)) - subprocess.check_call([gn, "gen", "-C", options.build_path], - cwd=options.v8_path) + args = [gn, "gen", options.build_path, "-q", "--args=" + flattened_args] + subprocess.check_call(args) def Build(options): - print "Building." depot_tools = node_common.EnsureDepotTools(options.v8_path, False) ninja = os.path.join(depot_tools, "ninja") - subprocess.check_call([ninja, "-v", "-C", options.build_path, BUILD_TARGET], - cwd=options.v8_path) + if sys.platform == 'win32': + # Required because there is an extension-less file called "ninja". + ninja += ".exe" + args = [ninja, "-C", options.build_path, BUILD_TARGET] + if options.max_load: + args += ["-l" + options.max_load] + if options.max_jobs: + args += ["-j" + options.max_jobs] + else: + with open(os.path.join(options.build_path, "args.gn")) as f: + if "use_goma = true" in f.read(): + args += ["-j500"] + subprocess.check_call(args) def ParseOptions(args): parser = argparse.ArgumentParser( description="Build %s with GN" % BUILD_TARGET) parser.add_argument("--mode", help="Build mode (Release/Debug)") - parser.add_argument("--v8_path", help="Path to V8") - parser.add_argument("--build_path", help="Path to build result") + parser.add_argument("--v8_path", help="Path to V8", required=True) + parser.add_argument("--build_path", help="Path to build result", + required=True) parser.add_argument("--flag", help="Translate GYP flag to GN", action="append") parser.add_argument("--host_os", help="Current operating system") + parser.add_argument("--bundled-win-toolchain", + help="Value for DEPOT_TOOLS_WIN_TOOLCHAIN") + parser.add_argument("--depot-tools", help="Absolute path to depot_tools") + parser.add_argument("--extra-gn-args", help="Additional GN args") + parser.add_argument("--build", help="Run ninja as opposed to gn gen.", + action="store_true") + parser.add_argument("--max-jobs", help="ninja's -j parameter") + parser.add_argument("--max-load", help="ninja's -l parameter") options = parser.parse_args(args) - assert options.host_os - assert options.mode == "Debug" or options.mode == "Release" + options.build_path = os.path.abspath(options.build_path) - assert options.v8_path - options.v8_path = os.path.abspath(options.v8_path) - assert os.path.isdir(options.v8_path) + if not options.build: + assert options.host_os + assert options.mode == "Debug" or options.mode == "Release" + + options.v8_path = os.path.abspath(options.v8_path) + assert os.path.isdir(options.v8_path) - assert options.build_path - options.build_path = os.path.abspath(options.build_path) return options + if __name__ == "__main__": options = ParseOptions(sys.argv[1:]) - GenerateBuildFiles(options) - Build(options) + # Build can result in running gn gen, so need to set environment variables + # for build as well as generate. + os.environ['DEPOT_TOOLS_WIN_TOOLCHAIN'] = options.bundled_win_toolchain + os.environ['PATH'] += os.path.pathsep + options.depot_tools + if not options.build: + GenerateBuildFiles(options) + else: + Build(options) diff --git a/deps/v8/tools/node/fetch_deps.py b/deps/v8/tools/node/fetch_deps.py index 945dbb7677f4f3..26b9d6a72f6eec 100755 --- a/deps/v8/tools/node/fetch_deps.py +++ b/deps/v8/tools/node/fetch_deps.py @@ -43,18 +43,21 @@ ] def EnsureGit(v8_path): + def git(args): + # shell=True needed on Windows to resolve git.bat. + return subprocess.check_output( + "git " + args, cwd=v8_path, shell=True).strip() + expected_git_dir = os.path.join(v8_path, ".git") - actual_git_dir = subprocess.check_output( - ["git", "rev-parse", "--absolute-git-dir"], cwd=v8_path).strip() + actual_git_dir = git("rev-parse --absolute-git-dir") if expected_git_dir == actual_git_dir: print "V8 is tracked stand-alone by git." return False print "Initializing temporary git repository in v8." - subprocess.check_call(["git", "init"], cwd=v8_path) - subprocess.check_call(["git", "config", "user.name", "\"Ada Lovelace\""], cwd=v8_path) - subprocess.check_call(["git", "config", "user.email", "\"ada@lovela.ce\""], cwd=v8_path) - subprocess.check_call(["git", "commit", "--allow-empty", "-m", "init"], - cwd=v8_path) + git("init") + git("config user.name \"Ada Lovelace\"") + git("config user.email ada@lovela.ce") + git("commit --allow-empty -m init") return True def FetchDeps(v8_path): @@ -86,8 +89,8 @@ def FetchDeps(v8_path): os.path.join(v8_path, os.pardir, ".gclient_entries")) if os.path.isfile(gclient_entries): os.remove(gclient_entries) - # Enable building with GN for configure script. - return True + + return depot_tools if __name__ == "__main__": diff --git a/deps/v8/tools/node/node_common.py b/deps/v8/tools/node/node_common.py index 72fbd9641aa44b..de2e98d9096461 100755 --- a/deps/v8/tools/node/node_common.py +++ b/deps/v8/tools/node/node_common.py @@ -4,6 +4,7 @@ # found in the LICENSE file. import os +import pipes import shutil import stat import subprocess @@ -22,7 +23,10 @@ def _Get(v8_path): pass if fetch_if_not_exist: print "Checking out depot_tools." - subprocess.check_call(["git", "clone", DEPOT_TOOLS_URL, depot_tools]) + # shell=True needed on Windows to resolve git.bat. + subprocess.check_call("git clone {} {}".format( + pipes.quote(DEPOT_TOOLS_URL), + pipes.quote(depot_tools)), shell=True) return depot_tools return None depot_tools = _Get(v8_path) diff --git a/node.gyp b/node.gyp index 5efe2323599cff..23f07f70650971 100644 --- a/node.gyp +++ b/node.gyp @@ -231,9 +231,18 @@ }, 'msvs_settings': { 'VCLinkerTool': { - 'AdditionalOptions': [ - '/WHOLEARCHIVE:<(PRODUCT_DIR)\\lib\\' - '<(node_core_target_name)<(STATIC_LIB_SUFFIX)', + 'conditions': [ + ['GENERATOR=="ninja"', { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(obj_dir)\\<(STATIC_LIB_PREFIX)' + '<(node_core_target_name)<(STATIC_LIB_SUFFIX)', + ], + }, { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(LIB_DIR)\\<(STATIC_LIB_PREFIX)' + '<(node_core_target_name)<(STATIC_LIB_SUFFIX)', + ], + }], ], }, }, diff --git a/node.gypi b/node.gypi index 0d66a842ad4de1..06d3f40145b222 100644 --- a/node.gypi +++ b/node.gypi @@ -144,8 +144,16 @@ }, 'msvs_settings': { 'VCLinkerTool': { - 'AdditionalOptions': [ - '/WHOLEARCHIVE:<(PRODUCT_DIR)\\lib\\zlib<(STATIC_LIB_SUFFIX)', + 'conditions': [ + ['GENERATOR=="ninja"', { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(obj_dir)\\deps\\zlib\\<(STATIC_LIB_PREFIX)zlib<(STATIC_LIB_SUFFIX)', + ], + }, { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(LIB_DIR)\\<(STATIC_LIB_PREFIX)zlib<(STATIC_LIB_SUFFIX)', + ], + }], ], }, }, @@ -182,8 +190,16 @@ }, 'msvs_settings': { 'VCLinkerTool': { - 'AdditionalOptions': [ - '/WHOLEARCHIVE:<(PRODUCT_DIR)\\lib\\libuv<(STATIC_LIB_SUFFIX)', + 'conditions': [ + ['GENERATOR=="ninja"', { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(obj_dir)\\deps\\uv\\<(STATIC_LIB_PREFIX)libuv<(STATIC_LIB_SUFFIX)', + ], + }, { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(LIB_DIR)\\<(STATIC_LIB_PREFIX)libuv<(STATIC_LIB_SUFFIX)', + ], + }], ], }, }, @@ -262,11 +278,21 @@ 'NODE_PLATFORM="sunos"', ], }], - [ '(OS=="freebsd" or OS=="linux") and node_shared=="false"' - ' and force_load=="true"', { - 'ldflags': [ '-Wl,-z,noexecstack', - '-Wl,--whole-archive <(v8_base)', - '-Wl,--no-whole-archive' ] + [ 'node_shared=="false" and force_load=="true"', { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(v8_base)', + ], + }, + }, + 'conditions': [ + ['OS=="freebsd" or OS=="linux"', { + 'ldflags': [ '-Wl,-z,noexecstack', + '-Wl,--whole-archive <(v8_base)', + '-Wl,--no-whole-archive' ], + }], + ], }], [ 'OS in "mac freebsd linux" and node_shared=="false"' ' and coverage=="true"', { @@ -316,8 +342,16 @@ }, 'msvs_settings': { 'VCLinkerTool': { - 'AdditionalOptions': [ - '/WHOLEARCHIVE:<(PRODUCT_DIR)\\lib\\<(openssl_product)', + 'conditions': [ + ['GENERATOR=="ninja"', { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(obj_dir)\\deps\\openssl\\<(STATIC_LIB_PREFIX)<(openssl_product)', + ], + }, { + 'AdditionalOptions': [ + '/WHOLEARCHIVE:<(LIB_DIR)\\<(STATIC_LIB_PREFIX)<(openssl_product)', + ], + }], ], }, },