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
2a7d5779
Commit
2a7d5779
authored
Jan 22, 2020
by
Jenn Magder
Committed by
Flutter GitHub Bot
Jan 22, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Generate bitcode for plugin frameworks for flutter build ios-framework (#49102)
parent
4c32ae8e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
111 additions
and
29 deletions
+111
-29
build_ios_framework_module_test.dart
dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+29
-1
ios.dart
dev/devicelab/lib/framework/ios.dart
+44
-2
build_ios_framework.dart
...s/flutter_tools/lib/src/commands/build_ios_framework.dart
+13
-6
project.dart
packages/flutter_tools/lib/src/project.dart
+25
-20
No files found.
dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
View file @
2a7d5779
...
...
@@ -42,6 +42,21 @@ Future<void> main() async {
);
});
// First, build the module in Debug to copy the debug version of Flutter.framework.
// This proves "flutter build ios-framework" re-copies the relevant Flutter.framework,
// otherwise building plugins with bitcode will fail linking because the debug version
// of Flutter.framework does not contain bitcode.
await
inDirectory
(
projectDir
,
()
async
{
await
flutter
(
'build'
,
options:
<
String
>[
'ios'
,
'--debug'
,
'--no-codesign'
,
],
);
});
// This builds all build modes' frameworks by default
section
(
'Build frameworks'
);
...
...
@@ -123,6 +138,7 @@ Future<void> main() async {
);
await
_checkFrameworkArchs
(
appFrameworkPath
,
mode
);
await
_checkBitcode
(
appFrameworkPath
,
mode
);
final
String
aotSymbols
=
await
dylibSymbols
(
appFrameworkPath
);
...
...
@@ -168,6 +184,7 @@ Future<void> main() async {
);
await
_checkFrameworkArchs
(
engineFrameworkPath
,
mode
);
await
_checkBitcode
(
engineFrameworkPath
,
mode
);
checkFileExists
(
path
.
join
(
outputPath
,
...
...
@@ -211,6 +228,7 @@ Future<void> main() async {
'device_info'
,
);
await
_checkFrameworkArchs
(
pluginFrameworkPath
,
mode
);
await
_checkBitcode
(
pluginFrameworkPath
,
mode
);
checkFileExists
(
path
.
join
(
outputPath
,
...
...
@@ -235,7 +253,7 @@ Future<void> main() async {
}
}
section
(
"Check all modes' have generated plugin registrant"
);
section
(
'Check all modes have generated plugin registrant'
);
for
(
final
String
mode
in
<
String
>[
'Debug'
,
'Profile'
,
'Release'
])
{
final
String
registrantFrameworkPath
=
path
.
join
(
...
...
@@ -246,6 +264,7 @@ Future<void> main() async {
);
await
_checkFrameworkArchs
(
registrantFrameworkPath
,
mode
);
await
_checkBitcode
(
registrantFrameworkPath
,
mode
);
checkFileExists
(
path
.
join
(
outputPath
,
...
...
@@ -310,3 +329,12 @@ Future<void> _checkFrameworkArchs(String frameworkPath, String mode) async {
throw
TaskResult
.
failure
(
'
$mode
$frameworkPath
x86_64 architecture
${isDebug ? 'missing' : 'present'}
'
);
}
}
Future
<
void
>
_checkBitcode
(
String
frameworkPath
,
String
mode
)
async
{
checkFileExists
(
frameworkPath
);
// Bitcode only needed in Release mode for archiving.
if
(
mode
==
'Release'
&&
!
await
containsBitcode
(
frameworkPath
))
{
throw
TaskResult
.
failure
(
'
$frameworkPath
does not contain bitcode'
);
}
}
dev/devicelab/lib/framework/ios.dart
View file @
2a7d5779
...
...
@@ -54,6 +54,48 @@ Future<String> dylibSymbols(String pathToDylib) {
return
eval
(
'nm'
,
<
String
>[
'-g'
,
pathToDylib
]);
}
Future
<
String
>
fileType
(
String
pathToDylib
)
{
return
eval
(
'file'
,
<
String
>[
pathToDylib
]);
Future
<
String
>
fileType
(
String
pathToBinary
)
{
return
eval
(
'file'
,
<
String
>[
pathToBinary
]);
}
Future
<
bool
>
containsBitcode
(
String
pathToBinary
)
async
{
// See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
final
String
loadCommands
=
await
eval
(
'otool'
,
<
String
>[
'-l'
,
pathToBinary
,
]);
if
(!
loadCommands
.
contains
(
'__LLVM'
))
{
return
false
;
}
// Presence of the section may mean a bitcode marker was embedded (size=1), but there is no content.
if
(!
loadCommands
.
contains
(
'size 0x0000000000000001'
))
{
return
true
;
}
// Check the false positives: size=1 wasn't referencing the __LLVM section.
bool
emptyBitcodeMarkerFound
=
false
;
// Section
// sectname __bundle
// segname __LLVM
// addr 0x003c4000
// size 0x0042b633
// offset 3932160
// ...
final
List
<
String
>
lines
=
LineSplitter
.
split
(
loadCommands
).
toList
();
lines
.
asMap
().
forEach
((
int
index
,
String
line
)
{
if
(
line
.
contains
(
'segname __LLVM'
)
&&
lines
.
length
-
index
-
1
>
3
)
{
final
String
emptyBitcodeMarker
=
lines
.
skip
(
index
-
1
)
.
take
(
3
)
.
firstWhere
(
(
String
line
)
=>
line
.
contains
(
' size 0x0000000000000001'
),
orElse:
()
=>
null
,
);
if
(
emptyBitcodeMarker
!=
null
)
{
emptyBitcodeMarkerFound
=
true
;
return
;
}
}
});
return
!
emptyBitcodeMarkerFound
;
}
packages/flutter_tools/lib/src/commands/build_ios_framework.dart
View file @
2a7d5779
...
...
@@ -159,7 +159,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
cache
??=
globals
.
cache
;
for
(
final
BuildMode
mode
in
buildModes
)
{
globals
.
printStatus
(
'Building framework for
$iosProject
in
${getNameForBuildMode(mode)}
mode...'
);
globals
.
printStatus
(
'Building framework
s
for
$iosProject
in
${getNameForBuildMode(mode)}
mode...'
);
final
String
xcodeBuildConfiguration
=
toTitleCase
(
getNameForBuildMode
(
mode
));
final
Directory
modeDirectory
=
outputDirectory
.
childDirectory
(
xcodeBuildConfiguration
);
...
...
@@ -175,7 +175,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
produceFlutterPodspec
(
mode
,
modeDirectory
);
}
else
{
// Copy Flutter.framework.
await
_produceFlutterFramework
(
outputDirectory
,
mode
,
iPhoneBuildOutput
,
simulatorBuildOutput
,
modeDirectory
);
await
_produceFlutterFramework
(
mode
,
modeDirectory
);
}
// Build aot, create module.framework and copy.
...
...
@@ -266,10 +266,7 @@ end
}
Future<void> _produceFlutterFramework(
Directory outputDirectory,
BuildMode mode,
Directory iPhoneBuildOutput,
Directory simulatorBuildOutput,
Directory modeDirectory,
) async {
final Status status = globals.logger.startProgress(
...
...
@@ -446,6 +443,15 @@ end
final Status status = globals.logger.startProgress(
'
├─
Building
plugins
...
', timeout: timeoutConfiguration.slowOperation);
try {
// Regardless of the last "flutter build" build mode,
// copy the corresponding engine.
// A plugin framework built with bitcode must link against the bitcode version
// of Flutter.framework (Release).
_project.ios.copyEngineArtifactToProject(mode);
final String bitcodeGenerationMode = mode == BuildMode.release ?
'
bitcode
' : '
marker
'; // In release, force bitcode embedding without archiving.
List<String> pluginsBuildCommand = <String>[
'
xcrun
',
'
xcodebuild
',
...
...
@@ -455,6 +461,7 @@ end
'
-
configuration
',
xcodeBuildConfiguration,
'
SYMROOT
=
$
{
iPhoneBuildOutput
.
path
}
',
'
BITCODE_GENERATION_MODE
=
$bitcodeGenerationMode
',
'
ONLY_ACTIVE_ARCH
=
NO
' // No device targeted, so build all valid architectures.
];
...
...
@@ -592,7 +599,7 @@ end
final Status status = globals.logger.startProgress(
'
├─
Creating
$frameworkBinaryName
.
xcframework
...
',
timeout: timeoutConfiguration.
fast
Operation,
timeout: timeoutConfiguration.
slow
Operation,
);
try {
if (mode == BuildMode.debug) {
...
...
packages/flutter_tools/lib/src/project.dart
View file @
2a7d5779
...
...
@@ -490,10 +490,6 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
return;
}
final Directory engineDest = ephemeralDirectory
.childDirectory('
Flutter
')
.childDirectory('
engine
');
_deleteIfExistsSync(ephemeralDirectory);
_overwriteFromTemplate(
globals.fs.path.join('
module
', '
ios
', '
library
'),
...
...
@@ -511,23 +507,32 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
ephemeralDirectory,
);
}
// Copy podspec and framework from engine cache. The actual build mode
// doesn'
t
actually
matter
as
it
will
be
overwritten
by
xcode_backend
.
sh
.
// However, cocoapods will run before that script and requires something
// to be in this location.
final
Directory
framework
=
globals
.
fs
.
directory
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
copyEngineArtifactToProject(BuildMode.debug);
}
}
void copyEngineArtifactToProject(BuildMode mode) {
// Copy podspec and framework from engine cache. The actual build mode
// doesn'
t
actually
matter
as
it
will
be
overwritten
by
xcode_backend
.
sh
.
// However, cocoapods will run before that script and requires something
// to be in this location.
final
Directory
framework
=
globals
.
fs
.
directory
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
platform:
TargetPlatform
.
ios
,
mode:
BuildMode
.
debug
,
));
if
(
framework
.
existsSync
())
{
final
File
podspec
=
framework
.
parent
.
childFile
(
'Flutter.podspec'
);
fsUtils
.
copyDirectorySync
(
framework
,
engineDest
.
childDirectory
(
'Flutter.framework'
),
);
podspec
.
copySync
(
engineDest
.
childFile
(
'Flutter.podspec'
).
path
);
}
mode:
mode
,
)
);
if
(
framework
.
existsSync
())
{
final
Directory
engineDest
=
ephemeralDirectory
.
childDirectory
(
'Flutter'
)
.
childDirectory
(
'engine'
);
final
File
podspec
=
framework
.
parent
.
childFile
(
'Flutter.podspec'
);
fsUtils
.
copyDirectorySync
(
framework
,
engineDest
.
childDirectory
(
'Flutter.framework'
),
);
podspec
.
copySync
(
engineDest
.
childFile
(
'Flutter.podspec'
).
path
);
}
}
...
...
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