Unverified Commit d63442c1 authored by Ivan Dlugos's avatar Ivan Dlugos Committed by GitHub

refactor: strip all local symbols from macOS and iOS App.framework - reduces app size (#111264)

parent d7f6a4db
...@@ -162,7 +162,7 @@ class AOTSnapshotter { ...@@ -162,7 +162,7 @@ class AOTSnapshotter {
} }
final String assembly = _fileSystem.path.join(outputDir.path, 'snapshot_assembly.S'); final String assembly = _fileSystem.path.join(outputDir.path, 'snapshot_assembly.S');
if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin) { if (targetingApplePlatform) {
genSnapshotArgs.addAll(<String>[ genSnapshotArgs.addAll(<String>[
'--snapshot_kind=app-aot-assembly', '--snapshot_kind=app-aot-assembly',
'--assembly=$assembly', '--assembly=$assembly',
...@@ -181,7 +181,7 @@ class AOTSnapshotter { ...@@ -181,7 +181,7 @@ class AOTSnapshotter {
if (targetingApplePlatform) { if (targetingApplePlatform) {
stripAfterBuild = shouldStrip; stripAfterBuild = shouldStrip;
if (stripAfterBuild) { if (stripAfterBuild) {
_logger.printTrace('Will strip AOT snapshot manual after build and dSYM generation.'); _logger.printTrace('Will strip AOT snapshot manually after build and dSYM generation.');
} }
} else { } else {
stripAfterBuild = false; stripAfterBuild = false;
...@@ -331,7 +331,7 @@ class AOTSnapshotter { ...@@ -331,7 +331,7 @@ class AOTSnapshotter {
if (stripAfterBuild) { if (stripAfterBuild) {
// See https://www.unix.com/man-page/osx/1/strip/ for arguments // See https://www.unix.com/man-page/osx/1/strip/ for arguments
final RunResult stripResult = await _xcode.strip(<String>['-S', appLib, '-o', appLib]); final RunResult stripResult = await _xcode.strip(<String>['-x', appLib, '-o', appLib]);
if (stripResult.exitCode != 0) { if (stripResult.exitCode != 0) {
_logger.printError('Failed to strip debugging symbols from the generated AOT snapshot - strip terminated with exit code ${stripResult.exitCode}'); _logger.printError('Failed to strip debugging symbols from the generated AOT snapshot - strip terminated with exit code ${stripResult.exitCode}');
return stripResult.exitCode; return stripResult.exitCode;
......
...@@ -262,7 +262,7 @@ void main() { ...@@ -262,7 +262,7 @@ void main() {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
'-o', '-o',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
...@@ -335,7 +335,7 @@ void main() { ...@@ -335,7 +335,7 @@ void main() {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
'-o', '-o',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
...@@ -407,7 +407,7 @@ void main() { ...@@ -407,7 +407,7 @@ void main() {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
'-o', '-o',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
...@@ -476,7 +476,7 @@ void main() { ...@@ -476,7 +476,7 @@ void main() {
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
'-o', '-o',
'build/foo/App.framework/App', 'build/foo/App.framework/App',
......
...@@ -529,7 +529,7 @@ void main() { ...@@ -529,7 +529,7 @@ void main() {
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'$build/arm64/App.framework/App', '$build/arm64/App.framework/App',
'-o', '-o',
'$build/arm64/App.framework/App', '$build/arm64/App.framework/App',
...@@ -619,7 +619,7 @@ void main() { ...@@ -619,7 +619,7 @@ void main() {
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
'$build/arm64/App.framework/App', '$build/arm64/App.framework/App',
'-o', '-o',
'$build/arm64/App.framework/App', '$build/arm64/App.framework/App',
......
...@@ -503,7 +503,7 @@ void main() { ...@@ -503,7 +503,7 @@ void main() {
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
environment.buildDir.childFile('arm64/App.framework/App').path, environment.buildDir.childFile('arm64/App.framework/App').path,
'-o', '-o',
environment.buildDir.childFile('arm64/App.framework/App').path, environment.buildDir.childFile('arm64/App.framework/App').path,
...@@ -511,7 +511,7 @@ void main() { ...@@ -511,7 +511,7 @@ void main() {
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'strip', 'strip',
'-S', '-x',
environment.buildDir.childFile('x86_64/App.framework/App').path, environment.buildDir.childFile('x86_64/App.framework/App').path,
'-o', '-o',
environment.buildDir.childFile('x86_64/App.framework/App').path, environment.buildDir.childFile('x86_64/App.framework/App').path,
......
...@@ -193,37 +193,28 @@ void main() { ...@@ -193,37 +193,28 @@ void main() {
}); });
testWithoutContext('check symbols', () { testWithoutContext('check symbols', () {
final ProcessResult symbols = processManager.runSync( final List<String> symbols =
<String>[ AppleTestUtils.getExportedSymbols(outputAppFrameworkBinary.path);
'nm', if (buildMode == BuildMode.debug) {
'-g', expect(symbols, isEmpty);
outputAppFrameworkBinary.path, } else {
'-arch', expect(symbols, equals(AppleTestUtils.requiredSymbols));
'arm64', }
],
);
final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot');
expect(aotSymbolsFound, buildMode != BuildMode.debug);
}); });
// dSYM is not created for a debug build so nothing to check. testWithoutContext('check symbols in dSYM', () {
if (buildMode != BuildMode.debug) { if (buildMode == BuildMode.debug) {
testWithoutContext('check symbols in dSYM', () { // dSYM is not created for a debug build.
final ProcessResult nm = processManager.runSync( expect(buildAppFrameworkDsymBinary.existsSync(), isFalse);
<String>[ } else {
'nm', final List<String> symbols =
'--debug-syms', AppleTestUtils.getExportedSymbols(buildAppFrameworkDsymBinary.path);
'--defined-only', expect(symbols, containsAll(AppleTestUtils.requiredSymbols));
'--just-symbol-name', // The actual number of symbols is going to vary but there should
buildAppFrameworkDsymBinary.path, // be "many" in the dSYM. At the time of writing, it was 7656.
'-arch', expect(symbols.length, greaterThanOrEqualTo(5000));
'arm64', }
], });
);
final List<String> symbols = (nm.stdout as String).split('\n');
expect(symbols, contains('_kDartVmSnapshotInstructions'));
});
}
testWithoutContext('xcode_backend embed_and_thin', () { testWithoutContext('xcode_backend embed_and_thin', () {
outputFlutterFramework.deleteSync(recursive: true); outputFlutterFramework.deleteSync(recursive: true);
......
...@@ -87,19 +87,27 @@ void main() { ...@@ -87,19 +87,27 @@ void main() {
'App.framework', 'App.framework',
)); ));
_checkFatBinary( final File libBinary = outputAppFramework.childFile('App');
outputAppFramework.childFile('App'), final File libDsymBinary =
buildModeLower, buildPath.childFile('App.framework.dSYM/Contents/Resources/DWARF/App');
'dynamically linked shared library',
); _checkFatBinary(libBinary, buildModeLower, 'dynamically linked shared library');
// dSYM is not created for a debug build so nothing to check. final List<String> libSymbols = AppleTestUtils.getExportedSymbols(libBinary.path);
if (buildMode != 'Debug') {
_checkFatBinary( if (buildMode == 'Debug') {
buildPath.childFile('App.framework.dSYM/Contents/Resources/DWARF/App'), // dSYM is not created for a debug build.
buildModeLower, expect(libDsymBinary.existsSync(), isFalse);
'dSYM companion file', expect(libSymbols, isEmpty);
); } else {
_checkFatBinary(libDsymBinary, buildModeLower, 'dSYM companion file');
expect(libSymbols, equals(AppleTestUtils.requiredSymbols));
final List<String> dSymSymbols =
AppleTestUtils.getExportedSymbols(libDsymBinary.path);
expect(dSymSymbols, containsAll(AppleTestUtils.requiredSymbols));
// The actual number of symbols is going to vary but there should
// be "many" in the dSYM. At the time of writing, it was 19195.
expect(dSymSymbols.length, greaterThanOrEqualTo(15000));
} }
expect(outputAppFramework.childLink('Resources'), exists); expect(outputAppFramework.childLink('Resources'), exists);
......
...@@ -99,3 +99,31 @@ Future<void> pollForServiceExtensionValue<T>({ ...@@ -99,3 +99,31 @@ Future<void> pollForServiceExtensionValue<T>({
" attempts responded with '$continuePollingValue'.", " attempts responded with '$continuePollingValue'.",
); );
} }
class AppleTestUtils {
// static only
AppleTestUtils._();
static const List<String> requiredSymbols = <String>[
'_kDartIsolateSnapshotData',
'_kDartIsolateSnapshotInstructions',
'_kDartVmSnapshotData',
'_kDartVmSnapshotInstructions'
];
static List<String> getExportedSymbols(String dwarfPath) {
final ProcessResult nm = processManager.runSync(
<String>[
'nm',
'--debug-syms', // nm docs: 'Show all symbols, even debugger only'
'--defined-only',
'--just-symbol-name',
dwarfPath,
'-arch',
'arm64',
],
);
final String nmOutput = (nm.stdout as String).trim();
return nmOutput.isEmpty ? const <String>[] : nmOutput.split('\n');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment