1010
1111ROOT_DIR = os.path.abspath(os.path.join(__file__, '..', '..'))
1212
13- def install_and_rebuild(args, install_args):
13+ # Run install.py to install headers.
14+ def generate_headers(headers_dir, install_args):
15+ print('Generating headers')
16+ subprocess.check_call([
17+ sys.executable,
18+ os.path.join(ROOT_DIR, 'tools/install.py'),
19+ 'install',
20+ '--silent',
21+ '--headers-only',
22+ '--prefix', '/',
23+ '--dest-dir', headers_dir,
24+ ] + install_args)
25+
26+ # Rebuild addons in parallel.
27+ def rebuild_addons(args):
28+ headers_dir = os.path.abspath(args.headers_dir)
1429 out_dir = os.path.abspath(args.out_dir)
1530 node_bin = os.path.join(out_dir, 'node')
1631 if args.is_win:
@@ -21,71 +36,57 @@ def install_and_rebuild(args, install_args):
2136 else:
2237 node_gyp = os.path.join(ROOT_DIR, args.node_gyp)
2338
24- # Create a temporary directory for node headers.
25- with tempfile.TemporaryDirectory() as headers_dir:
26- # Run install.py to install headers.
27- print('Generating headers')
28- subprocess.check_call([
29- sys.executable,
30- os.path.join(ROOT_DIR, 'tools/install.py'),
31- 'install',
32- '--silent',
33- '--headers-only',
34- '--prefix', '/',
35- '--dest-dir', headers_dir,
36- ] + install_args)
37-
38- # Copy node.lib.
39- if args.is_win:
40- node_lib_dir = os.path.join(headers_dir, 'Release')
41- os.makedirs(node_lib_dir)
42- shutil.copy2(os.path.join(args.out_dir, 'node.lib'),
43- os.path.join(node_lib_dir, 'node.lib'))
39+ # Copy node.lib.
40+ if args.is_win:
41+ node_lib_dir = os.path.join(headers_dir, 'Release')
42+ os.makedirs(node_lib_dir)
43+ shutil.copy2(os.path.join(args.out_dir, 'node.lib'),
44+ os.path.join(node_lib_dir, 'node.lib'))
4445
45- def rebuild_addon (test_dir):
46- print('Building addon in', test_dir)
47- try:
48- process = subprocess.Popen([
49- node_bin,
50- node_gyp,
51- 'rebuild',
52- '--directory', test_dir,
53- '--nodedir', headers_dir,
54- '--python', sys.executable,
55- '--loglevel', args.loglevel,
56- ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
46+ def node_gyp_rebuild (test_dir):
47+ print('Building addon in', test_dir)
48+ try:
49+ process = subprocess.Popen([
50+ node_bin,
51+ node_gyp,
52+ 'rebuild',
53+ '--directory', test_dir,
54+ '--nodedir', headers_dir,
55+ '--python', sys.executable,
56+ '--loglevel', args.loglevel,
57+ ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
5758
58- # We buffer the output and print it out once the process is done in order
59- # to avoid interleaved output from multiple builds running at once.
60- return_code = process.wait()
61- stdout, stderr = process.communicate()
62- if return_code != 0:
63- print(f'Failed to build addon in {test_dir}:')
64- if stdout:
65- print(stdout.decode())
66- if stderr:
67- print(stderr.decode())
59+ # We buffer the output and print it out once the process is done in order
60+ # to avoid interleaved output from multiple builds running at once.
61+ return_code = process.wait()
62+ stdout, stderr = process.communicate()
63+ if return_code != 0:
64+ print(f'Failed to build addon in {test_dir}:')
65+ if stdout:
66+ print(stdout.decode())
67+ if stderr:
68+ print(stderr.decode())
6869
69- except Exception as e:
70- print(f'Unexpected error when building addon in {test_dir}. Error: {e}')
70+ except Exception as e:
71+ print(f'Unexpected error when building addon in {test_dir}. Error: {e}')
7172
72- test_dirs = []
73- skip_tests = args.skip_tests.split(',')
74- only_tests = args.only_tests.split(',') if args.only_tests else None
75- for child_dir in os.listdir(args.target):
76- full_path = os.path.join(args.target, child_dir)
77- if not os.path.isdir(full_path):
78- continue
79- if 'binding.gyp' not in os.listdir(full_path):
80- continue
81- if child_dir in skip_tests:
82- continue
83- if only_tests and child_dir not in only_tests:
84- continue
85- test_dirs.append(full_path)
73+ test_dirs = []
74+ skip_tests = args.skip_tests.split(',')
75+ only_tests = args.only_tests.split(',') if args.only_tests else None
76+ for child_dir in os.listdir(args.target):
77+ full_path = os.path.join(args.target, child_dir)
78+ if not os.path.isdir(full_path):
79+ continue
80+ if 'binding.gyp' not in os.listdir(full_path):
81+ continue
82+ if child_dir in skip_tests:
83+ continue
84+ if only_tests and child_dir not in only_tests:
85+ continue
86+ test_dirs.append(full_path)
8687
87- with ThreadPoolExecutor() as executor:
88- executor.map(rebuild_addon , test_dirs)
88+ with ThreadPoolExecutor() as executor:
89+ executor.map(node_gyp_rebuild , test_dirs)
8990
9091def main():
9192 if sys.platform == 'cygwin':
@@ -94,6 +95,10 @@ def main():
9495 parser = argparse.ArgumentParser(
9596 description='Install headers and rebuild child directories')
9697 parser.add_argument('target', help='target directory to build addons')
98+ parser.add_argument('--headers-dir',
99+ help='path to node headers directory, if not specified '
100+ 'new headers will be generated for building',
101+ default=None)
97102 parser.add_argument('--out-dir', help='path to the output directory',
98103 default='out/Release')
99104 parser.add_argument('--loglevel', help='loglevel of node-gyp',
@@ -108,7 +113,17 @@ def main():
108113 action='store_true', default=(sys.platform == 'win32'))
109114 args, unknown_args = parser.parse_known_args()
110115
111- install_and_rebuild(args, unknown_args)
116+ if args.headers_dir:
117+ rebuild_addons(args)
118+ else:
119+ # When --headers-dir is not specified, generate headers into a temp dir and
120+ # build with the new headers.
121+ try:
122+ args.headers_dir = tempfile.mkdtemp()
123+ generate_headers(args.headers_dir, unknown_args)
124+ rebuild_addons(args)
125+ finally:
126+ shutil.rmtree(args.headers_dir)
112127
113128if __name__ == '__main__':
114129 main()
0 commit comments