Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c953cd19
Unverified
Commit
c953cd19
authored
Jul 19, 2019
by
Dan Field
Committed by
GitHub
Jul 19, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable bitcode compilation for AOT (#36471)
parent
e6128a0c
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
485 additions
and
25 deletions
+485
-25
xcode_backend.sh
packages/flutter_tools/bin/xcode_backend.sh
+7
-1
build.dart
packages/flutter_tools/lib/src/base/build.dart
+46
-3
build_info.dart
packages/flutter_tools/lib/src/build_info.dart
+0
-2
dart.dart
...ages/flutter_tools/lib/src/build_system/targets/dart.dart
+8
-0
build_aot.dart
packages/flutter_tools/lib/src/commands/build_aot.dart
+63
-2
mac.dart
packages/flutter_tools/lib/src/ios/mac.dart
+12
-0
xcode.dart
packages/flutter_tools/lib/src/macos/xcode.dart
+12
-0
build_test.dart
...ges/flutter_tools/test/general.shard/base/build_test.dart
+79
-2
dart_test.dart
...ls/test/general.shard/build_system/targets/dart_test.dart
+78
-4
build_aot_test.dart
...ter_tools/test/general.shard/commands/build_aot_test.dart
+139
-0
mac_test.dart
packages/flutter_tools/test/general.shard/ios/mac_test.dart
+27
-0
project_test.dart
packages/flutter_tools/test/general.shard/project_test.dart
+0
-11
common.dart
packages/flutter_tools/test/src/common.dart
+11
-0
mocks.dart
packages/flutter_tools/test/src/mocks.dart
+3
-0
No files found.
packages/flutter_tools/bin/xcode_backend.sh
View file @
c953cd19
...
...
@@ -114,6 +114,7 @@ BuildApp() {
flutter_engine_flag
=
"--local-engine-src-path=
${
FLUTTER_ENGINE
}
"
fi
local
bitcode_flag
=
""
if
[[
-n
"
$LOCAL_ENGINE
"
]]
;
then
if
[[
$(
echo
"
$LOCAL_ENGINE
"
|
tr
"[:upper:]"
"[:lower:]"
)
!=
*
"
$build_mode
"
*
]]
;
then
EchoError
"========================================================================"
...
...
@@ -130,6 +131,9 @@ BuildApp() {
local_engine_flag
=
"--local-engine=
${
LOCAL_ENGINE
}
"
flutter_framework
=
"
${
FLUTTER_ENGINE
}
/out/
${
LOCAL_ENGINE
}
/Flutter.framework"
flutter_podspec
=
"
${
FLUTTER_ENGINE
}
/out/
${
LOCAL_ENGINE
}
/Flutter.podspec"
if
[[
$ENABLE_BITCODE
==
"YES"
]]
;
then
bitcode_flag
=
"--bitcode"
fi
fi
if
[[
-e
"
${
project_path
}
/.ios"
]]
;
then
...
...
@@ -174,6 +178,7 @@ BuildApp() {
EchoError
"========================================================================"
exit
-1
fi
RunCommand
"
${
FLUTTER_ROOT
}
/bin/flutter"
--suppress-analytics
\
${
verbose_flag
}
\
build aot
\
...
...
@@ -183,7 +188,8 @@ BuildApp() {
--
${
build_mode
}
\
--ios-arch
=
"
${
archs
}
"
\
${
flutter_engine_flag
}
\
${
local_engine_flag
}
${
local_engine_flag
}
\
${
bitcode_flag
}
if
[[
$?
-ne
0
]]
;
then
EchoError
"Failed to build
${
project_path
}
."
...
...
packages/flutter_tools/lib/src/base/build.dart
View file @
c953cd19
...
...
@@ -94,7 +94,13 @@ class AOTSnapshotter {
@required
String
outputPath
,
IOSArch
iosArch
,
List
<
String
>
extraGenSnapshotOptions
=
const
<
String
>[],
@required
bool
bitcode
,
})
async
{
if
(
bitcode
&&
platform
!=
TargetPlatform
.
ios
)
{
printError
(
'Bitcode is only supported for iOS.'
);
return
1
;
}
if
(!
_isValidAotPlatform
(
platform
,
buildMode
))
{
printError
(
'
${getNameForTargetPlatform(platform)}
does not support AOT compilation.'
);
return
1
;
...
...
@@ -172,6 +178,21 @@ class AOTSnapshotter {
return
genSnapshotExitCode
;
}
// TODO(dnfield): This should be removed when https://github.com/dart-lang/sdk/issues/37560
// is resolved.
// The DWARF section confuses Xcode tooling, so this strips it. Ideally,
// gen_snapshot would provide an argument to do this automatically.
if
(
platform
==
TargetPlatform
.
ios
&&
bitcode
)
{
final
IOSink
sink
=
fs
.
file
(
'
$assembly
.bitcode'
).
openWrite
();
for
(
String
line
in
await
fs
.
file
(
assembly
).
readAsLines
())
{
if
(
line
.
startsWith
(
'.section __DWARF'
))
{
break
;
}
sink
.
writeln
(
line
);
}
await
sink
.
close
();
}
// Write path to gen_snapshot, since snapshots have to be re-generated when we roll
// the Dart SDK.
final
String
genSnapshotPath
=
GenSnapshot
.
getSnapshotterPath
(
snapshotType
);
...
...
@@ -180,7 +201,12 @@ class AOTSnapshotter {
// On iOS, we use Xcode to compile the snapshot into a dynamic library that the
// end-developer can link into their app.
if
(
platform
==
TargetPlatform
.
ios
)
{
final
RunResult
result
=
await
_buildIosFramework
(
iosArch:
iosArch
,
assemblyPath:
assembly
,
outputPath:
outputDir
.
path
);
final
RunResult
result
=
await
_buildIosFramework
(
iosArch:
iosArch
,
assemblyPath:
bitcode
?
'
$assembly
.bitcode'
:
assembly
,
outputPath:
outputDir
.
path
,
bitcode:
bitcode
,
);
if
(
result
.
exitCode
!=
0
)
return
result
.
exitCode
;
}
...
...
@@ -193,13 +219,21 @@ class AOTSnapshotter {
@required
IOSArch
iosArch
,
@required
String
assemblyPath
,
@required
String
outputPath
,
@required
bool
bitcode
,
})
async
{
final
String
targetArch
=
iosArch
==
IOSArch
.
armv7
?
'armv7'
:
'arm64'
;
printStatus
(
'Building App.framework for
$targetArch
...'
);
final
List
<
String
>
commonBuildOptions
=
<
String
>[
'-arch'
,
targetArch
,
'-miphoneos-version-min=8.0'
];
final
String
assemblyO
=
fs
.
path
.
join
(
outputPath
,
'snapshot_assembly.o'
);
final
RunResult
compileResult
=
await
xcode
.
cc
(<
String
>[...
commonBuildOptions
,
'-c'
,
assemblyPath
,
'-o'
,
assemblyO
]);
final
RunResult
compileResult
=
await
xcode
.
cc
(<
String
>[
...
commonBuildOptions
,
'-c'
,
assemblyPath
,
'-o'
,
assemblyO
,
if
(
bitcode
)
'-fembed-bitcode'
,
]);
if
(
compileResult
.
exitCode
!=
0
)
{
printError
(
'Failed to compile AOT snapshot. Compiler terminated with exit code
${compileResult.exitCode}
'
);
return
compileResult
;
...
...
@@ -214,14 +248,23 @@ class AOTSnapshotter {
'-Xlinker'
,
'-rpath'
,
'-Xlinker'
,
'@executable_path/Frameworks'
,
'-Xlinker'
,
'-rpath'
,
'-Xlinker'
,
'@loader_path/Frameworks'
,
'-install_name'
,
'@rpath/App.framework/App'
,
if
(
bitcode
)
'-fembed-bitcode'
,
'-o'
,
appLib
,
assemblyO
,
];
final
RunResult
linkResult
=
await
xcode
.
clang
(
linkArgs
);
if
(
linkResult
.
exitCode
!=
0
)
{
printError
(
'Failed to link AOT snapshot. Linker terminated with exit code
${compileResult.exitCode}
'
);
return
linkResult
;
}
final
RunResult
dsymResult
=
await
xcode
.
dsymutil
(<
String
>[
appLib
,
'-o'
,
fs
.
path
.
join
(
outputPath
,
'App.framework.dSYM'
),
]);
if
(
dsymResult
.
exitCode
!=
0
)
{
printError
(
'Failed to extract dSYM out of dynamic lib'
);
}
return
link
Result
;
return
dsym
Result
;
}
/// Compiles a Dart file to kernel.
...
...
packages/flutter_tools/lib/src/build_info.dart
View file @
c953cd19
...
...
@@ -119,8 +119,6 @@ const List<String> _kBuildModes = <String>[
'debug'
,
'profile'
,
'release'
,
'dynamic-profile'
,
'dynamic-release'
,
];
/// Return the name for the build mode, or "any" if null.
...
...
packages/flutter_tools/lib/src/build_system/targets/dart.dart
View file @
c953cd19
...
...
@@ -25,6 +25,9 @@ const String kTargetPlatform = 'TargetPlatform';
/// The define to control what target file is used.
const
String
kTargetFile
=
'TargetFile'
;
/// The define to control whether the AOT snapshot is built with bitcode.
const
String
kBitcodeFlag
=
'EnableBitcode'
;
/// The define to control what iOS architectures are built for.
///
/// This is expected to be a comma-separated list of architectures. If not
...
...
@@ -74,6 +77,7 @@ Future<void> compileAotElf(Map<String, ChangeType> updates, Environment environm
if
(
environment
.
defines
[
kTargetPlatform
]
==
null
)
{
throw
MissingDefineException
(
kTargetPlatform
,
'aot_elf'
);
}
final
BuildMode
buildMode
=
getBuildModeForName
(
environment
.
defines
[
kBuildMode
]);
final
TargetPlatform
targetPlatform
=
getTargetPlatformForName
(
environment
.
defines
[
kTargetPlatform
]);
final
int
snapshotExitCode
=
await
snapshotter
.
build
(
...
...
@@ -82,6 +86,7 @@ Future<void> compileAotElf(Map<String, ChangeType> updates, Environment environm
mainPath:
environment
.
buildDir
.
childFile
(
'main.app.dill'
).
path
,
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
outputPath:
outputPath
,
bitcode:
false
,
);
if
(
snapshotExitCode
!=
0
)
{
throw
Exception
(
'AOT snapshotter exited with code
$snapshotExitCode
'
);
...
...
@@ -126,6 +131,7 @@ Future<void> compileAotAssembly(Map<String, ChangeType> updates, Environment env
if
(
targetPlatform
!=
TargetPlatform
.
ios
)
{
throw
Exception
(
'aot_assembly is only supported for iOS applications'
);
}
final
bool
bitcode
=
environment
.
defines
[
kBitcodeFlag
]
==
'true'
;
// If we're building for a single architecture (common), then skip the lipo.
if
(
iosArchs
.
length
==
1
)
{
...
...
@@ -136,6 +142,7 @@ Future<void> compileAotAssembly(Map<String, ChangeType> updates, Environment env
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
outputPath:
outputPath
,
iosArch:
iosArchs
.
single
,
bitcode:
bitcode
,
);
if
(
snapshotExitCode
!=
0
)
{
throw
Exception
(
'AOT snapshotter exited with code
$snapshotExitCode
'
);
...
...
@@ -152,6 +159,7 @@ Future<void> compileAotAssembly(Map<String, ChangeType> updates, Environment env
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
outputPath:
fs
.
path
.
join
(
outputPath
,
getNameForIOSArch
(
iosArch
)),
iosArch:
iosArch
,
bitcode:
bitcode
,
));
}
final
List
<
int
>
results
=
await
Future
.
wait
(
pending
);
...
...
packages/flutter_tools/lib/src/commands/build_aot.dart
View file @
c953cd19
...
...
@@ -4,14 +4,18 @@
import
'dart:async'
;
import
'../artifacts.dart'
;
import
'../base/build.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/logger.dart'
;
import
'../base/process.dart'
;
import
'../build_info.dart'
;
import
'../dart/package_map.dart'
;
import
'../globals.dart'
;
import
'../ios/ios_workflow.dart'
;
import
'../macos/xcode.dart'
;
import
'../resident_runner.dart'
;
import
'../runner/flutter_command.dart'
;
import
'build.dart'
;
...
...
@@ -52,6 +56,11 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
..
addMultiOption
(
FlutterOptions
.
kExtraGenSnapshotOptions
,
splitCommas:
true
,
hide:
true
,
)
..
addFlag
(
'bitcode'
,
defaultsTo:
false
,
help:
'Build the AOT bundle with bitcode. Requires a compatible bitcode engine.'
,
hide:
true
,
);
}
...
...
@@ -68,8 +77,16 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
if
(
platform
==
null
)
throwToolExit
(
'Unknown platform:
$targetPlatform
'
);
final
bool
bitcode
=
argResults
[
'bitcode'
];
final
BuildMode
buildMode
=
getBuildMode
();
if
(
bitcode
)
{
if
(
platform
!=
TargetPlatform
.
ios
)
{
throwToolExit
(
'Bitcode is only supported on iOS (TargetPlatform is
$targetPlatform
).'
);
}
await
validateBitcode
();
}
Status
status
;
if
(!
argResults
[
'quiet'
])
{
final
String
typeName
=
artifacts
.
getEngineType
(
platform
,
buildMode
);
...
...
@@ -118,6 +135,7 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
bitcode:
bitcode
,
).
then
<
int
>((
int
buildExitCode
)
{
return
buildExitCode
;
});
...
...
@@ -131,8 +149,15 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
'lipo'
,
...
dylibs
,
'-create'
,
'-output'
,
fs
.
path
.
join
(
outputPath
,
'App.framework'
,
'App'
),
'-output'
,
fs
.
path
.
join
(
outputPath
,
'App.framework'
,
'App'
),
]);
final
Iterable
<
String
>
dSYMs
=
iosBuilds
.
values
.
map
<
String
>((
String
outputDir
)
=>
fs
.
path
.
join
(
outputDir
,
'App.framework.dSYM'
));
fs
.
directory
(
fs
.
path
.
join
(
outputPath
,
'App.framework.dSYM'
,
'Contents'
,
'Resources'
,
'DWARF'
))..
createSync
(
recursive:
true
);
await
runCheckedAsync
(<
String
>[
'lipo'
,
'-create'
,
'-output'
,
fs
.
path
.
join
(
outputPath
,
'App.framework.dSYM'
,
'Contents'
,
'Resources'
,
'DWARF'
,
'App'
),
...
dSYMs
.
map
((
String
path
)
=>
fs
.
path
.
join
(
path
,
'Contents'
,
'Resources'
,
'DWARF'
,
'App'
))
]);
}
else
{
status
?.
cancel
();
...
...
@@ -150,6 +175,7 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
bitcode:
false
,
);
if
(
snapshotExitCode
!=
0
)
{
status
?.
cancel
();
...
...
@@ -176,3 +202,38 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
return
null
;
}
}
Future
<
void
>
validateBitcode
()
async
{
final
Artifacts
artifacts
=
Artifacts
.
instance
;
if
(
artifacts
is
!
LocalEngineArtifacts
)
{
throwToolExit
(
'Bitcode is only supported with a local engine built with --bitcode.'
);
}
final
String
flutterFrameworkPath
=
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
);
if
(!
fs
.
isDirectorySync
(
flutterFrameworkPath
))
{
throwToolExit
(
'Flutter.framework not found at
$flutterFrameworkPath
'
);
}
final
Xcode
xcode
=
context
.
get
<
Xcode
>();
// Check for bitcode in Flutter binary.
final
RunResult
otoolResult
=
await
xcode
.
otool
(<
String
>[
'-l'
,
fs
.
path
.
join
(
flutterFrameworkPath
,
'Flutter'
),
]);
if
(!
otoolResult
.
stdout
.
contains
(
'__LLVM'
))
{
throwToolExit
(
'The Flutter.framework at
$flutterFrameworkPath
does not contain bitcode.'
);
}
final
RunResult
clangResult
=
await
xcode
.
clang
(<
String
>[
'--version'
]);
final
String
clangVersion
=
clangResult
.
stdout
.
split
(
'
\n
'
).
first
;
final
String
engineClangVersion
=
iosWorkflow
.
getPlistValueFromFile
(
fs
.
path
.
join
(
flutterFrameworkPath
,
'Info.plist'
),
'ClangVersion'
,
);
if
(
clangVersion
!=
engineClangVersion
)
{
printStatus
(
'The Flutter.framework at
$flutterFrameworkPath
was built '
'with "
${engineClangVersion ?? 'unknown'}
", but the current version '
'of clang is "
$clangVersion
". This may result in failures when '
'archiving your application in Xcode.'
,
emphasis:
true
,
);
}
}
packages/flutter_tools/lib/src/ios/mac.dart
View file @
c953cd19
...
...
@@ -469,6 +469,18 @@ String readGeneratedXcconfig(String appPath) {
}
Future
<
void
>
diagnoseXcodeBuildFailure
(
XcodeBuildResult
result
)
async
{
if
(
result
.
xcodeBuildExecution
!=
null
&&
result
.
xcodeBuildExecution
.
buildForPhysicalDevice
&&
result
.
stdout
?.
toUpperCase
()?.
contains
(
'BITCODE'
)
==
true
)
{
flutterUsage
.
sendEvent
(
'Xcode'
,
'bitcode-failure'
,
parameters:
<
String
,
String
>{
'build-commands'
:
result
.
xcodeBuildExecution
.
buildCommands
.
toString
(),
'build-settings'
:
result
.
xcodeBuildExecution
.
buildSettings
.
toString
(),
});
}
if
(
result
.
xcodeBuildExecution
!=
null
&&
result
.
xcodeBuildExecution
.
buildForPhysicalDevice
&&
result
.
stdout
?.
contains
(
'BCEROR'
)
==
true
&&
...
...
packages/flutter_tools/lib/src/macos/xcode.dart
View file @
c953cd19
...
...
@@ -97,6 +97,18 @@ class Xcode {
return
runCheckedAsync
(<
String
>[
'xcrun'
,
'clang'
,
...
args
]);
}
Future
<
RunResult
>
dsymutil
(
List
<
String
>
args
)
{
return
runCheckedAsync
(<
String
>[
'xcrun'
,
'dsymutil'
,
...
args
]);
}
Future
<
RunResult
>
strip
(
List
<
String
>
args
)
{
return
runCheckedAsync
(<
String
>[
'xcrun'
,
'strip'
,
...
args
]);
}
Future
<
RunResult
>
otool
(
List
<
String
>
args
)
{
return
runCheckedAsync
(<
String
>[
'xcrun'
,
'otool'
,
...
args
]);
}
String
getSimulatorPath
()
{
if
(
xcodeSelectPath
==
null
)
return
null
;
...
...
packages/flutter_tools/test/general.shard/base/build_test.dart
View file @
c953cd19
...
...
@@ -116,6 +116,13 @@ void main() {
when
(
mockArtifacts
.
getArtifactPath
(
Artifact
.
snapshotDart
,
platform:
anyNamed
(
'platform'
),
mode:
mode
)).
thenReturn
(
kSnapshotDart
);
}
when
(
mockXcode
.
dsymutil
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
RunResult
(
ProcessResult
(
1
,
0
,
''
,
''
),
<
String
>[
'command name'
,
'arguments...'
]),
),
);
});
final
Map
<
Type
,
Generator
>
contextOverrides
=
<
Type
,
Generator
>{
...
...
@@ -135,6 +142,7 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
),
isNot
(
equals
(
0
)));
},
overrides:
contextOverrides
);
...
...
@@ -146,6 +154,7 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
),
isNot
(
0
));
},
overrides:
contextOverrides
);
...
...
@@ -157,17 +166,69 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
),
isNot
(
0
));
},
overrides:
contextOverrides
);
testUsingContext
(
'iOS debug AOT with bitcode uses right flags'
,
()
async
{
fs
.
file
(
'main.dill'
).
writeAsStringSync
(
'binary magic'
);
final
String
outputPath
=
fs
.
path
.
join
(
'build'
,
'foo'
);
fs
.
directory
(
outputPath
).
createSync
(
recursive:
true
);
final
String
assembly
=
fs
.
path
.
join
(
outputPath
,
'snapshot_assembly.S'
);
genSnapshot
.
outputs
=
<
String
,
String
>{
assembly:
'blah blah
\n
.section __DWARF
\n
blah blah
\n
'
,
};
final
RunResult
successResult
=
RunResult
(
ProcessResult
(
1
,
0
,
''
,
''
),
<
String
>[
'command name'
,
'arguments...'
]);
when
(
xcode
.
cc
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
successResult
));
when
(
xcode
.
clang
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
successResult
));
final
int
genSnapshotExitCode
=
await
snapshotter
.
build
(
platform:
TargetPlatform
.
ios
,
buildMode:
BuildMode
.
profile
,
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
iosArch:
IOSArch
.
armv7
,
bitcode:
true
,
);
expect
(
genSnapshotExitCode
,
0
);
expect
(
genSnapshot
.
callCount
,
1
);
expect
(
genSnapshot
.
snapshotType
.
platform
,
TargetPlatform
.
ios
);
expect
(
genSnapshot
.
snapshotType
.
mode
,
BuildMode
.
profile
);
expect
(
genSnapshot
.
additionalArgs
,
<
String
>[
'--deterministic'
,
'--snapshot_kind=app-aot-assembly'
,
'--assembly=
$assembly
'
,
'--no-sim-use-hardfp'
,
'--no-use-integer-division'
,
'main.dill'
,
]);
verify
(
xcode
.
cc
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
1
);
verify
(
xcode
.
clang
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
1
);
verify
(
xcode
.
dsymutil
(
any
)).
called
(
1
);
final
File
assemblyFile
=
fs
.
file
(
assembly
);
final
File
assemblyBitcodeFile
=
fs
.
file
(
'
$assembly
.bitcode'
);
expect
(
assemblyFile
.
existsSync
(),
true
);
expect
(
assemblyBitcodeFile
.
existsSync
(),
true
);
expect
(
assemblyFile
.
readAsStringSync
().
contains
(
'.section __DWARF'
),
true
);
expect
(
assemblyBitcodeFile
.
readAsStringSync
().
contains
(
'.section __DWARF'
),
false
);
},
overrides:
contextOverrides
);
testUsingContext
(
'builds iOS armv7 profile AOT snapshot'
,
()
async
{
fs
.
file
(
'main.dill'
).
writeAsStringSync
(
'binary magic'
);
final
String
outputPath
=
fs
.
path
.
join
(
'build'
,
'foo'
);
fs
.
directory
(
outputPath
).
createSync
(
recursive:
true
);
final
String
assembly
=
fs
.
path
.
join
(
outputPath
,
'snapshot_assembly.S'
);
genSnapshot
.
outputs
=
<
String
,
String
>{
fs
.
path
.
join
(
outputPath
,
'snapshot_assembly.S'
):
'
'
,
assembly:
'blah blah
\n
.section __DWARF
\n
blah blah
\n
'
,
};
final
RunResult
successResult
=
RunResult
(
ProcessResult
(
1
,
0
,
''
,
''
),
<
String
>[
'command name'
,
'arguments...'
]);
...
...
@@ -181,6 +242,7 @@ void main() {
packagesPath:
'.packages'
,
outputPath:
outputPath
,
iosArch:
IOSArch
.
armv7
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -190,11 +252,20 @@ void main() {
expect
(
genSnapshot
.
additionalArgs
,
<
String
>[
'--deterministic'
,
'--snapshot_kind=app-aot-assembly'
,
'--assembly=
$
{fs.path.join(outputPath, 'snapshot_assembly.S')}
'
,
'--assembly=
$
assembly
'
,
'--no-sim-use-hardfp'
,
'--no-use-integer-division'
,
'main.dill'
,
]);
verifyNever
(
xcode
.
cc
(
argThat
(
contains
(
'-fembed-bitcode'
))));
verifyNever
(
xcode
.
clang
(
argThat
(
contains
(
'-fembed-bitcode'
))));
verify
(
xcode
.
dsymutil
(
any
)).
called
(
1
);
final
File
assemblyFile
=
fs
.
file
(
assembly
);
final
File
assemblyBitcodeFile
=
fs
.
file
(
'
$assembly
.bitcode'
);
expect
(
assemblyFile
.
existsSync
(),
true
);
expect
(
assemblyBitcodeFile
.
existsSync
(),
false
);
expect
(
assemblyFile
.
readAsStringSync
().
contains
(
'.section __DWARF'
),
true
);
},
overrides:
contextOverrides
);
testUsingContext
(
'builds iOS arm64 profile AOT snapshot'
,
()
async
{
...
...
@@ -218,6 +289,7 @@ void main() {
packagesPath:
'.packages'
,
outputPath:
outputPath
,
iosArch:
IOSArch
.
arm64
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -253,6 +325,7 @@ void main() {
packagesPath:
'.packages'
,
outputPath:
outputPath
,
iosArch:
IOSArch
.
armv7
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -290,6 +363,7 @@ void main() {
packagesPath:
'.packages'
,
outputPath:
outputPath
,
iosArch:
IOSArch
.
arm64
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -316,6 +390,7 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -345,6 +420,7 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
@@ -380,6 +456,7 @@ void main() {
mainPath:
'main.dill'
,
packagesPath:
'.packages'
,
outputPath:
outputPath
,
bitcode:
false
,
);
expect
(
genSnapshotExitCode
,
0
);
...
...
packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
View file @
c953cd19
...
...
@@ -5,12 +5,14 @@
import
'package:flutter_tools/src/base/build.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/base/process.dart'
;
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/build_system/build_system.dart'
;
import
'package:flutter_tools/src/build_system/exceptions.dart'
;
import
'package:flutter_tools/src/build_system/targets/dart.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/compile.dart'
;
import
'package:flutter_tools/src/macos/xcode.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
...
...
@@ -26,6 +28,7 @@ void main() {
Environment
androidEnvironment
;
Environment
iosEnvironment
;
MockProcessManager
mockProcessManager
;
MockXcode
mockXcode
;
setUpAll
(()
{
Cache
.
disableLocking
();
...
...
@@ -33,6 +36,7 @@ void main() {
setUp
(()
{
mockProcessManager
=
MockProcessManager
();
mockXcode
=
MockXcode
();
testbed
=
Testbed
(
setup:
()
{
androidEnvironment
=
Environment
(
projectDir:
fs
.
currentDirectory
,
...
...
@@ -153,8 +157,70 @@ flutter_tools:lib/''');
expect
(
result
.
exceptions
.
values
.
single
.
exception
,
isInstanceOf
<
Exception
>());
}));
test
(
'aot_assembly_profile with bitcode sends correct argument to snapshotter (one arch)'
,
()
=>
testbed
.
run
(()
async
{
iosEnvironment
.
defines
[
kIosArchs
]
=
'arm64'
;
iosEnvironment
.
defines
[
kBitcodeFlag
]
=
'true'
;
final
FakeProcessResult
fakeProcessResult
=
FakeProcessResult
(
stdout:
''
,
stderr:
''
,
);
final
RunResult
fakeRunResult
=
RunResult
(
fakeProcessResult
,
const
<
String
>[
'foo'
]);
when
(
mockProcessManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
fs
.
file
(
fs
.
path
.
join
(
iosEnvironment
.
buildDir
.
path
,
'App.framework'
,
'App'
))
.
createSync
(
recursive:
true
);
return
fakeProcessResult
;
});
when
(
mockXcode
.
cc
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
when
(
mockXcode
.
clang
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
when
(
mockXcode
.
dsymutil
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
final
BuildResult
result
=
await
buildSystem
.
build
(
'aot_assembly_profile'
,
iosEnvironment
,
const
BuildSystemConfig
());
expect
(
result
.
success
,
true
);
verify
(
mockXcode
.
cc
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
1
);
verify
(
mockXcode
.
clang
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
1
);
verify
(
mockXcode
.
dsymutil
(
any
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
Xcode:
()
=>
mockXcode
,
}));
test
(
'aot_assembly_profile with bitcode sends correct argument to snapshotter (mutli arch)'
,
()
=>
testbed
.
run
(()
async
{
iosEnvironment
.
defines
[
kIosArchs
]
=
'armv7,arm64'
;
iosEnvironment
.
defines
[
kBitcodeFlag
]
=
'true'
;
final
FakeProcessResult
fakeProcessResult
=
FakeProcessResult
(
stdout:
''
,
stderr:
''
,
);
final
RunResult
fakeRunResult
=
RunResult
(
fakeProcessResult
,
const
<
String
>[
'foo'
]);
when
(
mockProcessManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
fs
.
file
(
fs
.
path
.
join
(
iosEnvironment
.
buildDir
.
path
,
'App.framework'
,
'App'
))
.
createSync
(
recursive:
true
);
return
fakeProcessResult
;
});
when
(
mockXcode
.
cc
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
when
(
mockXcode
.
clang
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
when
(
mockXcode
.
dsymutil
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
fakeRunResult
));
final
BuildResult
result
=
await
buildSystem
.
build
(
'aot_assembly_profile'
,
iosEnvironment
,
const
BuildSystemConfig
());
expect
(
result
.
success
,
true
);
verify
(
mockXcode
.
cc
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
2
);
verify
(
mockXcode
.
clang
(
argThat
(
contains
(
'-fembed-bitcode'
)))).
called
(
2
);
verify
(
mockXcode
.
dsymutil
(
any
)).
called
(
2
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
Xcode:
()
=>
mockXcode
,
}));
test
(
'aot_assembly_profile will lipo binaries together when multiple archs are requested'
,
()
=>
testbed
.
run
(()
async
{
iosEnvironment
.
defines
[
kIosArchs
]
=
'armv7,arm64'
;
iosEnvironment
.
defines
[
kIosArchs
]
=
'armv7,arm64'
;
when
(
mockProcessManager
.
run
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
fs
.
file
(
fs
.
path
.
join
(
iosEnvironment
.
buildDir
.
path
,
'App.framework'
,
'App'
))
.
createSync
(
recursive:
true
);
...
...
@@ -175,18 +241,26 @@ flutter_tools:lib/''');
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockXcode
extends
Mock
implements
Xcode
{}
class
FakeGenSnapshot
implements
GenSnapshot
{
List
<
String
>
lastCallAdditionalArgs
;
@override
Future
<
int
>
run
({
SnapshotType
snapshotType
,
IOSArch
iosArch
,
Iterable
<
String
>
additionalArgs
=
const
<
String
>[]})
async
{
final
Directory
out
=
fs
.
file
(
additionalArgs
.
last
).
parent
;
lastCallAdditionalArgs
=
additionalArgs
.
toList
();
final
Directory
out
=
fs
.
file
(
lastCallAdditionalArgs
.
last
).
parent
;
if
(
iosArch
==
null
)
{
out
.
childFile
(
'app.so'
).
createSync
();
out
.
childFile
(
'gen_snapshot.d'
).
createSync
();
return
0
;
}
out
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
).
createSync
(
recursive:
true
);
out
.
childFile
(
'snapshot_assembly.S'
).
createSync
();
out
.
childFile
(
'snapshot_assembly.o'
).
createSync
();
final
String
assembly
=
lastCallAdditionalArgs
.
firstWhere
((
String
arg
)
=>
arg
.
startsWith
(
'--assembly'
))
.
substring
(
'--assembly='
.
length
);
fs
.
file
(
assembly
).
createSync
();
fs
.
file
(
assembly
.
replaceAll
(
'.S'
,
'.o'
)).
createSync
();
return
0
;
}
}
...
...
packages/flutter_tools/test/general.shard/commands/build_aot_test.dart
0 → 100644
View file @
c953cd19
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/artifacts.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/process.dart'
;
import
'package:flutter_tools/src/commands/build_aot.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/ios/ios_workflow.dart'
;
import
'package:flutter_tools/src/macos/xcode.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/mocks.dart'
;
void
main
(
)
{
MockXcode
mockXcode
;
MemoryFileSystem
memoryFileSystem
;
MockProcessManager
mockProcessManager
;
BufferLogger
bufferLogger
;
MockIOSWorkflow
mockIOSWorkflow
;
setUp
(()
{
mockXcode
=
MockXcode
();
memoryFileSystem
=
MemoryFileSystem
(
style:
FileSystemStyle
.
posix
);
mockProcessManager
=
MockProcessManager
();
bufferLogger
=
BufferLogger
();
mockIOSWorkflow
=
MockIOSWorkflow
();
});
testUsingContext
(
'build aot validates building with bitcode requires a local engine'
,
()
async
{
await
expectToolExitLater
(
validateBitcode
(),
equals
(
'Bitcode is only supported with a local engine built with --bitcode.'
),
);
});
testUsingContext
(
'build aot validates existence of Flutter.framework in engine'
,
()
async
{
await
expectToolExitLater
(
validateBitcode
(),
equals
(
'Flutter.framework not found at ios_profile/Flutter.framework'
),
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
LocalEngineArtifacts
(
'/engine'
,
'ios_profile'
,
'host_profile'
),
FileSystem:
()
=>
memoryFileSystem
,
});
testUsingContext
(
'build aot validates Flutter.framework/Flutter contains bitcode'
,
()
async
{
final
Directory
flutterFramework
=
memoryFileSystem
.
directory
(
'ios_profile/Flutter.framework'
)
..
createSync
(
recursive:
true
);
flutterFramework
.
childFile
(
'Flutter'
).
createSync
();
flutterFramework
.
childFile
(
'Info.plist'
).
createSync
();
final
RunResult
otoolResult
=
RunResult
(
FakeProcessResult
(
stdout:
''
,
stderr:
''
),
const
<
String
>[
'foo'
],
);
when
(
mockXcode
.
otool
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
otoolResult
));
await
expectToolExitLater
(
validateBitcode
(),
equals
(
'The Flutter.framework at ios_profile/Flutter.framework does not contain bitcode.'
),
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
LocalEngineArtifacts
(
'/engine'
,
'ios_profile'
,
'host_profile'
),
FileSystem:
()
=>
memoryFileSystem
,
ProcessManager:
()
=>
mockProcessManager
,
Xcode:
()
=>
mockXcode
,
});
testUsingContext
(
'build aot validates Flutter.framework/Flutter was built with same toolchain'
,
()
async
{
final
Directory
flutterFramework
=
memoryFileSystem
.
directory
(
'ios_profile/Flutter.framework'
)
..
createSync
(
recursive:
true
);
flutterFramework
.
childFile
(
'Flutter'
).
createSync
();
final
File
infoPlist
=
flutterFramework
.
childFile
(
'Info.plist'
)..
createSync
();
final
RunResult
otoolResult
=
RunResult
(
FakeProcessResult
(
stdout:
'__LLVM'
,
stderr:
''
),
const
<
String
>[
'foo'
],
);
final
RunResult
clangResult
=
RunResult
(
FakeProcessResult
(
stdout:
'BadVersion
\n
BlahBlah
\n
'
,
stderr:
''
),
const
<
String
>[
'foo'
],
);
when
(
mockXcode
.
otool
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
otoolResult
));
when
(
mockXcode
.
clang
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
clangResult
));
when
(
mockIOSWorkflow
.
getPlistValueFromFile
(
infoPlist
.
path
,
'ClangVersion'
)).
thenReturn
(
'Apple LLVM Version 10.0.1'
);
await
validateBitcode
();
expect
(
bufferLogger
.
statusText
,
startsWith
(
'The Flutter.framework at
${flutterFramework.path}
was built with "Apple LLVM Version 10.0.1'
),
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
LocalEngineArtifacts
(
'/engine'
,
'ios_profile'
,
'host_profile'
),
FileSystem:
()
=>
memoryFileSystem
,
ProcessManager:
()
=>
mockProcessManager
,
Xcode:
()
=>
mockXcode
,
Logger:
()
=>
bufferLogger
,
IOSWorkflow:
()
=>
mockIOSWorkflow
,
});
testUsingContext
(
'build aot validates and succeeds'
,
()
async
{
final
Directory
flutterFramework
=
memoryFileSystem
.
directory
(
'ios_profile/Flutter.framework'
)
..
createSync
(
recursive:
true
);
flutterFramework
.
childFile
(
'Flutter'
).
createSync
();
final
File
infoPlist
=
flutterFramework
.
childFile
(
'Info.plist'
)..
createSync
();
final
RunResult
otoolResult
=
RunResult
(
FakeProcessResult
(
stdout:
'__LLVM'
,
stderr:
''
),
const
<
String
>[
'foo'
],
);
final
RunResult
clangResult
=
RunResult
(
FakeProcessResult
(
stdout:
'Apple LLVM Version 10.0.1
\n
BlahBlah
\n
'
,
stderr:
''
),
const
<
String
>[
'foo'
],
);
when
(
mockXcode
.
otool
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
otoolResult
));
when
(
mockXcode
.
clang
(
any
)).
thenAnswer
((
_
)
=>
Future
<
RunResult
>.
value
(
clangResult
));
when
(
mockIOSWorkflow
.
getPlistValueFromFile
(
infoPlist
.
path
,
'ClangVersion'
)).
thenReturn
(
'Apple LLVM Version 10.0.1'
);
await
validateBitcode
();
expect
(
bufferLogger
.
statusText
,
''
);
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
LocalEngineArtifacts
(
'/engine'
,
'ios_profile'
,
'host_profile'
),
FileSystem:
()
=>
memoryFileSystem
,
ProcessManager:
()
=>
mockProcessManager
,
Xcode:
()
=>
mockXcode
,
Logger:
()
=>
bufferLogger
,
IOSWorkflow:
()
=>
mockIOSWorkflow
,
});
}
class
MockXcode
extends
Mock
implements
Xcode
{}
class
MockIOSWorkflow
extends
Mock
implements
IOSWorkflow
{}
packages/flutter_tools/test/general.shard/ios/mac_test.dart
View file @
c953cd19
...
...
@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/ios/xcodeproj.dart';
import
'package:flutter_tools/src/artifacts.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/usage.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
...
...
@@ -159,11 +160,35 @@ void main() {
group
(
'Diagnose Xcode build failure'
,
()
{
Map
<
String
,
String
>
buildSettings
;
MockUsage
mockUsage
;
setUp
(()
{
buildSettings
=
<
String
,
String
>{
'PRODUCT_BUNDLE_IDENTIFIER'
:
'test.app'
,
};
mockUsage
=
MockUsage
();
});
testUsingContext
(
'Sends analytics when bitcode fails'
,
()
async
{
const
List
<
String
>
buildCommands
=
<
String
>[
'xcrun'
,
'cc'
,
'blah'
];
final
XcodeBuildResult
buildResult
=
XcodeBuildResult
(
success:
false
,
stdout:
'BITCODE_ENABLED = YES'
,
xcodeBuildExecution:
XcodeBuildExecution
(
buildCommands:
buildCommands
,
appDirectory:
'/blah/blah'
,
buildForPhysicalDevice:
true
,
buildSettings:
buildSettings
,
),
);
await
diagnoseXcodeBuildFailure
(
buildResult
);
verify
(
mockUsage
.
sendEvent
(
'Xcode'
,
'bitcode-failure'
,
parameters:
<
String
,
String
>{
'build-commands'
:
buildCommands
.
toString
(),
'build-settings'
:
buildSettings
.
toString
(),
})).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
Usage:
()
=>
mockUsage
,
});
testUsingContext
(
'No provisioning profile shows message'
,
()
async
{
...
...
@@ -379,3 +404,5 @@ Could not build the precompiled application for the device.''',
});
});
}
class MockUsage extends Mock implements Usage {}
packages/flutter_tools/test/general.shard/project_test.dart
View file @
c953cd19
...
...
@@ -533,17 +533,6 @@ void transfer(FileSystemEntity entity, FileSystem target) {
}
}
Future
<
void
>
expectToolExitLater
(
Future
<
dynamic
>
future
,
Matcher
messageMatcher
)
async
{
try
{
await
future
;
fail
(
'ToolExit expected, but nothing thrown'
);
}
on
ToolExit
catch
(
e
)
{
expect
(
e
.
message
,
messageMatcher
);
}
catch
(
e
,
trace
)
{
fail
(
'ToolExit expected, got
$e
\n
$trace
'
);
}
}
void
expectExists
(
FileSystemEntity
entity
)
{
expect
(
entity
.
existsSync
(),
isTrue
);
}
...
...
packages/flutter_tools/test/src/common.dart
View file @
c953cd19
...
...
@@ -141,3 +141,14 @@ const Timeout allowForRemotePubInvocation = Timeout.factor(10.0);
/// Test case timeout for tests involving creating a Flutter project with
/// `--no-pub`. Use [allowForRemotePubInvocation] when creation involves `pub`.
const
Timeout
allowForCreateFlutterProject
=
Timeout
.
factor
(
3.0
);
Future
<
void
>
expectToolExitLater
(
Future
<
dynamic
>
future
,
Matcher
messageMatcher
)
async
{
try
{
await
future
;
fail
(
'ToolExit expected, but nothing thrown'
);
}
on
ToolExit
catch
(
e
)
{
expect
(
e
.
message
,
messageMatcher
);
}
catch
(
e
,
trace
)
{
fail
(
'ToolExit expected, got
$e
\n
$trace
'
);
}
}
packages/flutter_tools/test/src/mocks.dart
View file @
c953cd19
...
...
@@ -606,4 +606,7 @@ class FakeProcessResult implements ProcessResult {
@override
final
dynamic
stdout
;
@override
String
toString
()
=>
stdout
?.
toString
()
??
stderr
?.
toString
()
??
runtimeType
.
toString
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment