Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env dart | 1 #!/usr/bin/env dart |
| 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 /// Command line tool to merge the SDK libraries and our patch files. | 6 /// Command line tool to merge the SDK libraries and our patch files. |
| 7 /// This is currently designed as an offline tool, but we could automate it. | 7 /// This is currently designed as an offline tool, but we could automate it. |
| 8 | 8 |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'dart:async'; | 10 import 'dart:async'; |
| 11 import 'dart:math' as math; | 11 import 'dart:math' as math; |
| 12 | 12 |
| 13 import 'package:analyzer/analyzer.dart'; | 13 import 'package:analyzer/analyzer.dart'; |
| 14 import 'package:analyzer/src/generated/sdk.dart'; | 14 import 'package:analyzer/src/generated/sdk.dart'; |
| 15 import 'package:path/path.dart' as path; | 15 import 'package:path/path.dart' as path; |
| 16 import 'package:front_end/src/fasta/compile_platform.dart' as | 16 import 'package:front_end/src/fasta/compile_platform.dart' as |
| 17 compile_platform; | 17 compile_platform; |
| 18 | 18 |
| 19 import 'package:front_end/src/fasta/outline.dart' show CompileTask; | |
| 20 | |
| 21 import 'package:front_end/src/fasta/compiler_command_line.dart' show CompilerCom mandLine; | |
|
kustermann
2017/03/03 13:23:08
nit: long line
Vyacheslav Egorov (Google)
2017/03/03 13:49:15
Done.
| |
| 22 | |
| 23 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext; | |
| 24 | |
| 25 import 'package:front_end/src/fasta/ticker.dart' show Ticker; | |
| 26 | |
| 27 /// Set of input files that were read by this script to generate patched SDK. | |
| 28 /// We will dump it out into the depfile for ninja to use. | |
| 29 /// | |
| 30 /// For more information see GN and Ninja references: | |
| 31 /// https://chromium.googlesource.com/chromium/src/+/56807c6cb383140af0c03da8 f6731d77785d7160/tools/gn/docs/reference.md#depfile_string_File-name-for-input-d ependencies-for-actions | |
| 32 /// https://ninja-build.org/manual.html#_depfile | |
| 33 /// | |
| 34 final deps = new Set<String>(); | |
| 35 | |
| 36 /// Create [File] object from the given path and register it as a dependency. | |
| 37 File getInputFile(String path, {canBeMissing: true}) { | |
| 38 final file = new File(path); | |
| 39 if (!file.existsSync()) { | |
| 40 if (!canBeMissing) | |
| 41 throw "patch_sdk.dart expects all inputs to exist"; | |
| 42 return null; | |
| 43 } | |
| 44 deps.add(new File(path).absolute.path); | |
|
kustermann
2017/03/03 13:23:08
deps.add(file.absolute.path);
Vyacheslav Egorov (Google)
2017/03/03 13:49:15
Done.
| |
| 45 return file; | |
| 46 } | |
| 47 | |
| 48 | |
| 49 /// Read the given file synchronously as a string and register this path as | |
| 50 /// a dependency. | |
| 51 String readInputFile(String path, {canBeMissing: true}) => | |
| 52 getInputFile(path, canBeMissing: canBeMissing)?.readAsStringSync(); | |
| 53 | |
| 19 Future main(List<String> argv) async { | 54 Future main(List<String> argv) async { |
| 20 var base = path.fromUri(Platform.script); | 55 var base = path.fromUri(Platform.script); |
| 21 var dartDir = path.dirname(path.dirname(path.absolute(base))); | 56 var dartDir = path.dirname(path.dirname(path.absolute(base))); |
| 22 | 57 |
| 23 if (argv.length != 5 || argv.first != 'vm') { | 58 if (argv.length != 5 || argv.first != 'vm') { |
| 24 final self = path.relative(base); | 59 final self = path.relative(base); |
| 25 print('Usage: $self vm SDK_DIR PATCH_DIR OUTPUT_DIR PACKAGES'); | 60 print('Usage: $self vm SDK_DIR PATCH_DIR OUTPUT_DIR PACKAGES'); |
| 26 | 61 |
| 27 final repositoryDir = path.relative(path.dirname(path.dirname(base))); | 62 final repositoryDir = path.relative(path.dirname(path.dirname(base))); |
| 28 final sdkExample = path.relative(path.join(repositoryDir, 'sdk')); | 63 final sdkExample = path.relative(path.join(repositoryDir, 'sdk')); |
| 29 final patchExample = path.relative( | 64 final patchExample = path.relative( |
| 30 path.join(repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patch')); | 65 path.join(repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patch')); |
| 31 final outExample = path.relative(path.join(repositoryDir, 'out', 'DebugX64', | 66 final outExample = path.relative(path.join(repositoryDir, 'out', 'DebugX64', |
| 32 'obj', 'gen', 'patched_sdk')); | 67 'obj', 'gen', 'patched_sdk')); |
| 33 print('For example:'); | 68 print('For example:'); |
| 34 print('\$ $self vm $sdkExample $patchExample $outExample'); | 69 print('\$ $self vm $sdkExample $patchExample $outExample'); |
| 35 | 70 |
| 36 exit(1); | 71 exit(1); |
| 37 } | 72 } |
| 38 | 73 |
| 39 var mode = argv[0]; | 74 var mode = argv[0]; |
| 75 assert(mode == "vm"); | |
| 40 var input = argv[1]; | 76 var input = argv[1]; |
| 41 var sdkLibIn = path.join(input, 'lib'); | 77 var sdkLibIn = path.join(input, 'lib'); |
| 42 var patchIn = argv[2]; | 78 var patchIn = argv[2]; |
| 43 var outDir = argv[3]; | 79 var outDir = argv[3]; |
| 44 var sdkOut = path.join(outDir, 'lib'); | 80 var sdkOut = path.join(outDir, 'lib'); |
| 45 var packagesFile = argv[4]; | 81 var packagesFile = argv[4]; |
| 46 | 82 |
| 47 var privateIn = path.join(input, 'private'); | 83 var privateIn = path.join(input, 'private'); |
| 48 var INTERNAL_PATH = '_internal/compiler/js_lib/'; | 84 var INTERNAL_PATH = '_internal/compiler/js_lib/'; |
| 49 | 85 |
| 50 // Copy and patch libraries.dart and version | 86 // Copy and patch libraries.dart and version |
| 51 var libContents = new File(path.join(sdkLibIn, '_internal', | 87 var libContents = readInputFile(path.join(sdkLibIn, '_internal', |
| 52 'sdk_library_metadata', 'lib', 'libraries.dart')).readAsStringSync(); | 88 'sdk_library_metadata', 'lib', 'libraries.dart')); |
| 53 if (mode == 'vm') { | 89 libContents = libContents.replaceAll( |
|
kustermann
2017/03/03 13:23:08
readInputFile has canBeMissing: true so we could d
Vyacheslav Egorov (Google)
2017/03/03 13:49:15
canBeMissing should be false by default
| |
| 54 libContents = libContents.replaceAll( | |
| 55 ' libraries = const {', | 90 ' libraries = const {', |
| 56 ''' libraries = const { | 91 ''' libraries = const { |
| 57 | 92 |
| 58 "_builtin": const LibraryInfo( | 93 "_builtin": const LibraryInfo( |
| 59 "_builtin/_builtin.dart", | 94 "_builtin/_builtin.dart", |
| 60 categories: "Client,Server", | 95 categories: "Client,Server", |
| 61 implementation: true, | 96 implementation: true, |
| 62 documented: false, | 97 documented: false, |
| 63 platforms: VM_PLATFORM), | 98 platforms: VM_PLATFORM), |
| 64 | 99 |
| 65 "profiler": const LibraryInfo( | 100 "profiler": const LibraryInfo( |
| 66 "profiler/profiler.dart", | 101 "profiler/profiler.dart", |
| 67 maturity: Maturity.DEPRECATED, | 102 maturity: Maturity.DEPRECATED, |
| 68 documented: false), | 103 documented: false), |
| 69 | 104 |
| 70 "_vmservice": const LibraryInfo( | 105 "_vmservice": const LibraryInfo( |
| 71 "vmservice/vmservice.dart", | 106 "vmservice/vmservice.dart", |
| 72 implementation: true, | 107 implementation: true, |
| 73 documented: false, | 108 documented: false, |
| 74 platforms: VM_PLATFORM), | 109 platforms: VM_PLATFORM), |
| 75 | 110 |
| 76 "vmservice_io": const LibraryInfo( | 111 "vmservice_io": const LibraryInfo( |
| 77 "vmservice_io/vmservice_io.dart", | 112 "vmservice_io/vmservice_io.dart", |
| 78 implementation: true, | 113 implementation: true, |
| 79 documented: false, | 114 documented: false, |
| 80 platforms: VM_PLATFORM), | 115 platforms: VM_PLATFORM), |
| 81 | 116 |
| 82 '''); | 117 '''); |
| 83 } | |
| 84 _writeSync( | 118 _writeSync( |
| 85 path.join( | 119 path.join( |
| 86 sdkOut, '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart'), | 120 sdkOut, '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart'), |
| 87 libContents); | 121 libContents); |
| 88 if (mode == 'ddc') { | |
| 89 _writeSync(path.join(sdkOut, '..', 'version'), | |
| 90 new File(path.join(sdkLibIn, '..', 'version')).readAsStringSync()); | |
| 91 } | |
| 92 | 122 |
| 93 // Parse libraries.dart | 123 // Parse libraries.dart |
| 94 var sdkLibraries = _getSdkLibraries(libContents); | 124 var sdkLibraries = _getSdkLibraries(libContents); |
| 95 | 125 |
| 96 // Enumerate core libraries and apply patches | 126 // Enumerate core libraries and apply patches |
| 97 for (SdkLibrary library in sdkLibraries) { | 127 for (SdkLibrary library in sdkLibraries) { |
| 98 // TODO(jmesserly): analyzer does not handle the default case of | 128 if (library.isDart2JsLibrary) { |
| 99 // "both platforms" correctly, and treats it as being supported on neither. | |
| 100 // So instead we skip explicitly marked as either VM or dart2js libs. | |
| 101 if (mode == 'ddc' ? library.isVmLibrary : library.isDart2JsLibrary) { | |
| 102 continue; | 129 continue; |
| 103 } | 130 } |
| 104 | 131 |
| 105 var libraryOut = path.join(sdkLibIn, library.path); | 132 var libraryOut = path.join(sdkLibIn, library.path); |
| 106 var libraryIn; | 133 var libraryIn = libraryOut; |
| 107 if (mode == 'ddc' && library.path.contains(INTERNAL_PATH)) { | |
| 108 libraryIn = | |
| 109 path.join(privateIn, library.path.replaceAll(INTERNAL_PATH, '')); | |
| 110 } else { | |
| 111 libraryIn = libraryOut; | |
| 112 } | |
| 113 | 134 |
| 114 var libraryFile = new File(libraryIn); | 135 var libraryFile = getInputFile(libraryIn, canBeMissing: true); |
| 115 if (libraryFile.existsSync()) { | 136 if (libraryFile != null) { |
| 116 var outPaths = <String>[libraryOut]; | 137 var outPaths = <String>[libraryOut]; |
| 117 var libraryContents = libraryFile.readAsStringSync(); | 138 var libraryContents = libraryFile.readAsStringSync(); |
| 118 | 139 |
| 119 int inputModifyTime = | 140 int inputModifyTime = |
| 120 libraryFile.lastModifiedSync().millisecondsSinceEpoch; | 141 libraryFile.lastModifiedSync().millisecondsSinceEpoch; |
| 121 var partFiles = <File>[]; | 142 var partFiles = <File>[]; |
| 122 for (var part in parseDirectives(libraryContents).directives) { | 143 for (var part in parseDirectives(libraryContents).directives) { |
| 123 if (part is PartDirective) { | 144 if (part is PartDirective) { |
| 124 var partPath = part.uri.stringValue; | 145 var partPath = part.uri.stringValue; |
| 125 outPaths.add(path.join(path.dirname(libraryOut), partPath)); | 146 outPaths.add(path.join(path.dirname(libraryOut), partPath)); |
| 126 | 147 |
| 127 var partFile = new File(path.join(path.dirname(libraryIn), partPath)); | 148 var partFile = getInputFile(path.join(path.dirname(libraryIn), partPat h)); |
|
kustermann
2017/03/03 13:23:08
run dartfmt?
Vyacheslav Egorov (Google)
2017/03/03 13:49:15
Done.
| |
| 128 partFiles.add(partFile); | 149 partFiles.add(partFile); |
| 129 inputModifyTime = math.max(inputModifyTime, | 150 inputModifyTime = math.max(inputModifyTime, |
| 130 partFile.lastModifiedSync().millisecondsSinceEpoch); | 151 partFile.lastModifiedSync().millisecondsSinceEpoch); |
| 131 } | 152 } |
| 132 } | 153 } |
| 133 | 154 |
| 134 // See if we can find a patch file. | 155 // See if we can find a patch file. |
| 135 var patchPath = path.join( | 156 var patchPath = path.join( |
| 136 patchIn, path.basenameWithoutExtension(libraryIn) + '_patch.dart'); | 157 patchIn, path.basenameWithoutExtension(libraryIn) + '_patch.dart'); |
| 137 | 158 |
| 138 var patchFile = new File(patchPath); | 159 var patchFile = getInputFile(patchPath, canBeMissing: true); |
| 139 bool patchExists = patchFile.existsSync(); | 160 if (patchFile != null) { |
| 140 if (patchExists) { | |
| 141 inputModifyTime = math.max(inputModifyTime, | 161 inputModifyTime = math.max(inputModifyTime, |
| 142 patchFile.lastModifiedSync().millisecondsSinceEpoch); | 162 patchFile.lastModifiedSync().millisecondsSinceEpoch); |
| 143 } | 163 } |
| 144 | 164 |
| 145 // Compute output paths | 165 // Compute output paths |
| 146 outPaths = outPaths | 166 outPaths = outPaths |
| 147 .map((p) => path.join(sdkOut, path.relative(p, from: sdkLibIn))) | 167 .map((p) => path.join(sdkOut, path.relative(p, from: sdkLibIn))) |
| 148 .toList(); | 168 .toList(); |
| 149 | 169 |
| 150 // Compare output modify time with input modify time. | 170 // Compare output modify time with input modify time. |
| 151 bool needsUpdate = false; | 171 bool needsUpdate = false; |
| 152 for (var outPath in outPaths) { | 172 for (var outPath in outPaths) { |
| 153 var outFile = new File(outPath); | 173 var outFile = new File(outPath); |
| 154 if (!outFile.existsSync() || | 174 if (!outFile.existsSync() || |
| 155 outFile.lastModifiedSync().millisecondsSinceEpoch < | 175 outFile.lastModifiedSync().millisecondsSinceEpoch < |
| 156 inputModifyTime) { | 176 inputModifyTime) { |
| 157 needsUpdate = true; | 177 needsUpdate = true; |
| 158 break; | 178 break; |
| 159 } | 179 } |
| 160 } | 180 } |
| 161 | 181 |
| 162 if (needsUpdate) { | 182 if (needsUpdate) { |
| 163 var contents = <String>[libraryContents]; | 183 var contents = <String>[libraryContents]; |
| 164 contents.addAll(partFiles.map((f) => f.readAsStringSync())); | 184 contents.addAll(partFiles.map((f) => f.readAsStringSync())); |
| 165 if (patchExists) { | 185 if (patchFile != null) { |
| 166 var patchContents = patchFile.readAsStringSync(); | 186 var patchContents = patchFile.readAsStringSync(); |
| 167 contents = _patchLibrary( | 187 contents = _patchLibrary( |
| 168 patchFile.path, contents, patchContents); | 188 patchFile.path, contents, patchContents); |
| 169 } | 189 } |
| 170 | 190 |
| 171 for (var i = 0; i < outPaths.length; i++) { | 191 for (var i = 0; i < outPaths.length; i++) { |
| 172 _writeSync(outPaths[i], contents[i]); | 192 _writeSync(outPaths[i], contents[i]); |
| 173 } | 193 } |
| 174 } | 194 } |
| 175 } | 195 } |
| 176 } | 196 } |
| 177 | 197 |
| 178 if (mode == 'vm') { | 198 for (var tuple in [['_builtin', 'builtin.dart']]) { |
| 179 for (var tuple in [['_builtin', 'builtin.dart']]) { | 199 var vmLibrary = tuple[0]; |
| 180 var vmLibrary = tuple[0]; | 200 var dartFile = tuple[1]; |
| 181 var dartFile = tuple[1]; | |
| 182 | 201 |
| 183 // The "dart:_builtin" library is only available for the DartVM. | 202 // The "dart:_builtin" library is only available for the DartVM. |
| 184 var builtinLibraryIn = path.join(dartDir, 'runtime', 'bin', dartFile); | 203 var builtinLibraryIn = path.join(dartDir, 'runtime', 'bin', dartFile); |
| 185 var builtinLibraryOut = path.join(sdkOut, vmLibrary, '${vmLibrary}.dart'); | 204 var builtinLibraryOut = path.join(sdkOut, vmLibrary, '${vmLibrary}.dart'); |
| 186 _writeSync(builtinLibraryOut, new File(builtinLibraryIn).readAsStringSync( )); | 205 _writeSync(builtinLibraryOut, readInputFile(builtinLibraryIn)); |
| 187 } | 206 } |
| 188 | 207 |
| 189 for (var file in ['loader.dart', 'server.dart', 'vmservice_io.dart']) { | 208 for (var file in ['loader.dart', 'server.dart', 'vmservice_io.dart']) { |
| 190 var libraryIn = path.join(dartDir, 'runtime', 'bin', 'vmservice', file); | 209 var libraryIn = path.join(dartDir, 'runtime', 'bin', 'vmservice', file); |
| 191 var libraryOut = path.join(sdkOut, 'vmservice_io', file); | 210 var libraryOut = path.join(sdkOut, 'vmservice_io', file); |
| 192 _writeSync(libraryOut, new File(libraryIn).readAsStringSync()); | 211 _writeSync(libraryOut, readInputFile(libraryIn)); |
| 193 } | |
| 194 } | 212 } |
| 195 | 213 |
| 196 // TODO(kustermann): We suppress compiler hints/warnings/errors temporarily | 214 // TODO(kustermann): We suppress compiler hints/warnings/errors temporarily |
| 197 // because everyone building the `runtime` target will get these now. | 215 // because everyone building the `runtime` target will get these now. |
| 198 // We should remove the suppression again once the underlying issues have | 216 // We should remove the suppression again once the underlying issues have |
| 199 // been fixed (either in fasta or the dart files in the patched_sdk). | 217 // been fixed (either in fasta or the dart files in the patched_sdk). |
| 200 final capturedLines = <String>[]; | 218 final capturedLines = <String>[]; |
| 201 try { | 219 try { |
| 220 final platform = path.join(outDir, 'platform.dill'); | |
| 221 | |
| 202 await runZoned(() async { | 222 await runZoned(() async { |
| 203 await compile_platform.mainEntryPoint(<String>[ | 223 await compile_platform.mainEntryPoint(<String>[ |
| 204 '--packages', | 224 '--packages', |
| 205 new Uri.file(packagesFile).toString(), | 225 new Uri.file(packagesFile).toString(), |
| 206 new Uri.directory(outDir).toString(), | 226 new Uri.directory(outDir).toString(), |
| 207 path.join(outDir, 'platform.dill') | 227 platform, |
| 208 ]); | 228 ]); |
| 229 | |
| 230 // platform.dill was generated, now generate platform.dill.d depfile | |
| 231 // that captures all dependencies that participated in the generation. | |
| 232 // There are two types of dependencies: | |
| 233 // (1) all Dart sources that constitute this tool itself | |
| 234 // (2) Dart SDK and patch sources. | |
| 235 // We already collected all inputs from the second category in the deps | |
| 236 // set. To collect inputs from the first category we actually use Fasta: | |
| 237 // we ask Fasta to outline patch_sdk.dart and generate a depfile which | |
| 238 // would list all the sources. | |
| 239 final depfile = "${outDir}.d"; | |
| 240 await CompilerCommandLine.withGlobalOptions("outline", [ | |
| 241 '--packages', | |
| 242 new Uri.file(packagesFile).toString(), | |
| 243 '--platform', | |
| 244 platform, // platform.dill that was just generated | |
| 245 Platform.script.toString() // patch_sdk.dart | |
| 246 ], (CompilerContext c) async { | |
| 247 CompileTask task = | |
| 248 new CompileTask(c, new Ticker(isVerbose: c.options.verbose)); | |
| 249 KernelTarget kernelTarget = await task.buildOutline(null); | |
| 250 await kernelTarget.writeDepsFile(new Uri.file(platform), new Uri.file(de pfile)); | |
| 251 }); | |
| 252 | |
| 253 // Read depfile generated by Fasta and append deps that we have collected | |
| 254 // during generation of patched_sdk to it. | |
| 255 final list = new File(depfile).readAsStringSync().split(':'); | |
| 256 assert(list.length == 2); | |
| 257 deps.addAll(list[1].split(' ').where((str) => str.isNotEmpty)); | |
|
kustermann
2017/03/03 13:23:08
maybe assert list[0] == 'platform.dill'
Could you
| |
| 258 new File(depfile).writeAsStringSync("${list[0]}: ${deps.join(' ')}\n"); | |
| 209 }, zoneSpecification: new ZoneSpecification(print: (_, _2, _3, line) { | 259 }, zoneSpecification: new ZoneSpecification(print: (_, _2, _3, line) { |
| 210 capturedLines.add(line); | 260 capturedLines.add(line); |
| 211 })); | 261 })); |
| 212 } catch (_) { | 262 } catch (_) { |
| 213 for (final line in capturedLines) { | 263 for (final line in capturedLines) { |
| 214 print(line); | 264 print(line); |
| 215 } | 265 } |
| 216 rethrow; | 266 rethrow; |
| 217 } | 267 } |
| 218 } | 268 } |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 if (diff != 0) return diff; | 601 if (diff != 0) return diff; |
| 552 return end - other.end; | 602 return end - other.end; |
| 553 } | 603 } |
| 554 } | 604 } |
| 555 | 605 |
| 556 List<SdkLibrary> _getSdkLibraries(String contents) { | 606 List<SdkLibrary> _getSdkLibraries(String contents) { |
| 557 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); | 607 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); |
| 558 parseCompilationUnit(contents).accept(libraryBuilder); | 608 parseCompilationUnit(contents).accept(libraryBuilder); |
| 559 return libraryBuilder.librariesMap.sdkLibraries; | 609 return libraryBuilder.librariesMap.sdkLibraries; |
| 560 } | 610 } |
| OLD | NEW |