-
Notifications
You must be signed in to change notification settings - Fork 0
/
export.py
executable file
·98 lines (88 loc) · 3.79 KB
/
export.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python3
import json
import os
import pipes
from optparse import OptionParser
import make
def rule_to_json(rule):
return {
'targets': rule.targets,
'deps': rule.deps,
'cwd': rule.cwd,
'cmds': rule.cmds,
'd_file': rule.d_file,
'order_only_deps': rule.order_only_deps,
'msvc_show_includes': rule.msvc_show_includes,
'stdout_filter': rule.stdout_filter,
'latency': rule.latency,
}
def path_strip(prefix, path):
if not prefix.endswith('/'):
prefix += '/'
if path.startswith(prefix):
path = path[len(prefix):]
return path
# Escape a path for use inside a Makefile. No idea if this is good enough...
def makefile_esc(path):
if ':' in path:
print('ERROR: Make cannot handle paths with colons: %r' % path)
exit(1)
return path.replace('\\', '\\\\').replace(' ', '\\ ')
def rule_to_makefile(fp, rule):
# targets
target_list = [path_strip(rule.cwd, p) for p in rule.targets]
targets = ' '.join(map(makefile_esc, target_list))
# deps
deps = ' '.join([makefile_esc(path_strip(rule.cwd, p)) for p in rule.deps])
# cmds
cmd_list = rule.cmds[:]
target_dirs = {os.path.dirname(t) for t in target_list}
target_dirs.discard('')
if target_dirs:
# Create target directories
cmd_list.insert(0, ['mkdir', '-p'] + list(target_dirs))
cmds = '\n\t'.join([' '.join([pipes.quote(arg) for arg in cmd]) for cmd in cmd_list])
# recipe
fp.write('%s: %s\n\t%s\n\n' % (targets, deps, cmds))
# d_file
if rule.d_file:
fp.write('-include %s\n\n' % (path_strip(rule.cwd, rule.d_file),))
def main():
# Parse command line. This is a copied+pasted subset of options from make.py, but oh well
parser = OptionParser()
parser.add_option('-f', dest='files', action='append', help='specify the path to a rules.py file (default is "rules.py")', metavar='FILE')
parser.add_option('-v', dest='verbose', action='store_true', help='print verbose build output')
parser.add_option('--var', dest='vars', type='str', action='append', default=[], metavar='KEY=VALUE',
help='option in the form key=value, sets a variable in the ctx.vars dictionary for passing to rules')
parser.add_option('--json', dest='json', type='str', metavar='JSON_FILE',
help='dump build rules to the given file in JSON format')
parser.add_option('--makefile', dest='makefile', type='str', help='generate a gnu makefile', metavar='MAKEFILE')
(options, args) = parser.parse_args()
assert not args
if not options.makefile and not options.json:
print("ERROR: must specify either --json or --makefile")
exit(1)
if options.files is None:
options.files = ['rules.py'] # default to "-f rules.py"
cwd = os.getcwd()
# Set up rule DB, reading in make.db files as we go
ctx = make.BuildContext(options.vars)
visited_rules_files = set()
for f in options.files:
make.parse_rules_py(ctx, options, make.normpath(make.joinpath(cwd, f)), visited_rules_files)
# Generate Makefile
if options.makefile:
with open(options.makefile, 'wt', encoding='utf-8') as f:
f.write('# Automatically generated by make.py from %s\n\n' % (options.files,))
for rule in make.rules.values():
rule_to_makefile(f, rule)
if options.json:
# rules is a dictionary that can have the same rule as a value under multiple targets,
# so make a set
all_rules = set(make.rules.values())
all_rules = [rule_to_json(rule) for rule in sorted(all_rules, key=lambda r: tuple(r.targets))]
all_rules = {'rules': all_rules}
with open(options.json, 'w') as f:
json.dump(all_rules, f, sort_keys=True, indent=2)
if __name__ == '__main__':
main()