blob: 7a3c2f441ad2238285aa26630d649267f4ac73b2 [file] [log] [blame]
Avi Drissman914a636c2022-09-27 20:08:531# Copyright 2017 The Chromium Authors
damargulis5c5337d2017-04-21 22:36:082# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""Used by a js_binary action to compile javascript files.
5
6This script takes in a list of sources and dependencies and compiles them all
7together into a single compiled .js file. The dependencies are ordered in a
8post-order, left-to-right traversal order. If multiple instances of the same
9source file are read, only the first is kept. The script can also take in
10optional --flags argument which will add custom flags to the compiler. Any
11extern files can also be passed in using the --extern flag.
12"""
13
Luciano Pachecoaab13d412021-01-06 08:58:1814from __future__ import print_function
15
Mike Bjorge61bf88e2017-05-14 07:34:0616import argparse
damargulis5c5337d2017-04-21 22:36:0817import os
Mike Bjorge61bf88e2017-05-14 07:34:0618import sys
19
Dan Beam0135f0c2019-01-23 02:18:3720import compiler
damargulis5c5337d2017-04-21 22:36:0821
22
23def ParseDepList(dep):
Christopher Lam997fd812017-11-03 03:42:4024 """Parses a dependency list, returns |sources, deps, externs|."""
25 assert os.path.isfile(dep), (dep +
damargulis5c5337d2017-04-21 22:36:0826 ' is not a js_library target')
27 with open(dep, 'r') as dep_list:
28 lines = dep_list.read().splitlines()
29 assert 'deps:' in lines, dep + ' is not formated correctly, missing "deps:"'
Christopher Lam997fd812017-11-03 03:42:4030 deps_start = lines.index('deps:')
31 assert 'externs:' in lines, dep + ' is not formated correctly, missing "externs:"'
32 externs_start = lines.index('externs:')
33
34 return (lines[1:deps_start],
35 lines[deps_start+1:externs_start],
36 lines[externs_start+1:])
damargulis5c5337d2017-04-21 22:36:0837
38
Trent Apted131641f02018-08-09 23:46:4539# Cache, to avoid reading the same file twice in the dependency tree and
40# processing its dependencies again.
41depcache = {}
42
43def AppendUnique(items, new_items):
44 """Append items in |new_items| to |items|, avoiding duplicates."""
45 # Note this is O(n*n), and assumes |new_items| is already unique, but this is
46 # not a bottleneck overall.
47 items += [i for i in new_items if i not in items]
48
49def CrawlDepsTree(deps):
damargulis5c5337d2017-04-21 22:36:0850 """Parses the dependency tree creating a post-order listing of sources."""
Trent Apted131641f02018-08-09 23:46:4551 global depcache
52
53 if len(deps) == 0:
54 return ([], [])
55
56 new_sources = []
57 new_externs = []
damargulis5c5337d2017-04-21 22:36:0858 for dep in deps:
Trent Apted131641f02018-08-09 23:46:4559 if dep in depcache:
60 cur_sources, cur_externs = depcache[dep]
61 else:
62 dep_sources, dep_deps, dep_externs = ParseDepList(dep)
63 cur_sources, cur_externs = CrawlDepsTree(dep_deps)
64 # Add child dependencies of this node before the current node, then cache.
65 AppendUnique(cur_sources, dep_sources)
66 AppendUnique(cur_externs, dep_externs)
67 depcache[dep] = (cur_sources, cur_externs)
Christopher Lam997fd812017-11-03 03:42:4068
69 # Add the current node's sources and dedupe.
Trent Apted131641f02018-08-09 23:46:4570 AppendUnique(new_sources, cur_sources)
71 AppendUnique(new_externs, cur_externs)
Christopher Lam997fd812017-11-03 03:42:4072
Trent Apted131641f02018-08-09 23:46:4573 return new_sources, new_externs
Christopher Lam997fd812017-11-03 03:42:4074
Trent Apted131641f02018-08-09 23:46:4575
76def CrawlRootDepsTree(deps, target_sources, target_externs):
77 """Parses the dependency tree and adds target sources."""
78 sources, externs = CrawlDepsTree(deps)
79 AppendUnique(sources, target_sources)
80 AppendUnique(externs, target_externs)
Christopher Lam997fd812017-11-03 03:42:4081 return sources, externs
damargulis5c5337d2017-04-21 22:36:0882
83
84def main():
Mike Bjorge61bf88e2017-05-14 07:34:0685 parser = argparse.ArgumentParser()
damargulis5c5337d2017-04-21 22:36:0886 parser.add_argument('-c', '--compiler', required=True,
87 help='Path to compiler')
88 parser.add_argument('-s', '--sources', nargs='*', default=[],
89 help='List of js source files')
Shawn Quereshi7eeef232021-10-19 20:39:2690 parser.add_argument('-o', '--output', required=False,
damargulis5c5337d2017-04-21 22:36:0891 help='Compile to output')
Shawn Quereshi7eeef232021-10-19 20:39:2692 parser.add_argument('--chunks', action='store_true',
93 help='Compile each source to its own chunk')
94 parser.add_argument('--chunk_suffix', required=False,
95 help='String appended to the source when naming a chunk')
damargulis5c5337d2017-04-21 22:36:0896 parser.add_argument('-d', '--deps', nargs='*', default=[],
97 help='List of js_libarary dependencies')
98 parser.add_argument('-b', '--bootstrap',
99 help='A file to include before all others')
100 parser.add_argument('-cf', '--config', nargs='*', default=[],
101 help='A list of files to include after bootstrap and '
102 'before all others')
103 parser.add_argument('-f', '--flags', nargs='*', default=[],
104 help='A list of custom flags to pass to the compiler. '
105 'Do not include leading dashes')
106 parser.add_argument('-e', '--externs', nargs='*', default=[],
107 help='A list of extern files to pass to the compiler')
Christopher Lamc7566742018-07-18 03:02:06108 parser.add_argument('-co', '--checks-only', action='store_true',
109 help='Only performs checks and writes an empty output')
damargulis5c5337d2017-04-21 22:36:08110
111 args = parser.parse_args()
damargulis5c5337d2017-04-21 22:36:08112
Shawn Quereshi7eeef232021-10-19 20:39:26113 # If --chunks is used, args.sources will be added later
114 sources, externs = CrawlRootDepsTree(args.deps, [] if args.chunks else args.sources, args.externs)
damargulis5c5337d2017-04-21 22:36:08115 compiler_args = ['--%s' % flag for flag in args.flags]
Trent Apted131641f02018-08-09 23:46:45116 compiler_args += ['--externs=%s' % e for e in externs]
Shawn Quereshi7eeef232021-10-19 20:39:26117
118 if not args.chunks:
119 compiler_args += [
120 '--js_output_file',
121 args.output,
122 ]
123
damargulis5c5337d2017-04-21 22:36:08124 compiler_args += [
damargulis5c5337d2017-04-21 22:36:08125 '--js',
126 ]
Shawn Quereshi7eeef232021-10-19 20:39:26127
damargulis5c5337d2017-04-21 22:36:08128 if args.bootstrap:
129 compiler_args += [args.bootstrap]
Shawn Quereshi7eeef232021-10-19 20:39:26130
damargulis5c5337d2017-04-21 22:36:08131 compiler_args += args.config
132 compiler_args += sources
133
Shawn Quereshi7eeef232021-10-19 20:39:26134 if args.chunks:
135 chunk_suffix = args.chunk_suffix
136 common_chunk_name = 'common' + chunk_suffix
137 compiler_args += [
138 '--chunk_output_path_prefix {}'.format(args.output),
139 '--chunk {}:auto'.format(common_chunk_name)
140 ]
141
142 for s in args.sources:
143 # '//path/to/target.js' becomes 'target'
144 chunk_name = '{}{}'.format(s.split('/')[-1].split('.')[0], chunk_suffix)
145 compiler_args += [
146 '--chunk {}:1:{}: {}'.format(chunk_name, common_chunk_name, s)
147 ]
148
Christopher Lamc7566742018-07-18 03:02:06149 if args.checks_only:
150 compiler_args += ['--checks-only']
151 open(args.output, 'w').close()
152
Dan Beam0135f0c2019-01-23 02:18:37153 returncode, errors = compiler.Compiler().run_jar(args.compiler, compiler_args)
Mike Bjorge61bf88e2017-05-14 07:34:06154 if returncode != 0:
Luciano Pachecoaab13d412021-01-06 08:58:18155 print(args.compiler, ' '.join(compiler_args))
156 print(errors)
Mike Bjorge61bf88e2017-05-14 07:34:06157
158 return returncode
damargulis5c5337d2017-04-21 22:36:08159
160
161if __name__ == '__main__':
Mike Bjorge61bf88e2017-05-14 07:34:06162 sys.exit(main())