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
5bc100da
Unverified
Commit
5bc100da
authored
Feb 25, 2021
by
Jenn Magder
Committed by
GitHub
Feb 25, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move iOS framework thinning into the tool (#76665)
parent
9df362a7
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
364 additions
and
67 deletions
+364
-67
xcode_backend.sh
packages/flutter_tools/bin/xcode_backend.sh
+9
-65
ios.dart
packages/flutter_tools/lib/src/build_system/targets/ios.dart
+81
-1
assemble.dart
packages/flutter_tools/lib/src/commands/assemble.dart
+1
-0
ios_test.dart
...ols/test/general.shard/build_system/targets/ios_test.dart
+271
-1
ios_content_validation_test.dart
...s/test/integration.shard/ios_content_validation_test.dart
+2
-0
No files found.
packages/flutter_tools/bin/xcode_backend.sh
View file @
5bc100da
...
...
@@ -204,73 +204,17 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
return
0
}
# Returns the CFBundleExecutable for the specified framework directory.
GetFrameworkExecutablePath
()
{
local
framework_dir
=
"
$1
"
local
plist_path
=
"
${
framework_dir
}
/Info.plist"
local
executable
=
"
$(
defaults
read
"
${
plist_path
}
"
CFBundleExecutable
)
"
echo
"
${
framework_dir
}
/
${
executable
}
"
}
# Destructively thins the specified executable file to include only the
# specified architectures.
LipoExecutable
()
{
local
executable
=
"
$1
"
shift
# Split $@ into an array.
read
-r
-a
archs
<<<
"
$@
"
# Extract architecture-specific framework executables.
local
all_executables
=()
for
arch
in
"
${
archs
[@]
}
"
;
do
local
output
=
"
${
executable
}
_
${
arch
}
"
local
lipo_info
=
"
$(
lipo
-info
"
${
executable
}
"
)
"
if
[[
"
${
lipo_info
}
"
==
"Non-fat file:"
*
]]
;
then
if
[[
"
${
lipo_info
}
"
!=
*
"
${
arch
}
"
]]
;
then
echo
"Non-fat binary
${
executable
}
is not
${
arch
}
. Running lipo -info:"
echo
"
${
lipo_info
}
"
exit
1
fi
else
if
lipo
-output
"
${
output
}
"
-extract
"
${
arch
}
"
"
${
executable
}
"
;
then
all_executables+
=(
"
${
output
}
"
)
else
echo
"Failed to extract
${
arch
}
for
${
executable
}
. Running lipo -info:"
RunCommand lipo
-info
"
${
executable
}
"
exit
1
fi
fi
done
# Generate a merged binary from the architecture-specific executables.
# Skip this step for non-fat executables.
if
[[
${#
all_executables
[@]
}
>
0
]]
;
then
local
merged
=
"
${
executable
}
_merged"
RunCommand lipo
-output
"
${
merged
}
"
-create
"
${
all_executables
[@]
}
"
RunCommand
cp
-f
--
"
${
merged
}
"
"
${
executable
}
"
>
/dev/null
RunCommand
rm
-f
--
"
${
merged
}
"
"
${
all_executables
[@]
}
"
fi
}
# Destructively thins the specified framework to include only the specified
# Destructively thins the Flutter and App frameworks to include only the specified
# architectures.
ThinFramework
()
{
local
framework_dir
=
"
$1
"
shift
local
executable
=
"
$(
GetFrameworkExecutablePath
"
${
framework_dir
}
"
)
"
LipoExecutable
"
${
executable
}
"
"
$@
"
}
ThinAppFrameworks
()
{
local
xcode_frameworks_dir
=
"
${
TARGET_BUILD_DIR
}
/
${
FRAMEWORKS_FOLDER_PATH
}
"
[[
-d
"
${
xcode_frameworks_dir
}
"
]]
||
return
0
find
"
${
xcode_frameworks_dir
}
"
-type
d
-name
"*.framework"
|
while
read
framework_dir
;
do
ThinFramework
"
$framework_dir
"
"
$ARCHS
"
done
RunCommand
"
${
FLUTTER_ROOT
}
/bin/flutter"
\
${
verbose_flag
}
\
assemble
\
--no-version-check
\
--output
=
"
${
TARGET_BUILD_DIR
}
/
${
FRAMEWORKS_FOLDER_PATH
}
"
\
-dTargetPlatform
=
ios
\
-dIosArchs
=
"
${
ARCHS
}
"
\
"thin_ios_application_frameworks"
}
# Adds the App.framework as an embedded binary and the flutter_assets as
...
...
packages/flutter_tools/lib/src/build_system/targets/ios.dart
View file @
5bc100da
...
...
@@ -417,7 +417,6 @@ abstract class IosAssetBundle extends Target {
environment
.
buildDir
.
childFile
(
'flutter_assets.d'
),
);
// Copy the plist from either the project or module.
// TODO(jonahwilliams): add plist to inputs
final
FlutterProject
flutterProject
=
FlutterProject
.
fromDirectory
(
environment
.
projectDir
);
...
...
@@ -535,3 +534,84 @@ Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot,
}
}
}
/// Destructively thins the specified executable file to include only the specified architectures.
///
/// This target is not fingerprinted and will always run.
class
ThinIosApplicationFrameworks
extends
Target
{
const
ThinIosApplicationFrameworks
();
@override
String
get
name
=>
'thin_ios_application_frameworks'
;
@override
List
<
Target
>
get
dependencies
=>
const
<
Target
>[];
@override
List
<
Source
>
get
inputs
=>
const
<
Source
>[];
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[];
@override
Future
<
void
>
build
(
Environment
environment
)
async
{
if
(
environment
.
defines
[
kIosArchs
]
==
null
)
{
throw
MissingDefineException
(
kIosArchs
,
'thin_ios_application_frameworks'
);
}
final
Directory
frameworkDirectory
=
environment
.
outputDir
;
final
File
appFramework
=
frameworkDirectory
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
);
final
File
flutterFramework
=
frameworkDirectory
.
childDirectory
(
'Flutter.framework'
).
childFile
(
'Flutter'
);
await
_thinBinary
(
appFramework
,
environment
);
await
_thinBinary
(
flutterFramework
,
environment
);
}
Future
<
void
>
_thinBinary
(
File
binary
,
Environment
environment
)
async
{
final
String
binaryPath
=
binary
.
path
;
if
(!
binary
.
existsSync
())
{
throw
Exception
(
'Binary
$binaryPath
does not exist, cannot thin'
);
}
final
String
archs
=
environment
.
defines
[
kIosArchs
];
final
List
<
String
>
archList
=
archs
.
split
(
' '
).
toList
();
final
ProcessResult
infoResult
=
environment
.
processManager
.
runSync
(<
String
>[
'lipo'
,
'-info'
,
binaryPath
,
]);
final
String
lipoInfo
=
infoResult
.
stdout
as
String
;
final
ProcessResult
verifyResult
=
environment
.
processManager
.
runSync
(<
String
>[
'lipo'
,
binaryPath
,
'-verify_arch'
,
...
archList
]);
if
(
verifyResult
.
exitCode
!=
0
)
{
throw
Exception
(
'Binary
$binaryPath
does not contain
$archs
. Running lipo -info:
\n
$lipoInfo
'
);
}
// Skip this step for non-fat executables.
if
(
lipoInfo
.
startsWith
(
'Non-fat file:'
))
{
environment
.
logger
.
printTrace
(
'Skipping lipo for non-fat file
$binaryPath
'
);
return
;
}
// Thin in-place.
final
ProcessResult
extractResult
=
environment
.
processManager
.
runSync
(<
String
>[
'lipo'
,
'-output'
,
binaryPath
,
for
(
final
String
arch
in
archList
)
...<
String
>[
'-extract'
,
arch
,
],
...<
String
>[
binaryPath
],
]);
if
(
extractResult
.
exitCode
!=
0
)
{
throw
Exception
(
'Failed to extract
$archs
for
$binaryPath
.
\n
${extractResult.stderr}
\n
Running lipo -info:
\n
$lipoInfo
'
);
}
}
}
packages/flutter_tools/lib/src/commands/assemble.dart
View file @
5bc100da
...
...
@@ -66,6 +66,7 @@ const List<Target> _kDefaultTargets = <Target>[
DebugIosApplicationBundle
(),
ProfileIosApplicationBundle
(),
ReleaseIosApplicationBundle
(),
ThinIosApplicationFrameworks
(),
// Windows targets
UnpackWindows
(),
DebugBundleWindowsAssets
(),
...
...
packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart
View file @
5bc100da
...
...
@@ -45,7 +45,7 @@ void main() {
FileSystem
fileSystem
;
FakeProcessManager
processManager
;
Artifacts
artifacts
;
Logger
logger
;
Buffer
Logger
logger
;
setUp
(()
{
fileSystem
=
MemoryFileSystem
.
test
();
...
...
@@ -300,4 +300,274 @@ void main() {
await
const
DebugUnpackIOS
().
build
(
environment
);
});
});
group
(
'thin frameworks'
,
()
{
testWithoutContext
(
'fails when frameworks missing'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
outputDir
=
fileSystem
.
directory
(
'Runner.app'
).
childDirectory
(
'Frameworks'
);
final
Environment
environment
=
Environment
.
test
(
fileSystem
.
currentDirectory
,
processManager:
processManager
,
artifacts:
artifacts
,
logger:
logger
,
fileSystem:
fileSystem
,
outputDir:
outputDir
,
defines:
<
String
,
String
>{
kIosArchs:
'arm64'
,
},
);
expect
(
const
ThinIosApplicationFrameworks
().
build
(
environment
),
throwsA
(
isA
<
Exception
>().
having
(
(
Exception
exception
)
=>
exception
.
toString
(),
'description'
,
contains
(
'App.framework/App does not exist, cannot thin'
),
)));
});
testWithoutContext
(
'fails when requested archs missing from framework'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
outputDir
=
fileSystem
.
directory
(
'Runner.app'
).
childDirectory
(
'Frameworks'
)..
createSync
(
recursive:
true
);
final
File
appBinary
=
outputDir
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
)..
createSync
(
recursive:
true
);
final
Environment
environment
=
Environment
.
test
(
fileSystem
.
currentDirectory
,
processManager:
processManager
,
artifacts:
artifacts
,
logger:
logger
,
fileSystem:
fileSystem
,
outputDir:
outputDir
,
defines:
<
String
,
String
>{
kIosArchs:
'arm64 armv7'
,
},
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
appBinary
.
path
,
],
stdout:
'Architectures in the fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
appBinary
.
path
,
'-verify_arch'
,
'arm64'
,
'armv7'
,
],
exitCode:
1
),
);
expect
(
const
ThinIosApplicationFrameworks
().
build
(
environment
),
throwsA
(
isA
<
Exception
>().
having
(
(
Exception
exception
)
=>
exception
.
toString
(),
'description'
,
contains
(
'does not contain arm64 armv7. Running lipo -info:
\n
Architectures in the fat file:'
),
)));
});
testWithoutContext
(
'fails when lipo extract fails'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
outputDir
=
fileSystem
.
directory
(
'Runner.app'
).
childDirectory
(
'Frameworks'
)..
createSync
(
recursive:
true
);
final
File
appBinary
=
outputDir
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
)..
createSync
(
recursive:
true
);
final
Environment
environment
=
Environment
.
test
(
fileSystem
.
currentDirectory
,
processManager:
processManager
,
artifacts:
artifacts
,
logger:
logger
,
fileSystem:
fileSystem
,
outputDir:
outputDir
,
defines:
<
String
,
String
>{
kIosArchs:
'arm64 armv7'
,
},
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
appBinary
.
path
,
],
stdout:
'Architectures in the fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
appBinary
.
path
,
'-verify_arch'
,
'arm64'
,
'armv7'
,
]),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-output'
,
appBinary
.
path
,
'-extract'
,
'arm64'
,
'-extract'
,
'armv7'
,
appBinary
.
path
,
],
exitCode:
1
,
stderr:
'lipo error'
),
);
expect
(
const
ThinIosApplicationFrameworks
().
build
(
environment
),
throwsA
(
isA
<
Exception
>().
having
(
(
Exception
exception
)
=>
exception
.
toString
(),
'description'
,
contains
(
'Failed to extract arm64 armv7 for Runner.app/Frameworks/App.framework/App.
\n
lipo error
\n
Running lipo -info:
\n
Architectures in the fat file:'
),
)));
});
testWithoutContext
(
'skips thin frameworks'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
outputDir
=
fileSystem
.
directory
(
'Runner.app'
).
childDirectory
(
'Frameworks'
)..
createSync
(
recursive:
true
);
final
File
appBinary
=
outputDir
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
)..
createSync
(
recursive:
true
);
final
File
flutterBinary
=
outputDir
.
childDirectory
(
'Flutter.framework'
).
childFile
(
'Flutter'
)..
createSync
(
recursive:
true
);
final
Environment
environment
=
Environment
.
test
(
fileSystem
.
currentDirectory
,
processManager:
processManager
,
artifacts:
artifacts
,
logger:
logger
,
fileSystem:
fileSystem
,
outputDir:
outputDir
,
defines:
<
String
,
String
>{
kIosArchs:
'arm64'
,
},
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
appBinary
.
path
,
],
stdout:
'Non-fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
appBinary
.
path
,
'-verify_arch'
,
'arm64'
,
]),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
flutterBinary
.
path
,
],
stdout:
'Non-fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
flutterBinary
.
path
,
'-verify_arch'
,
'arm64'
,
]),
);
await
const
ThinIosApplicationFrameworks
().
build
(
environment
);
expect
(
logger
.
traceText
,
contains
(
'Skipping lipo for non-fat file Runner.app/Frameworks/App.framework/App'
));
expect
(
logger
.
traceText
,
contains
(
'Skipping lipo for non-fat file Runner.app/Frameworks/Flutter.framework/Flutter'
));
expect
(
processManager
.
hasRemainingExpectations
,
isFalse
);
});
testWithoutContext
(
'thins fat frameworks'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
outputDir
=
fileSystem
.
directory
(
'Runner.app'
).
childDirectory
(
'Frameworks'
)..
createSync
(
recursive:
true
);
final
File
appBinary
=
outputDir
.
childDirectory
(
'App.framework'
).
childFile
(
'App'
)..
createSync
(
recursive:
true
);
final
File
flutterBinary
=
outputDir
.
childDirectory
(
'Flutter.framework'
).
childFile
(
'Flutter'
)..
createSync
(
recursive:
true
);
final
Environment
environment
=
Environment
.
test
(
fileSystem
.
currentDirectory
,
processManager:
processManager
,
artifacts:
artifacts
,
logger:
logger
,
fileSystem:
fileSystem
,
outputDir:
outputDir
,
defines:
<
String
,
String
>{
kIosArchs:
'arm64 armv7'
,
},
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
appBinary
.
path
,
],
stdout:
'Architectures in the fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
appBinary
.
path
,
'-verify_arch'
,
'arm64'
,
'armv7'
,
]),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-output'
,
appBinary
.
path
,
'-extract'
,
'arm64'
,
'-extract'
,
'armv7'
,
appBinary
.
path
,
]),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-info'
,
flutterBinary
.
path
,
],
stdout:
'Architectures in the fat file:'
),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
flutterBinary
.
path
,
'-verify_arch'
,
'arm64'
,
'armv7'
,
]),
);
processManager
.
addCommand
(
FakeCommand
(
command:
<
String
>[
'lipo'
,
'-output'
,
flutterBinary
.
path
,
'-extract'
,
'arm64'
,
'-extract'
,
'armv7'
,
flutterBinary
.
path
,
]),
);
await
const
ThinIosApplicationFrameworks
().
build
(
environment
);
expect
(
processManager
.
hasRemainingExpectations
,
isFalse
);
});
});
}
packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart
View file @
5bc100da
...
...
@@ -195,6 +195,8 @@ void main() {
'VERBOSE_SCRIPT_LOGGING'
:
'1'
,
'FLUTTER_BUILD_MODE'
:
'release'
,
'ACTION'
:
'install'
,
'ARCHS'
:
'arm64 armv7'
,
'FLUTTER_ROOT'
:
flutterRoot
,
// Skip bitcode stripping since we just checked that above.
},
);
...
...
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