Skip to content

Commit

Permalink
refactor: strip all local symbols from macOS and iOS App.framework - …
Browse files Browse the repository at this point in the history
…reduces app size (#111264)
  • Loading branch information
vaind committed Sep 9, 2022
1 parent d7f6a4d commit d63442c
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 53 deletions.
6 changes: 3 additions & 3 deletions packages/flutter_tools/lib/src/base/build.dart
Expand Up @@ -162,7 +162,7 @@ class AOTSnapshotter {
}

final String assembly = _fileSystem.path.join(outputDir.path, 'snapshot_assembly.S');
if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin) {
if (targetingApplePlatform) {
genSnapshotArgs.addAll(<String>[
'--snapshot_kind=app-aot-assembly',
'--assembly=$assembly',
Expand All @@ -181,7 +181,7 @@ class AOTSnapshotter {
if (targetingApplePlatform) {
stripAfterBuild = shouldStrip;
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 {
stripAfterBuild = false;
Expand Down Expand Up @@ -331,7 +331,7 @@ class AOTSnapshotter {

if (stripAfterBuild) {
// 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) {
_logger.printError('Failed to strip debugging symbols from the generated AOT snapshot - strip terminated with exit code ${stripResult.exitCode}');
return stripResult.exitCode;
Expand Down
Expand Up @@ -262,7 +262,7 @@ void main() {
const FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'build/foo/App.framework/App',
'-o',
'build/foo/App.framework/App',
Expand Down Expand Up @@ -335,7 +335,7 @@ void main() {
const FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'build/foo/App.framework/App',
'-o',
'build/foo/App.framework/App',
Expand Down Expand Up @@ -407,7 +407,7 @@ void main() {
const FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'build/foo/App.framework/App',
'-o',
'build/foo/App.framework/App',
Expand Down Expand Up @@ -476,7 +476,7 @@ void main() {
const FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'build/foo/App.framework/App',
'-o',
'build/foo/App.framework/App',
Expand Down
Expand Up @@ -529,7 +529,7 @@ void main() {
FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'$build/arm64/App.framework/App',
'-o',
'$build/arm64/App.framework/App',
Expand Down Expand Up @@ -619,7 +619,7 @@ void main() {
FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
'$build/arm64/App.framework/App',
'-o',
'$build/arm64/App.framework/App',
Expand Down
Expand Up @@ -503,15 +503,15 @@ void main() {
FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
environment.buildDir.childFile('arm64/App.framework/App').path,
'-o',
environment.buildDir.childFile('arm64/App.framework/App').path,
]),
FakeCommand(command: <String>[
'xcrun',
'strip',
'-S',
'-x',
environment.buildDir.childFile('x86_64/App.framework/App').path,
'-o',
environment.buildDir.childFile('x86_64/App.framework/App').path,
Expand Down
Expand Up @@ -193,37 +193,28 @@ void main() {
});

testWithoutContext('check symbols', () {
final ProcessResult symbols = processManager.runSync(
<String>[
'nm',
'-g',
outputAppFrameworkBinary.path,
'-arch',
'arm64',
],
);
final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot');
expect(aotSymbolsFound, buildMode != BuildMode.debug);
final List<String> symbols =
AppleTestUtils.getExportedSymbols(outputAppFrameworkBinary.path);
if (buildMode == BuildMode.debug) {
expect(symbols, isEmpty);
} else {
expect(symbols, equals(AppleTestUtils.requiredSymbols));
}
});

// dSYM is not created for a debug build so nothing to check.
if (buildMode != BuildMode.debug) {
testWithoutContext('check symbols in dSYM', () {
final ProcessResult nm = processManager.runSync(
<String>[
'nm',
'--debug-syms',
'--defined-only',
'--just-symbol-name',
buildAppFrameworkDsymBinary.path,
'-arch',
'arm64',
],
);
final List<String> symbols = (nm.stdout as String).split('\n');
expect(symbols, contains('_kDartVmSnapshotInstructions'));
});
}
testWithoutContext('check symbols in dSYM', () {
if (buildMode == BuildMode.debug) {
// dSYM is not created for a debug build.
expect(buildAppFrameworkDsymBinary.existsSync(), isFalse);
} else {
final List<String> symbols =
AppleTestUtils.getExportedSymbols(buildAppFrameworkDsymBinary.path);
expect(symbols, 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 7656.
expect(symbols.length, greaterThanOrEqualTo(5000));
}
});

testWithoutContext('xcode_backend embed_and_thin', () {
outputFlutterFramework.deleteSync(recursive: true);
Expand Down
Expand Up @@ -87,19 +87,27 @@ void main() {
'App.framework',
));

_checkFatBinary(
outputAppFramework.childFile('App'),
buildModeLower,
'dynamically linked shared library',
);

// dSYM is not created for a debug build so nothing to check.
if (buildMode != 'Debug') {
_checkFatBinary(
buildPath.childFile('App.framework.dSYM/Contents/Resources/DWARF/App'),
buildModeLower,
'dSYM companion file',
);
final File libBinary = outputAppFramework.childFile('App');
final File libDsymBinary =
buildPath.childFile('App.framework.dSYM/Contents/Resources/DWARF/App');

_checkFatBinary(libBinary, buildModeLower, 'dynamically linked shared library');

final List<String> libSymbols = AppleTestUtils.getExportedSymbols(libBinary.path);

if (buildMode == 'Debug') {
// dSYM is not created for a debug build.
expect(libDsymBinary.existsSync(), isFalse);
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);
Expand Down
28 changes: 28 additions & 0 deletions packages/flutter_tools/test/integration.shard/test_utils.dart
Expand Up @@ -99,3 +99,31 @@ Future<void> pollForServiceExtensionValue<T>({
" 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');
}
}

0 comments on commit d63442c

Please sign in to comment.