OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import buildbot_common | 6 import buildbot_common |
7 import make_rules | 7 import make_rules |
8 import optparse | 8 import optparse |
9 import os | 9 import os |
10 import sys | 10 import sys |
11 | 11 |
12 from make_rules import BuildDefineList, BuildLibList, BuildToolDict | 12 from make_rules import MakeRules, SetVar, GenerateCleanRules, GenerateNMFRules |
13 from make_rules import BuildIncludeList, GetBuildRule, BUILD_RULES | |
14 | 13 |
15 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 14 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
16 SDK_SRC_DIR = os.path.dirname(SCRIPT_DIR) | 15 SDK_SRC_DIR = os.path.dirname(SCRIPT_DIR) |
17 SDK_EXAMPLE_DIR = os.path.join(SDK_SRC_DIR, 'examples') | 16 SDK_EXAMPLE_DIR = os.path.join(SDK_SRC_DIR, 'examples') |
18 SDK_DIR = os.path.dirname(SDK_SRC_DIR) | 17 SDK_DIR = os.path.dirname(SDK_SRC_DIR) |
19 SRC_DIR = os.path.dirname(SDK_DIR) | 18 SRC_DIR = os.path.dirname(SDK_DIR) |
20 OUT_DIR = os.path.join(SRC_DIR, 'out') | 19 OUT_DIR = os.path.join(SRC_DIR, 'out') |
21 PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi') | 20 PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi') |
22 | 21 |
23 # Add SDK make tools scripts to the python path. | 22 # Add SDK make tools scripts to the python path. |
24 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) | 23 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) |
25 import getos | 24 import getos |
26 | 25 |
27 SUPPORTED_HOSTS = ['win'] | |
28 | 26 |
29 def ErrorExit(text): | 27 def ErrorExit(text): |
30 ErrorMsgFunc(text) | 28 ErrorMsgFunc(text) |
31 sys.exit(1) | 29 sys.exit(1) |
32 | 30 |
33 | 31 |
34 def Replace(text, replacements): | 32 def Replace(text, replacements): |
35 for key in replacements: | 33 for key in replacements: |
36 val = replacements[key] | 34 val = replacements[key] |
37 if val is not None: | 35 if val is not None: |
38 text = text.replace(key, val) | 36 text = text.replace(key, val) |
39 return text | 37 return text |
40 | 38 |
41 | 39 |
42 def WriteReplaced(srcpath, dstpath, replacements): | 40 def WriteReplaced(srcpath, dstpath, replacements): |
43 text = open(srcpath, 'rb').read() | 41 text = open(srcpath, 'rb').read() |
44 text = Replace(text, replacements) | 42 text = Replace(text, replacements) |
45 open(dstpath, 'wb').write(text) | 43 open(dstpath, 'wb').write(text) |
46 | 44 |
47 | 45 |
48 def SetVar(varname, values): | |
49 if not values: | |
50 return varname + ':=\n' | |
51 | |
52 line = varname + ':=' | |
53 out = '' | |
54 for value in values: | |
55 if len(line) + len(value) > 78: | |
56 out += line[:-1] + '\n' | |
57 line = '%s+=%s ' % (varname, value) | |
58 else: | |
59 line += value + ' ' | |
60 | |
61 if line: | |
62 out += line[:-1] + '\n' | |
63 return out | |
64 | |
65 | |
66 def GenerateSourceCopyList(desc): | 46 def GenerateSourceCopyList(desc): |
67 sources = [] | 47 sources = [] |
68 # Add sources for each target | 48 # Add sources for each target |
69 for target in desc['TARGETS']: | 49 for target in desc['TARGETS']: |
70 sources.extend(target['SOURCES']) | 50 sources.extend(target['SOURCES']) |
71 | 51 |
72 # And HTML and data files | 52 # And HTML and data files |
73 sources.extend(desc.get('DATA', [])) | 53 sources.extend(desc.get('DATA', [])) |
74 | 54 |
75 if desc['DEST'] == 'examples': | 55 if desc['DEST'] == 'examples': |
76 sources.append('common.js') | 56 sources.append('common.js') |
77 | 57 |
78 return sources | 58 return sources |
79 | 59 |
80 | 60 |
81 def GetSourcesDict(sources): | 61 def GetSourcesDict(sources): |
82 source_map = {} | 62 source_map = {} |
83 for key in ['.c', '.cc']: | 63 for key in ['.c', '.cc']: |
84 source_list = [fname for fname in sources if fname.endswith(key)] | 64 source_list = [fname for fname in sources if fname.endswith(key)] |
85 if source_list: | 65 if source_list: |
86 source_map[key] = source_list | 66 source_map[key] = source_list |
87 else: | 67 else: |
88 source_map[key] = [] | 68 source_map[key] = [] |
89 return source_map | 69 return source_map |
90 | 70 |
91 | 71 |
| 72 def GetProjectObjects(source_dict): |
| 73 object_list = [] |
| 74 for key in ['.c', '.cc']: |
| 75 for src in source_dict[key]: |
| 76 object_list.append(os.path.splitext(src)[0]) |
| 77 return object_list |
| 78 |
| 79 |
92 def GetPlatforms(plat_list, plat_filter): | 80 def GetPlatforms(plat_list, plat_filter): |
93 platforms = [] | 81 platforms = [] |
94 for plat in plat_list: | 82 for plat in plat_list: |
95 if plat in plat_filter: | 83 if plat in plat_filter: |
96 platforms.append(plat) | 84 platforms.append(plat) |
97 return platforms | 85 return platforms |
98 | 86 |
99 | 87 |
100 def GenerateToolDefaults(desc, tools): | 88 def GenerateToolDefaults(desc, tools): |
101 defaults = '' | 89 defaults = '' |
102 for tool in tools: | 90 for tool in tools: |
103 defaults += BUILD_RULES[tool]['DEFS'] | 91 defaults += MakeRules(tool).BuildDefaults() |
104 return defaults | 92 return defaults |
105 | 93 |
106 | 94 |
107 def GenerateSettings(desc, tools): | 95 def GenerateSettings(desc, tools): |
108 settings = SetVar('VALID_TOOLCHAINS', tools) | 96 settings = SetVar('VALID_TOOLCHAINS', tools) |
109 settings+= 'TOOLCHAIN?=%s\n\n' % tools[0] | 97 settings+= 'TOOLCHAIN?=%s\n\n' % tools[0] |
110 for target in desc['TARGETS']: | 98 for target in desc['TARGETS']: |
111 name = target['NAME'] | 99 project = target['NAME'] |
112 macro = name.upper() | 100 macro = project.upper() |
113 srcs = GetSourcesDict(target['SOURCES']) | 101 srcs = GetSourcesDict(target['SOURCES']) |
114 | 102 |
115 if srcs['.c']: | 103 c_flags = target.get('CCFLAGS') |
116 flags = target.get('CCFLAGS', ['$(NACL_CCFLAGS)']) | 104 cc_flags = target.get('CXXFLAGS') |
117 settings += SetVar(macro + '_CC', srcs['.c']) | 105 ld_flags = target.get('LDFLAGS') |
118 settings += SetVar(macro + '_CCFLAGS', flags) | |
119 | 106 |
120 if srcs['.cc']: | 107 if c_flags: |
121 flags = target.get('CXXFLAGS', ['$(NACL_CXXFLAGS)']) | 108 settings += SetVar(macro + '_CCFLAGS', c_flags) |
122 settings += SetVar(macro + '_CXX', srcs['.cc']) | 109 if cc_flags: |
123 settings += SetVar(macro + '_CXXFLAGS', flags) | 110 settings += SetVar(macro + '_CXXFLAGS', cc_flags) |
124 | 111 if ld_flags: |
125 flags = target.get('LDFLAGS', ['$(NACL_LDFLAGS)']) | 112 settings += SetVar(macro + '_LDFLAGS', ld_flags) |
126 settings += SetVar(macro + '_LDFLAGS', flags) | |
127 return settings | 113 return settings |
128 | 114 |
129 | 115 |
130 def GetTarget(tool, targ_type, replace): | |
131 pattern = BUILD_RULES[tool]['TOOL'][targ_type] | |
132 return Replace(pattern, replace) | |
133 | |
134 | |
135 def GenerateCompile(target, tool, arch, srcs): | |
136 """Generates a Compile target. | |
137 | |
138 For the given target, toolset and architecture, returns a rule to generate | |
139 the object files for the set of sources. | |
140 | |
141 Returns: | |
142 Returns a tuple containin the objects and the rule. | |
143 """ | |
144 rules = '' | |
145 name = target['NAME'] | |
146 object_sets = [] | |
147 | |
148 defs = BuildDefineList(tool, target.get('DEFINES', [])) | |
149 includes = BuildIncludeList(tool, target.get('INCLUDES', [])) | |
150 | |
151 if srcs['.c']: | |
152 replace = BuildToolDict(tool, name, arch, 'c', | |
153 DEFLIST=defs, INCLUDELIST=includes) | |
154 compile_rule = GetBuildRule(tool, 'CC') | |
155 rules += Replace(compile_rule, replace) | |
156 object_sets.append('$(%s)' % replace['<OBJS>']) | |
157 | |
158 if srcs['.cc']: | |
159 replace = BuildToolDict(tool, name, arch, 'cc', | |
160 DEFLIST=defs, INCLUDELIST=includes) | |
161 compile_rule = GetBuildRule(tool, 'CXX') | |
162 rules += Replace(compile_rule, replace) | |
163 object_sets.append('$(%s)' % replace['<OBJS>']) | |
164 | |
165 return (' '.join(object_sets), rules) | |
166 | |
167 | |
168 def GenerateLink(target, tool, arch, objs): | |
169 """Generate a Link target. | |
170 | |
171 Returns: | |
172 Returns a tuple containing the rule and target. | |
173 """ | |
174 targ_type = target['TYPE'] | |
175 link_rule = GetBuildRule(tool, targ_type.upper()) | |
176 libs = target.get('LIBS', []) | |
177 libs = BuildLibList(tool, libs) | |
178 replace = BuildToolDict(tool, target['NAME'], arch, 'nexe', | |
179 OBJS=objs, LIBLIST=libs) | |
180 rule = Replace(link_rule, replace) | |
181 target_out = GetTarget(tool, targ_type, replace) | |
182 return target_out, rule | |
183 | |
184 | |
185 def GenerateNMF(target, tool): | |
186 nmf_rule = BUILD_RULES[tool]['NMF'] | |
187 replace = BuildToolDict(tool, target['NAME']) | |
188 rule = Replace(nmf_rule, replace) | |
189 target_out = GetTarget(tool, 'nmf', replace) | |
190 return target_out, rule | |
191 | |
192 | |
193 def GenerateRules(desc, tools): | 116 def GenerateRules(desc, tools): |
194 all_targets = [] | 117 all_targets = [] |
195 rules = '' | |
196 clean = [] | 118 clean = [] |
| 119 rules = '#\n# Per target object lists\n#\n' |
| 120 |
| 121 #Determine which projects are in the NMF files. |
| 122 main = None |
| 123 dlls = [] |
| 124 project_list = [] |
| 125 glibc_rename = [] |
| 126 |
| 127 for target in desc['TARGETS']: |
| 128 ptype = target['TYPE'].upper() |
| 129 project = target['NAME'] |
| 130 project_list.append(project) |
| 131 srcs = GetSourcesDict(target['SOURCES']) |
| 132 if ptype == 'MAIN': |
| 133 main = project |
| 134 if ptype == 'SO': |
| 135 dlls.append(project) |
| 136 for arch in ['x86_32', 'x86_64']: |
| 137 glibc_rename.append('-n %s_%s.so,%s.so' % (project, arch, project)) |
| 138 |
| 139 objects = GetProjectObjects(srcs) |
| 140 rules += SetVar('%s_OBJS' % project.upper(), objects) |
| 141 if glibc_rename: |
| 142 rules += SetVar('GLIBC_REMAP', glibc_rename) |
| 143 |
| 144 configs = desc.get('CONFIGS', ['Debug', 'Release']) |
197 for tc in tools: | 145 for tc in tools: |
198 rules += '\n#\n# Rules for %s toolchain\n#\n%s:\n\t$(MKDIR) %s\n' % ( | 146 makeobj = MakeRules(tc) |
199 tc, tc, tc) | 147 arches = makeobj.GetArches() |
200 main = None | 148 rules += makeobj.BuildDirectoryRules(configs) |
201 for target in desc['TARGETS']: | 149 for cfg in configs: |
202 name = target['NAME'] | 150 makeobj.SetConfig(cfg) |
203 srcs = GetSourcesDict(target['SOURCES']) | 151 for target in desc['TARGETS']: |
204 for arch in BUILD_RULES[tc]['ARCHES']: | 152 project = target['NAME'] |
205 objs, comp_rule = GenerateCompile(target, tc, arch, srcs) | 153 ptype = target['TYPE'] |
206 targs, link_rule = GenerateLink(target, tc, arch, objs) | 154 srcs = GetSourcesDict(target['SOURCES']) |
207 rules += comp_rule + link_rule | 155 objs = GetProjectObjects(srcs) |
208 clean.append(objs) | 156 defs = target.get('DEFINES', []) |
209 if target['TYPE'] == 'lib': | 157 incs = target.get('INCLUDES', []) |
210 all_targets.append(targs) | 158 libs = target.get('LIBS', []) |
| 159 lpaths = target.get('LIBPATHS', []) |
| 160 ipaths = target.get('INCPATHS', []) |
| 161 makeobj.SetProject(project, ptype, defs=defs, incs=incs, libs=libs) |
| 162 for arch in arches: |
| 163 makeobj.SetArch(arch) |
| 164 for src in srcs.get('.c', []): |
| 165 rules += makeobj.BuildCompileRule('CC', src) |
| 166 for src in srcs.get('.cc', []): |
| 167 rules += makeobj.BuildCompileRule('CXX', src) |
| 168 rules += '\n' |
| 169 rules += makeobj.BuildObjectList() |
| 170 rules += makeobj.BuildLinkRule() |
| 171 if main: |
| 172 rules += GenerateNMFRules(tc, main, dlls, cfg, arches) |
211 | 173 |
212 if target['TYPE'] == 'main': | 174 rules += GenerateCleanRules(tools, configs) |
213 main = target | 175 rules += '\nall: $(ALL_TARGETS)\n' |
| 176 return '', rules |
214 | 177 |
215 if main: | |
216 targs, nmf_rule = GenerateNMF(main, tc) | |
217 rules += nmf_rule | |
218 all_targets.append(targs) | |
219 rules += '\n.PHONY : clean\nclean:\n\t$(RM) $(DEPFILES) ' + ' '.join(clean) | |
220 rules += '\n\n-include $(DEPFILES)' | |
221 return ' '.join(all_targets), rules | |
222 | |
223 | |
224 def GenerateTargets(desc, tools): | |
225 targets = [] | |
226 rules = '' | |
227 for tc in tools: | |
228 for target in desc['TARGETS']: | |
229 name = target['NAME'] | |
230 replace = BuildToolDict(tc, name) | |
231 target = GetTarget(tc, target['TYPE'], replace) | |
232 if target: | |
233 targets.append(target) | |
234 return targets | |
235 | 178 |
236 | 179 |
237 def GenerateReplacements(desc, tools): | 180 def GenerateReplacements(desc, tools): |
238 # Generate target settings | 181 # Generate target settings |
239 plats = GetPlatforms(desc['TOOLS'], tools) | 182 plats = GetPlatforms(desc['TOOLS'], tools) |
240 | 183 |
241 settings = GenerateSettings(desc, tools) | 184 settings = GenerateSettings(desc, tools) |
242 tool_def = GenerateToolDefaults(desc, tools) | 185 tool_def = GenerateToolDefaults(desc, tools) |
243 all_targets, rules = GenerateRules(desc, tools) | 186 all_targets, rules = GenerateRules(desc, tools) |
244 | 187 |
245 prelaunch = desc.get('LAUNCH', '') | 188 prelaunch = desc.get('LAUNCH', '') |
246 prerun = desc.get('PRE', '') | 189 prerun = desc.get('PRE', '') |
247 postlaunch = desc.get('POST', '') | 190 postlaunch = desc.get('POST', '') |
248 | 191 |
249 targets = GenerateTargets(desc, tools) | 192 target_def = 'all:' |
250 target_def = 'all: ' + all_targets | |
251 | 193 |
252 return { | 194 return { |
253 '__PROJECT_SETTINGS__' : settings, | 195 '__PROJECT_SETTINGS__' : settings, |
254 '__PROJECT_TARGETS__' : target_def, | 196 '__PROJECT_TARGETS__' : target_def, |
255 '__PROJECT_TOOLS__' : tool_def, | 197 '__PROJECT_TOOLS__' : tool_def, |
256 '__PROJECT_RULES__' : rules, | 198 '__PROJECT_RULES__' : rules, |
257 '__PROJECT_PRELAUNCH__' : prelaunch, | 199 '__PROJECT_PRELAUNCH__' : prelaunch, |
258 '__PROJECT_PRERUN__' : prerun, | 200 '__PROJECT_PRERUN__' : prerun, |
259 '__PROJECT_POSTLAUNCH__' : postlaunch | 201 '__PROJECT_POSTLAUNCH__' : postlaunch |
260 } | 202 } |
261 | 203 |
262 | 204 |
263 # 'KEY' : ( <TYPE>, [Accepted Values], <Required?>) | 205 # 'KEY' : ( <TYPE>, [Accepted Values], <Required?>) |
264 DSC_FORMAT = { | 206 DSC_FORMAT = { |
265 'TOOLS' : (list, ['newlib', 'glibc', 'pnacl', 'win'], True), | 207 'TOOLS' : (list, ['newlib', 'glibc', 'pnacl', 'win'], True), |
| 208 'CONFIGS' : (list, ['Debug', 'Release'], False), |
266 'PREREQ' : (list, '', False), | 209 'PREREQ' : (list, '', False), |
267 'TARGETS' : (list, { | 210 'TARGETS' : (list, { |
268 'NAME': (str, '', True), | 211 'NAME': (str, '', True), |
269 'TYPE': (str, ['main', 'nexe', 'lib', 'so'], True), | 212 'TYPE': (str, ['main', 'nexe', 'lib', 'so'], True), |
270 'SOURCES': (list, '', True), | 213 'SOURCES': (list, '', True), |
271 'CCFLAGS': (list, '', False), | 214 'CCFLAGS': (list, '', False), |
272 'CXXFLAGS': (list, '', False), | 215 'CXXFLAGS': (list, '', False), |
273 'LDFLAGS': (list, '', False), | 216 'LDFLAGS': (list, '', False), |
274 'INCLUDES': (list, '', False), | 217 'INCLUDES': (list, '', False), |
275 'LIBS' : (list, '', False) | 218 'LIBS' : (list, '', False) |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 def IsNexe(desc): | 353 def IsNexe(desc): |
411 for target in desc['TARGETS']: | 354 for target in desc['TARGETS']: |
412 if target['TYPE'] == 'main': | 355 if target['TYPE'] == 'main': |
413 return True | 356 return True |
414 return False | 357 return False |
415 | 358 |
416 | 359 |
417 def ProcessHTML(srcroot, dstroot, desc, toolchains): | 360 def ProcessHTML(srcroot, dstroot, desc, toolchains): |
418 name = desc['NAME'] | 361 name = desc['NAME'] |
419 outdir = os.path.join(dstroot, desc['DEST'], name) | 362 outdir = os.path.join(dstroot, desc['DEST'], name) |
420 | |
421 srcfile = os.path.join(srcroot, 'index.html') | 363 srcfile = os.path.join(srcroot, 'index.html') |
422 tools = GetPlatforms(toolchains, desc['TOOLS']) | 364 tools = GetPlatforms(toolchains, desc['TOOLS']) |
| 365 |
| 366 configs = ['Debug', 'Release'] |
| 367 |
423 for tool in tools: | 368 for tool in tools: |
424 dstfile = os.path.join(outdir, 'index_%s.html' % tool); | 369 for cfg in configs: |
425 print 'Writting from %s to %s' % (srcfile, dstfile) | 370 dstfile = os.path.join(outdir, 'index_%s_%s.html' % (tool, cfg)) |
426 replace = { | 371 print 'Writing from %s to %s' % (srcfile, dstfile) |
427 '<NAME>': name, | 372 replace = { |
428 '<TITLE>': desc['TITLE'], | 373 '<config>': cfg, |
429 '<tc>': tool | 374 '<NAME>': name, |
430 } | 375 '<TITLE>': desc['TITLE'], |
431 WriteReplaced(srcfile, dstfile, replace) | 376 '<tc>': tool |
| 377 } |
| 378 WriteReplaced(srcfile, dstfile, replace) |
432 | 379 |
433 replace['<tc>'] = tools[0] | 380 replace['<tc>'] = tools[0] |
| 381 replace['<config>'] = configs[0] |
| 382 |
434 srcfile = os.path.join(SDK_SRC_DIR, 'build_tools', 'redirect.html') | 383 srcfile = os.path.join(SDK_SRC_DIR, 'build_tools', 'redirect.html') |
435 dstfile = os.path.join(outdir, 'index.html') | 384 dstfile = os.path.join(outdir, 'index.html') |
436 WriteReplaced(srcfile, dstfile, replace) | 385 WriteReplaced(srcfile, dstfile, replace) |
437 | 386 |
438 | 387 |
439 def LoadProject(filename, toolchains): | 388 def LoadProject(filename, toolchains): |
440 """Generate a Master Makefile that builds all examples. | 389 """Generate a Master Makefile that builds all examples. |
441 | 390 |
442 Load a project desciption file, verifying it conforms and checking | 391 Load a project desciption file, verifying it conforms and checking |
443 if it matches the set of requested toolchains. Return None if the | 392 if it matches the set of requested toolchains. Return None if the |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 | 502 |
554 if not args: | 503 if not args: |
555 ErrorExit('Please specify one or more projects to generate Makefiles for.') | 504 ErrorExit('Please specify one or more projects to generate Makefiles for.') |
556 | 505 |
557 # By default support newlib and glibc | 506 # By default support newlib and glibc |
558 if not toolchains: | 507 if not toolchains: |
559 toolchains = ['newlib', 'glibc'] | 508 toolchains = ['newlib', 'glibc'] |
560 print 'Using default toolchains: ' + ' '.join(toolchains) | 509 print 'Using default toolchains: ' + ' '.join(toolchains) |
561 | 510 |
562 master_projects = {} | 511 master_projects = {} |
| 512 |
563 for filename in args: | 513 for filename in args: |
564 desc = LoadProject(filename, toolchains) | 514 desc = LoadProject(filename, toolchains) |
565 if not desc: | 515 if not desc: |
566 print 'Skipping %s, not in [%s].' % (filename, ', '.join(toolchains)) | 516 print 'Skipping %s, not in [%s].' % (filename, ', '.join(toolchains)) |
567 continue | 517 continue |
568 | 518 |
569 if desc.get('EXPERIMENTAL', False) and not options.experimental: | 519 if desc.get('EXPERIMENTAL', False) and not options.experimental: |
570 print 'Skipping %s, experimental only.' % (filename,) | 520 print 'Skipping %s, experimental only.' % (filename,) |
571 continue | 521 continue |
572 | 522 |
(...skipping 12 matching lines...) Expand all Loading... |
585 if options.master: | 535 if options.master: |
586 master_in = os.path.join(SDK_EXAMPLE_DIR, 'Makefile') | 536 master_in = os.path.join(SDK_EXAMPLE_DIR, 'Makefile') |
587 for dest, projects in master_projects.iteritems(): | 537 for dest, projects in master_projects.iteritems(): |
588 master_out = os.path.join(options.dstroot, dest, 'Makefile') | 538 master_out = os.path.join(options.dstroot, dest, 'Makefile') |
589 GenerateMasterMakefile(master_in, master_out, projects) | 539 GenerateMasterMakefile(master_in, master_out, projects) |
590 return 0 | 540 return 0 |
591 | 541 |
592 | 542 |
593 if __name__ == '__main__': | 543 if __name__ == '__main__': |
594 sys.exit(main(sys.argv[1:])) | 544 sys.exit(main(sys.argv[1:])) |
OLD | NEW |