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
d2e87a5d
Unverified
Commit
d2e87a5d
authored
Nov 06, 2019
by
xster
Committed by
GitHub
Nov 06, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Build ios framework (#44065)
parent
028ed712
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
951 additions
and
283 deletions
+951
-283
test.dart
dev/bots/test.dart
+1
-0
build_ios_framework_module_test.dart
dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
+143
-0
utils.dart
dev/devicelab/lib/framework/utils.dart
+7
-0
aot.dart
packages/flutter_tools/lib/src/aot.dart
+239
-0
build.dart
packages/flutter_tools/lib/src/base/build.dart
+6
-1
file_system.dart
packages/flutter_tools/lib/src/base/file_system.dart
+1
-1
ios.dart
packages/flutter_tools/lib/src/build_system/targets/ios.dart
+54
-7
build.dart
packages/flutter_tools/lib/src/commands/build.dart
+2
-0
build_aar.dart
packages/flutter_tools/lib/src/commands/build_aar.dart
+4
-4
build_aot.dart
packages/flutter_tools/lib/src/commands/build_aot.dart
+21
-268
build_ios.dart
packages/flutter_tools/lib/src/commands/build_ios.dart
+5
-1
build_ios_framework.dart
...s/flutter_tools/lib/src/commands/build_ios_framework.dart
+400
-0
bitcode.dart
packages/flutter_tools/lib/src/ios/bitcode.dart
+67
-0
build_aot_test.dart
...ter_tools/test/general.shard/commands/build_aot_test.dart
+1
-1
No files found.
dev/bots/test.dart
View file @
d2e87a5d
...
...
@@ -761,6 +761,7 @@ Future<void> _runHostOnlyDeviceLabTests() async {
// TODO(jmagman): Re-enable once flakiness is resolved, https://github.com/flutter/flutter/issues/37525
// if (Platform.isMacOS) () => _runDevicelabTest('module_test_ios'),
if
(
Platform
.
isMacOS
)
()
=>
_runDevicelabTest
(
'build_ios_framework_module_test'
),
if
(
Platform
.
isMacOS
)
()
=>
_runDevicelabTest
(
'plugin_lint_mac'
),
()
=>
_runDevicelabTest
(
'plugin_test'
,
environment:
gradleEnvironment
),
]..
shuffle
(
math
.
Random
(
0
));
...
...
dev/devicelab/bin/tasks/build_ios_framework_module_test.dart
0 → 100644
View file @
d2e87a5d
// Copyright (c) 2019 The Chromium 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
'dart:async'
;
import
'dart:io'
;
import
'package:flutter_devicelab/framework/apk_utils.dart'
;
import
'package:flutter_devicelab/framework/framework.dart'
;
import
'package:flutter_devicelab/framework/utils.dart'
;
import
'package:path/path.dart'
as
path
;
/// Tests that iOS .frameworks can be built on module projects.
Future
<
void
>
main
()
async
{
await
task
(()
async
{
section
(
'Create module project'
);
final
Directory
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_module_test.'
);
final
Directory
projectDir
=
Directory
(
path
.
join
(
tempDir
.
path
,
'hello'
));
try
{
await
inDirectory
(
tempDir
,
()
async
{
await
flutter
(
'create'
,
options:
<
String
>[
'--org'
,
'io.flutter.devicelab'
,
'--template'
,
'module'
,
'hello'
],
);
});
section
(
'Add plugins'
);
final
File
pubspec
=
File
(
path
.
join
(
projectDir
.
path
,
'pubspec.yaml'
));
String
content
=
pubspec
.
readAsStringSync
();
content
=
content
.
replaceFirst
(
'
\n
dependencies:
\n
'
,
'
\n
dependencies:
\n
device_info: 0.4.1
\n
package_info: 0.4.0+9
\n
'
,
);
pubspec
.
writeAsStringSync
(
content
,
flush:
true
);
await
inDirectory
(
projectDir
,
()
async
{
await
flutter
(
'packages'
,
options:
<
String
>[
'get'
],
);
});
// This builds all build modes' frameworks by default
section
(
'Build frameworks'
);
await
inDirectory
(
projectDir
,
()
async
{
await
flutter
(
'build'
,
options:
<
String
>[
'ios-framework'
],
);
});
final
String
outputPath
=
path
.
join
(
projectDir
.
path
,
'build'
,
'ios'
,
'framework'
,
);
section
(
'Check debug build has Dart snapshot as asset'
);
checkFileExists
(
path
.
join
(
outputPath
,
'Debug'
,
'App.framework'
,
'flutter_assets'
,
'vm_snapshot_data'
,
));
section
(
'Check profile, release builds has Dart dylib'
);
for
(
String
mode
in
<
String
>[
'Profile'
,
'Release'
])
{
checkFileExists
(
path
.
join
(
outputPath
,
mode
,
'App.framework'
,
'App'
,
));
checkFileNotExists
(
path
.
join
(
outputPath
,
mode
,
'App.framework'
,
'flutter_assets'
,
'vm_snapshot_data'
,
));
}
section
(
"Check all modes' engine dylib"
);
for
(
String
mode
in
<
String
>[
'Debug'
,
'Profile'
,
'Release'
])
{
checkFileExists
(
path
.
join
(
outputPath
,
mode
,
'Flutter.framework'
,
'Flutter'
,
));
}
section
(
"Check all modes' engine header"
);
for
(
String
mode
in
<
String
>[
'Debug'
,
'Profile'
,
'Release'
])
{
checkFileContains
(
<
String
>[
'#include "FlutterEngine.h"'
],
path
.
join
(
outputPath
,
mode
,
'Flutter.framework'
,
'Headers'
,
'Flutter.h'
),
);
}
section
(
"Check all modes' have plugin dylib"
);
for
(
String
mode
in
<
String
>[
'Debug'
,
'Profile'
,
'Release'
])
{
checkFileExists
(
path
.
join
(
outputPath
,
mode
,
'device_info.framework'
,
'device_info'
,
));
}
section
(
"Check all modes' have generated plugin registrant"
);
for
(
String
mode
in
<
String
>[
'Debug'
,
'Profile'
,
'Release'
])
{
checkFileExists
(
path
.
join
(
outputPath
,
mode
,
'FlutterPluginRegistrant.framework'
,
'Headers'
,
'GeneratedPluginRegistrant.h'
,
));
}
return
TaskResult
.
success
(
null
);
}
on
TaskResult
catch
(
taskResult
)
{
return
taskResult
;
}
catch
(
e
)
{
return
TaskResult
.
failure
(
e
.
toString
());
}
finally
{
rmTree
(
tempDir
);
}
});
}
dev/devicelab/lib/framework/utils.dart
View file @
d2e87a5d
...
...
@@ -625,6 +625,13 @@ void checkFileExists(String file) {
}
}
/// Checks that the file does not exists, otherwise throws a [FileSystemException].
void
checkFileNotExists
(
String
file
)
{
if
(
exists
(
File
(
file
)))
{
throw
FileSystemException
(
'Expected file to exit.'
,
file
);
}
}
void
_checkExitCode
(
int
code
)
{
if
(
code
!=
0
)
{
throw
Exception
(
...
...
packages/flutter_tools/lib/src/aot.dart
0 → 100644
View file @
d2e87a5d
// Copyright 2019 The Chromium 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
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'base/build.dart'
;
import
'base/common.dart'
;
import
'base/file_system.dart'
;
import
'base/io.dart'
;
import
'base/logger.dart'
;
import
'base/process.dart'
;
import
'build_info.dart'
;
import
'build_system/build_system.dart'
;
import
'build_system/targets/dart.dart'
;
import
'dart/package_map.dart'
;
import
'globals.dart'
;
import
'ios/bitcode.dart'
;
import
'project.dart'
;
/// Builds AOT snapshots given a platform, build mode and a path to a Dart
/// library.
class
AotBuilder
{
Future
<
void
>
build
({
@required
TargetPlatform
platform
,
@required
String
outputPath
,
@required
BuildMode
buildMode
,
@required
String
mainDartFile
,
bool
bitcode
=
kBitcodeEnabledDefault
,
bool
quiet
=
true
,
bool
reportTimings
=
false
,
Iterable
<
DarwinArch
>
iosBuildArchs
=
defaultIOSArchs
,
List
<
String
>
extraFrontEndOptions
,
List
<
String
>
extraGenSnapshotOptions
,
})
async
{
if
(
platform
==
null
)
{
throwToolExit
(
'No AOT build platform specified'
);
}
if
(
_canUseAssemble
(
platform
)
&&
extraGenSnapshotOptions
?.
isEmpty
!=
false
&&
extraFrontEndOptions
?.
isEmpty
!=
false
)
{
await
_buildWithAssemble
(
targetFile:
mainDartFile
,
outputDir:
outputPath
,
targetPlatform:
platform
,
buildMode:
buildMode
,
quiet:
quiet
,
);
return
;
}
if
(
bitcode
)
{
if
(
platform
!=
TargetPlatform
.
ios
)
{
throwToolExit
(
'Bitcode is only supported on iOS (TargetPlatform is
$platform
).'
);
}
await
validateBitcode
(
buildMode
,
platform
);
}
Status
status
;
if
(!
quiet
)
{
final
String
typeName
=
artifacts
.
getEngineType
(
platform
,
buildMode
);
status
=
logger
.
startProgress
(
'Building AOT snapshot in
${getFriendlyModeName(buildMode)}
mode (
$typeName
)...'
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
}
try
{
final
AOTSnapshotter
snapshotter
=
AOTSnapshotter
(
reportTimings:
reportTimings
);
// Compile to kernel.
final
String
kernelOut
=
await
snapshotter
.
compileKernel
(
platform:
platform
,
buildMode:
buildMode
,
mainPath:
mainDartFile
,
packagesPath:
PackageMap
.
globalPackagesPath
,
trackWidgetCreation:
false
,
outputPath:
outputPath
,
extraFrontEndOptions:
extraFrontEndOptions
,
);
if
(
kernelOut
==
null
)
{
throwToolExit
(
'Compiler terminated unexpectedly.'
);
return
;
}
// Build AOT snapshot.
if
(
platform
==
TargetPlatform
.
ios
)
{
// Determine which iOS architectures to build for.
final
Map
<
DarwinArch
,
String
>
iosBuilds
=
<
DarwinArch
,
String
>{};
for
(
DarwinArch
arch
in
iosBuildArchs
)
{
iosBuilds
[
arch
]
=
fs
.
path
.
join
(
outputPath
,
getNameForDarwinArch
(
arch
));
}
// Generate AOT snapshot and compile to arch-specific App.framework.
final
Map
<
DarwinArch
,
Future
<
int
>>
exitCodes
=
<
DarwinArch
,
Future
<
int
>>{};
iosBuilds
.
forEach
((
DarwinArch
iosArch
,
String
outputPath
)
{
exitCodes
[
iosArch
]
=
snapshotter
.
build
(
platform:
platform
,
darwinArch:
iosArch
,
buildMode:
buildMode
,
mainPath:
kernelOut
,
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
extraGenSnapshotOptions
,
bitcode:
bitcode
,
quiet:
quiet
,
).
then
<
int
>((
int
buildExitCode
)
{
return
buildExitCode
;
});
});
// Merge arch-specific App.frameworks into a multi-arch App.framework.
if
((
await
Future
.
wait
<
int
>(
exitCodes
.
values
)).
every
((
int
buildExitCode
)
=>
buildExitCode
==
0
))
{
final
Iterable
<
String
>
dylibs
=
iosBuilds
.
values
.
map
<
String
>(
(
String
outputDir
)
=>
fs
.
path
.
join
(
outputDir
,
'App.framework'
,
'App'
));
fs
.
directory
(
fs
.
path
.
join
(
outputPath
,
'App.framework'
))..
createSync
();
await
processUtils
.
run
(
<
String
>[
'lipo'
,
...
dylibs
,
'-create'
,
'-output'
,
fs
.
path
.
join
(
outputPath
,
'App.framework'
,
'App'
),
],
throwOnError:
true
,
);
}
else
{
status
?.
cancel
();
exitCodes
.
forEach
((
DarwinArch
iosArch
,
Future
<
int
>
exitCodeFuture
)
async
{
final
int
buildExitCode
=
await
exitCodeFuture
;
printError
(
'Snapshotting (
$iosArch
) exited with non-zero exit code:
$buildExitCode
'
);
});
}
}
else
{
// Android AOT snapshot.
final
int
snapshotExitCode
=
await
snapshotter
.
build
(
platform:
platform
,
buildMode:
buildMode
,
mainPath:
kernelOut
,
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
extraGenSnapshotOptions
,
bitcode:
false
,
);
if
(
snapshotExitCode
!=
0
)
{
status
?.
cancel
();
throwToolExit
(
'Snapshotting exited with non-zero exit code:
$snapshotExitCode
'
);
}
}
}
on
ProcessException
catch
(
error
)
{
// Catch the String exceptions thrown from the `runSync` methods below.
status
?.
cancel
();
printError
(
error
.
toString
());
return
;
}
status
?.
stop
();
if
(
outputPath
==
null
)
{
throwToolExit
(
null
);
}
final
String
builtMessage
=
'Built to
$outputPath${fs.path.separator}
.'
;
if
(
quiet
)
{
printTrace
(
builtMessage
);
}
else
{
printStatus
(
builtMessage
);
}
return
;
}
bool
_canUseAssemble
(
TargetPlatform
targetPlatform
)
{
switch
(
targetPlatform
)
{
case
TargetPlatform
.
android_arm
:
case
TargetPlatform
.
android_arm64
:
case
TargetPlatform
.
android_x86
:
case
TargetPlatform
.
darwin_x64
:
return
true
;
case
TargetPlatform
.
android_x64
:
case
TargetPlatform
.
ios
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia_arm64
:
case
TargetPlatform
.
fuchsia_x64
:
case
TargetPlatform
.
tester
:
case
TargetPlatform
.
web_javascript
:
default
:
return
false
;
}
}
Future
<
void
>
_buildWithAssemble
({
TargetPlatform
targetPlatform
,
BuildMode
buildMode
,
String
targetFile
,
String
outputDir
,
bool
quiet
})
async
{
Status
status
;
if
(!
quiet
)
{
final
String
typeName
=
artifacts
.
getEngineType
(
targetPlatform
,
buildMode
);
status
=
logger
.
startProgress
(
'Building AOT snapshot in
${getFriendlyModeName(buildMode)}
mode (
$typeName
)...'
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
}
final
FlutterProject
flutterProject
=
FlutterProject
.
current
();
// Currently this only supports android, per the check above.
final
Target
target
=
buildMode
==
BuildMode
.
profile
?
const
ProfileCopyFlutterAotBundle
()
:
const
ReleaseCopyFlutterAotBundle
();
final
BuildResult
result
=
await
buildSystem
.
build
(
target
,
Environment
(
projectDir:
flutterProject
.
directory
,
outputDir:
fs
.
directory
(
outputDir
),
buildDir:
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
)
.
childDirectory
(
'flutter_build'
),
defines:
<
String
,
String
>{
kBuildMode:
getNameForBuildMode
(
buildMode
),
kTargetPlatform:
getNameForTargetPlatform
(
targetPlatform
),
kTargetFile:
targetFile
,
}
));
status
?.
stop
();
if
(!
result
.
success
)
{
for
(
ExceptionMeasurement
measurement
in
result
.
exceptions
.
values
)
{
printError
(
measurement
.
exception
.
toString
());
printError
(
measurement
.
stackTrace
.
toString
());
}
throwToolExit
(
'Failed to build aot.'
);
}
final
String
builtMessage
=
'Built to
$outputDir${fs.path.separator}
.'
;
if
(
quiet
)
{
printTrace
(
builtMessage
);
}
else
{
printStatus
(
builtMessage
);
}
}
}
packages/flutter_tools/lib/src/base/build.dart
View file @
d2e87a5d
...
...
@@ -94,6 +94,7 @@ class AOTSnapshotter {
DarwinArch
darwinArch
,
List
<
String
>
extraGenSnapshotOptions
=
const
<
String
>[],
@required
bool
bitcode
,
bool
quiet
=
false
,
})
async
{
if
(
bitcode
&&
platform
!=
TargetPlatform
.
ios
)
{
printError
(
'Bitcode is only supported for iOS.'
);
...
...
@@ -208,6 +209,7 @@ class AOTSnapshotter {
assemblyPath:
stripSymbols
?
'
$assembly
.stripped.S'
:
assembly
,
outputPath:
outputDir
.
path
,
bitcode:
bitcode
,
quiet:
quiet
,
);
if
(
result
.
exitCode
!=
0
)
{
return
result
.
exitCode
;
...
...
@@ -224,9 +226,12 @@ class AOTSnapshotter {
@required
String
assemblyPath
,
@required
String
outputPath
,
@required
bool
bitcode
,
@required
bool
quiet
})
async
{
final
String
targetArch
=
getNameForDarwinArch
(
appleArch
);
printStatus
(
'Building App.framework for
$targetArch
...'
);
if
(!
quiet
)
{
printStatus
(
'Building App.framework for
$targetArch
...'
);
}
final
List
<
String
>
commonBuildOptions
=
<
String
>[
'-arch'
,
targetArch
,
...
...
packages/flutter_tools/lib/src/base/file_system.dart
View file @
d2e87a5d
...
...
@@ -173,7 +173,7 @@ bool isOlderThanReference({ @required FileSystemEntity entity, @required File re
return
true
;
}
return
referenceFile
.
existsSync
()
&&
referenceFile
.
lastModifiedSync
()
.
isAfter
(
entity
.
statSync
().
modified
);
&&
referenceFile
.
statSync
().
modified
.
isAfter
(
entity
.
statSync
().
modified
);
}
/// Exception indicating that a file that was expected to exist was not found.
...
...
packages/flutter_tools/lib/src/build_system/targets/ios.dart
View file @
d2e87a5d
...
...
@@ -4,10 +4,13 @@
import
'../../artifacts.dart'
;
import
'../../base/build.dart'
;
import
'../../base/common.dart'
;
import
'../../base/file_system.dart'
;
import
'../../base/io.dart'
;
import
'../../base/process.dart'
;
import
'../../base/process_manager.dart'
;
import
'../../build_info.dart'
;
import
'../../macos/xcode.dart'
;
import
'../build_system.dart'
;
import
'../exceptions.dart'
;
import
'dart.dart'
;
...
...
@@ -22,7 +25,7 @@ abstract class AotAssemblyBase extends Target {
@override
Future
<
void
>
build
(
Environment
environment
)
async
{
final
AOTSnapshotter
snapshotter
=
AOTSnapshotter
(
reportTimings:
false
);
final
String
o
utputPath
=
environment
.
buildDir
.
path
;
final
String
buildO
utputPath
=
environment
.
buildDir
.
path
;
if
(
environment
.
defines
[
kBuildMode
]
==
null
)
{
throw
MissingDefineException
(
kBuildMode
,
'aot_assembly'
);
}
...
...
@@ -45,7 +48,7 @@ abstract class AotAssemblyBase extends Target {
buildMode:
buildMode
,
mainPath:
environment
.
buildDir
.
childFile
(
'app.dill'
).
path
,
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
outputPath:
outputP
ath
,
outputPath:
environment
.
outputDir
.
p
ath
,
darwinArch:
iosArchs
.
single
,
bitcode:
bitcode
,
);
...
...
@@ -62,7 +65,7 @@ abstract class AotAssemblyBase extends Target {
buildMode:
buildMode
,
mainPath:
environment
.
buildDir
.
childFile
(
'app.dill'
).
path
,
packagesPath:
environment
.
projectDir
.
childFile
(
'.packages'
).
path
,
outputPath:
fs
.
path
.
join
(
o
utputPath
,
getNameForDarwinArch
(
iosArch
)),
outputPath:
fs
.
path
.
join
(
buildO
utputPath
,
getNameForDarwinArch
(
iosArch
)),
darwinArch:
iosArch
,
bitcode:
bitcode
,
));
...
...
@@ -74,10 +77,10 @@ abstract class AotAssemblyBase extends Target {
final
ProcessResult
result
=
await
processManager
.
run
(<
String
>[
'lipo'
,
...
iosArchs
.
map
((
DarwinArch
iosArch
)
=>
fs
.
path
.
join
(
o
utputPath
,
getNameForDarwinArch
(
iosArch
),
'App.framework'
,
'App'
)),
fs
.
path
.
join
(
buildO
utputPath
,
getNameForDarwinArch
(
iosArch
),
'App.framework'
,
'App'
)),
'-create'
,
'-output'
,
fs
.
path
.
join
(
outputP
ath
,
'App.framework'
,
'App'
),
fs
.
path
.
join
(
environment
.
outputDir
.
p
ath
,
'App.framework'
,
'App'
),
]);
if
(
result
.
exitCode
!=
0
)
{
throw
Exception
(
'lipo exited with code
${result.exitCode}
'
);
...
...
@@ -108,7 +111,7 @@ class AotAssemblyRelease extends AotAssemblyBase {
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[
Source
.
pattern
(
'{
BUILD
_DIR}/App.framework/App'
),
Source
.
pattern
(
'{
OUTPUT
_DIR}/App.framework/App'
),
];
@override
...
...
@@ -140,7 +143,7 @@ class AotAssemblyProfile extends AotAssemblyBase {
@override
List
<
Source
>
get
outputs
=>
const
<
Source
>[
Source
.
pattern
(
'{
BUILD
_DIR}/App.framework/App'
),
Source
.
pattern
(
'{
OUTPUT
_DIR}/App.framework/App'
),
];
@override
...
...
@@ -148,3 +151,47 @@ class AotAssemblyProfile extends AotAssemblyBase {
KernelSnapshot
(),
];
}
/// Create an App.framework for debug iOS targets.
///
/// This framework needs to exist for the Xcode project to link/bundle,
/// but it isn't actually executed. To generate something valid, we compile a trivial
/// constant.
Future
<
RunResult
>
createStubAppFramework
(
Directory
appFrameworkDirectory
)
async
{
File
outputFile
;
try
{
if
(!
appFrameworkDirectory
.
existsSync
())
{
appFrameworkDirectory
.
createSync
(
recursive:
true
);
}
outputFile
=
appFrameworkDirectory
.
childFile
(
'App'
);
outputFile
.
createSync
(
recursive:
true
);
}
catch
(
e
)
{
throwToolExit
(
'Failed to create App.framework stub at
${appFrameworkDirectory.path}
'
);
}
final
Directory
tempDir
=
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_tools_stub_source.'
);
try
{
final
File
stubSource
=
tempDir
.
childFile
(
'debug_app.cc'
)
..
writeAsStringSync
(
r''
'
static const int Moo = 88;
'''
);
return
await
xcode
.
clang
(<
String
>[
'-x'
,
'c'
,
stubSource
.
path
,
'-dynamiclib'
,
'-Xlinker'
,
'-rpath'
,
'-Xlinker'
,
'@executable_path/Frameworks'
,
'-Xlinker'
,
'-rpath'
,
'-Xlinker'
,
'@loader_path/Frameworks'
,
'-install_name'
,
'@rpath/App.framework/App'
,
'-o'
,
outputFile
.
path
,
]);
}
finally
{
try
{
tempDir
.
deleteSync
(
recursive:
true
);
}
on
FileSystemException
catch
(
_
)
{
// Best effort. Sometimes we can't delete things from system temp.
}
}
}
packages/flutter_tools/lib/src/commands/build.dart
View file @
d2e87a5d
...
...
@@ -16,6 +16,7 @@ import 'build_appbundle.dart';
import
'build_bundle.dart'
;
import
'build_fuchsia.dart'
;
import
'build_ios.dart'
;
import
'build_ios_framework.dart'
;
import
'build_web.dart'
;
class
BuildCommand
extends
FlutterCommand
{
...
...
@@ -25,6 +26,7 @@ class BuildCommand extends FlutterCommand {
addSubcommand
(
BuildAppBundleCommand
(
verboseHelp:
verboseHelp
));
addSubcommand
(
BuildAotCommand
(
verboseHelp:
verboseHelp
));
addSubcommand
(
BuildIOSCommand
());
addSubcommand
(
BuildIOSFrameworkCommand
());
addSubcommand
(
BuildBundleCommand
(
verboseHelp:
verboseHelp
));
addSubcommand
(
BuildWebCommand
());
addSubcommand
(
BuildMacosCommand
(
verboseHelp:
verboseHelp
));
...
...
packages/flutter_tools/lib/src/commands/build_aar.dart
View file @
d2e87a5d
...
...
@@ -36,13 +36,13 @@ class BuildAarCommand extends BuildSubCommand {
@override
Future
<
Map
<
CustomDimensions
,
String
>>
get
usageValues
async
{
final
Map
<
CustomDimensions
,
String
>
usage
=
<
CustomDimensions
,
String
>{};
final
FlutterProject
futterProject
=
_getProject
();
if
(
futterProject
==
null
)
{
final
FlutterProject
f
l
utterProject
=
_getProject
();
if
(
f
l
utterProject
==
null
)
{
return
usage
;
}
if
(
futterProject
.
manifest
.
isModule
)
{
if
(
f
l
utterProject
.
manifest
.
isModule
)
{
usage
[
CustomDimensions
.
commandBuildAarProjectType
]
=
'module'
;
}
else
if
(
futterProject
.
manifest
.
isPlugin
)
{
}
else
if
(
f
l
utterProject
.
manifest
.
isPlugin
)
{
usage
[
CustomDimensions
.
commandBuildAarProjectType
]
=
'plugin'
;
}
else
{
usage
[
CustomDimensions
.
commandBuildAarProjectType
]
=
'app'
;
...
...
packages/flutter_tools/lib/src/commands/build_aot.dart
View file @
d2e87a5d
...
...
@@ -4,29 +4,17 @@
import
'dart:async'
;
import
'../artifacts.dart'
;
import
'../base/build.dart'
;
import
'../aot.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/process.dart'
;
import
'../base/version.dart'
;
import
'../build_info.dart'
;
import
'../build_system/build_system.dart'
;
import
'../build_system/targets/dart.dart'
;
import
'../dart/package_map.dart'
;
import
'../globals.dart'
;
import
'../ios/plist_parser.dart'
;
import
'../macos/xcode.dart'
;
import
'../project.dart'
;
import
'../ios/bitcode.dart'
;
import
'../resident_runner.dart'
;
import
'../runner/flutter_command.dart'
;
import
'build.dart'
;
/// Builds AOT snapshots into platform specific library containers.
class
BuildAotCommand
extends
BuildSubCommand
with
TargetPlatformBasedDevelopmentArtifacts
{
BuildAotCommand
({
bool
verboseHelp
=
false
})
{
BuildAotCommand
({
bool
verboseHelp
=
false
,
this
.
aotBuilder
})
{
usesTargetOption
();
addBuildModeFlags
();
usesPubOption
();
...
...
@@ -57,7 +45,7 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
hide:
true
,
)
..
addFlag
(
'bitcode'
,
defaultsTo:
false
,
defaultsTo:
kBitcodeEnabledDefault
,
help:
'Build the AOT bundle with bitcode. Requires a compatible bitcode engine.'
,
hide:
true
,
);
...
...
@@ -67,6 +55,8 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
usesTrackWidgetCreation
(
hasEffect:
false
,
verboseHelp:
verboseHelp
);
}
AotBuilder
aotBuilder
;
@override
final
String
name
=
'aot'
;
...
...
@@ -82,258 +72,21 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
if
(
platform
==
null
)
{
throwToolExit
(
'Unknown platform:
$targetPlatform
'
);
}
if
(
_canUseAssemble
(
platform
))
{
await
_buildWithAssemble
(
targetFile:
findMainDartFile
(
targetFile
),
outputDir:
outputPath
,
targetPlatform:
platform
,
buildMode:
buildMode
,
);
return
null
;
}
final
bool
bitcode
=
argResults
[
'bitcode'
];
if
(
bitcode
)
{
if
(
platform
!=
TargetPlatform
.
ios
)
{
throwToolExit
(
'Bitcode is only supported on iOS (TargetPlatform is
$targetPlatform
).'
);
}
await
validateBitcode
(
buildMode
,
platform
);
}
Status
status
;
if
(!
argResults
[
'quiet'
])
{
final
String
typeName
=
artifacts
.
getEngineType
(
platform
,
buildMode
);
status
=
logger
.
startProgress
(
'Building AOT snapshot in
${getFriendlyModeName(getBuildMode())}
mode (
$typeName
)...'
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
}
final
bool
reportTimings
=
argResults
[
'report-timings'
];
try
{
String
mainPath
=
findMainDartFile
(
targetFile
);
final
AOTSnapshotter
snapshotter
=
AOTSnapshotter
(
reportTimings:
reportTimings
);
// Compile to kernel.
mainPath
=
await
snapshotter
.
compileKernel
(
platform:
platform
,
buildMode:
buildMode
,
mainPath:
mainPath
,
packagesPath:
PackageMap
.
globalPackagesPath
,
trackWidgetCreation:
false
,
outputPath:
outputPath
,
extraFrontEndOptions:
argResults
[
FlutterOptions
.
kExtraFrontEndOptions
],
);
if
(
mainPath
==
null
)
{
throwToolExit
(
'Compiler terminated unexpectedly.'
);
return
null
;
}
// Build AOT snapshot.
if
(
platform
==
TargetPlatform
.
ios
)
{
// Determine which iOS architectures to build for.
final
Iterable
<
DarwinArch
>
buildArchs
=
argResults
[
'ios-arch'
].
map
<
DarwinArch
>(
getIOSArchForName
);
final
Map
<
DarwinArch
,
String
>
iosBuilds
=
<
DarwinArch
,
String
>{};
for
(
DarwinArch
arch
in
buildArchs
)
{
iosBuilds
[
arch
]
=
fs
.
path
.
join
(
outputPath
,
getNameForDarwinArch
(
arch
));
}
// Generate AOT snapshot and compile to arch-specific App.framework.
final
Map
<
DarwinArch
,
Future
<
int
>>
exitCodes
=
<
DarwinArch
,
Future
<
int
>>{};
iosBuilds
.
forEach
((
DarwinArch
iosArch
,
String
outputPath
)
{
exitCodes
[
iosArch
]
=
snapshotter
.
build
(
platform:
platform
,
darwinArch:
iosArch
,
buildMode:
buildMode
,
mainPath:
mainPath
,
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
bitcode:
bitcode
,
).
then
<
int
>((
int
buildExitCode
)
{
return
buildExitCode
;
});
});
// Merge arch-specific App.frameworks into a multi-arch App.framework.
if
((
await
Future
.
wait
<
int
>(
exitCodes
.
values
)).
every
((
int
buildExitCode
)
=>
buildExitCode
==
0
))
{
final
Iterable
<
String
>
dylibs
=
iosBuilds
.
values
.
map
<
String
>(
(
String
outputDir
)
=>
fs
.
path
.
join
(
outputDir
,
'App.framework'
,
'App'
));
fs
.
directory
(
fs
.
path
.
join
(
outputPath
,
'App.framework'
))..
createSync
();
await
processUtils
.
run
(
<
String
>[
'lipo'
,
...
dylibs
,
'-create'
,
'-output'
,
fs
.
path
.
join
(
outputPath
,
'App.framework'
,
'App'
),
],
throwOnError:
true
,
);
}
else
{
status
?.
cancel
();
exitCodes
.
forEach
((
DarwinArch
iosArch
,
Future
<
int
>
exitCodeFuture
)
async
{
final
int
buildExitCode
=
await
exitCodeFuture
;
printError
(
'Snapshotting (
$iosArch
) exited with non-zero exit code:
$buildExitCode
'
);
});
}
}
else
{
// Android AOT snapshot.
final
int
snapshotExitCode
=
await
snapshotter
.
build
(
platform:
platform
,
buildMode:
buildMode
,
mainPath:
mainPath
,
packagesPath:
PackageMap
.
globalPackagesPath
,
outputPath:
outputPath
,
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
bitcode:
false
,
);
if
(
snapshotExitCode
!=
0
)
{
status
?.
cancel
();
throwToolExit
(
'Snapshotting exited with non-zero exit code:
$snapshotExitCode
'
);
}
}
}
on
ProcessException
catch
(
error
)
{
// Catch the String exceptions thrown from the `runSync` methods below.
status
?.
cancel
();
printError
(
error
.
toString
());
return
null
;
}
status
?.
stop
();
if
(
outputPath
==
null
)
{
throwToolExit
(
null
);
}
final
String
builtMessage
=
'Built to
$outputPath${fs.path.separator}
.'
;
if
(
argResults
[
'quiet'
])
{
printTrace
(
builtMessage
);
}
else
{
printStatus
(
builtMessage
);
}
return
null
;
}
bool
_canUseAssemble
(
TargetPlatform
targetPlatform
)
{
if
(
argResults
.
wasParsed
(
FlutterOptions
.
kExtraFrontEndOptions
)
||
argResults
.
wasParsed
(
FlutterOptions
.
kExtraGenSnapshotOptions
))
{
return
false
;
}
switch
(
targetPlatform
)
{
case
TargetPlatform
.
android_arm
:
case
TargetPlatform
.
android_arm64
:
case
TargetPlatform
.
android_x86
:
case
TargetPlatform
.
darwin_x64
:
return
true
;
case
TargetPlatform
.
android_x64
:
case
TargetPlatform
.
ios
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia_arm64
:
case
TargetPlatform
.
fuchsia_x64
:
case
TargetPlatform
.
tester
:
case
TargetPlatform
.
web_javascript
:
default
:
return
false
;
}
}
Future
<
void
>
_buildWithAssemble
({
TargetPlatform
targetPlatform
,
BuildMode
buildMode
,
String
targetFile
,
String
outputDir
,
})
async
{
Status
status
;
if
(!
argResults
[
'quiet'
])
{
final
String
typeName
=
artifacts
.
getEngineType
(
targetPlatform
,
buildMode
);
status
=
logger
.
startProgress
(
'Building AOT snapshot in
${getFriendlyModeName(getBuildMode())}
mode (
$typeName
)...'
,
timeout:
timeoutConfiguration
.
slowOperation
,
);
}
final
FlutterProject
flutterProject
=
FlutterProject
.
current
();
// Currently this only supports android, per the check above.
final
Target
target
=
buildMode
==
BuildMode
.
profile
?
const
ProfileCopyFlutterAotBundle
()
:
const
ReleaseCopyFlutterAotBundle
();
final
BuildResult
result
=
await
buildSystem
.
build
(
target
,
Environment
(
projectDir:
flutterProject
.
directory
,
outputDir:
fs
.
directory
(
outputDir
),
buildDir:
flutterProject
.
directory
.
childDirectory
(
'.dart_tool'
)
.
childDirectory
(
'flutter_build'
),
defines:
<
String
,
String
>{
kBuildMode:
getNameForBuildMode
(
buildMode
),
kTargetPlatform:
getNameForTargetPlatform
(
targetPlatform
),
kTargetFile:
targetFile
,
}
));
status
?.
stop
();
if
(!
result
.
success
)
{
for
(
ExceptionMeasurement
measurement
in
result
.
exceptions
.
values
)
{
printError
(
measurement
.
exception
.
toString
());
printError
(
measurement
.
stackTrace
.
toString
());
}
throwToolExit
(
'Failed to build aot.'
);
}
final
String
builtMessage
=
'Built to
$outputDir${fs.path.separator}
.'
;
if
(
argResults
[
'quiet'
])
{
printTrace
(
builtMessage
);
}
else
{
printStatus
(
builtMessage
);
}
}
}
Future
<
void
>
validateBitcode
(
BuildMode
buildMode
,
TargetPlatform
targetPlatform
)
async
{
final
Artifacts
artifacts
=
Artifacts
.
instance
;
final
String
flutterFrameworkPath
=
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
mode:
buildMode
,
platform:
targetPlatform
,
);
if
(!
fs
.
isDirectorySync
(
flutterFrameworkPath
))
{
throwToolExit
(
'Flutter.framework not found at
$flutterFrameworkPath
'
);
}
final
Xcode
xcode
=
context
.
get
<
Xcode
>();
final
RunResult
clangResult
=
await
xcode
.
clang
(<
String
>[
'--version'
]);
final
String
clangVersion
=
clangResult
.
stdout
.
split
(
'
\n
'
).
first
;
final
String
engineClangVersion
=
PlistParser
.
instance
.
getValueFromFile
(
fs
.
path
.
join
(
flutterFrameworkPath
,
'Info.plist'
),
'ClangVersion'
,
);
final
Version
engineClangSemVer
=
_parseVersionFromClang
(
engineClangVersion
);
final
Version
clangSemVer
=
_parseVersionFromClang
(
clangVersion
);
if
(
engineClangSemVer
>
clangSemVer
)
{
throwToolExit
(
'The Flutter.framework at
$flutterFrameworkPath
was built '
'with "
${engineClangVersion ?? 'unknown'}
", but the current version '
'of clang is "
$clangVersion
". This will result in failures when trying to'
'archive an IPA. To resolve this issue, update your version of Xcode to '
'at least
$engineClangSemVer
.'
,
aotBuilder
??=
AotBuilder
();
await
aotBuilder
.
build
(
platform:
platform
,
outputPath:
outputPath
,
buildMode:
buildMode
,
mainDartFile:
findMainDartFile
(
targetFile
),
bitcode:
argResults
[
'bitcode'
],
quiet:
argResults
[
'quiet'
],
reportTimings:
argResults
[
'report-timings'
],
iosBuildArchs:
argResults
[
'ios-arch'
].
map
<
DarwinArch
>(
getIOSArchForName
),
extraFrontEndOptions:
argResults
[
FlutterOptions
.
kExtraFrontEndOptions
],
extraGenSnapshotOptions:
argResults
[
FlutterOptions
.
kExtraGenSnapshotOptions
],
);
return
null
;
}
}
Version
_parseVersionFromClang
(
String
clangVersion
)
{
final
RegExp
pattern
=
RegExp
(
r'Apple (LLVM|clang) version (\d+\.\d+\.\d+) '
);
void
_invalid
()
{
throwToolExit
(
'Unable to parse Clang version from "
$clangVersion
". '
'Expected a string like "Apple (LLVM|clang) #.#.# (clang-####.#.##.#)".'
);
}
if
(
clangVersion
==
null
||
clangVersion
.
isEmpty
)
{
_invalid
();
}
final
RegExpMatch
match
=
pattern
.
firstMatch
(
clangVersion
);
if
(
match
==
null
||
match
.
groupCount
!=
2
)
{
_invalid
();
}
final
Version
version
=
Version
.
parse
(
match
.
group
(
2
));
if
(
version
==
null
)
{
_invalid
();
}
return
version
;
}
packages/flutter_tools/lib/src/commands/build_ios.dart
View file @
d2e87a5d
...
...
@@ -6,6 +6,7 @@ import 'dart:async';
import
'../application_package.dart'
;
import
'../base/common.dart'
;
import
'../base/platform.dart'
;
import
'../base/utils.dart'
;
import
'../build_info.dart'
;
import
'../globals.dart'
;
...
...
@@ -13,6 +14,9 @@ import '../ios/mac.dart';
import
'../runner/flutter_command.dart'
show
DevelopmentArtifact
,
FlutterCommandResult
;
import
'build.dart'
;
/// Builds an .app for an iOS app to be used for local testing on an iOS device
/// or simulator. Can only be run on a macOS host. For producing deployment
/// .ipas, see https://flutter.dev/docs/deployment/ios.
class
BuildIOSCommand
extends
BuildSubCommand
{
BuildIOSCommand
()
{
usesTargetOption
();
...
...
@@ -59,7 +63,7 @@ class BuildIOSCommand extends BuildSubCommand {
final
bool
forSimulator
=
argResults
[
'simulator'
];
defaultBuildMode
=
forSimulator
?
BuildMode
.
debug
:
BuildMode
.
release
;
if
(
getCurrentHostPlatform
()
!=
HostPlatform
.
darwin_x64
)
{
if
(
!
platform
.
isMacOS
)
{
throwToolExit
(
'Building for iOS is only supported on the Mac.'
);
}
...
...
packages/flutter_tools/lib/src/commands/build_ios_framework.dart
0 → 100644
View file @
d2e87a5d
// Copyright 2019 The Chromium 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
'dart:async'
;
import
'package:file/file.dart'
;
import
'../aot.dart'
;
import
'../application_package.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/logger.dart'
;
import
'../base/platform.dart'
;
import
'../base/process.dart'
;
import
'../base/utils.dart'
;
import
'../build_info.dart'
;
import
'../build_system/targets/ios.dart'
;
import
'../bundle.dart'
;
import
'../globals.dart'
;
import
'../macos/cocoapod_utils.dart'
;
import
'../macos/xcode.dart'
;
import
'../plugins.dart'
;
import
'../project.dart'
;
import
'../runner/flutter_command.dart'
show
DevelopmentArtifact
,
FlutterCommandResult
;
import
'build.dart'
;
/// Produces a .framework for integration into a host iOS app. The .framework
/// contains the Flutter engine and framework code as well as plugins. It can
/// be integrated into plain Xcode projects without using or other package
/// managers.
class
BuildIOSFrameworkCommand
extends
BuildSubCommand
{
BuildIOSFrameworkCommand
({
this
.
aotBuilder
,
this
.
bundleBuilder
})
{
usesTargetOption
();
usesFlavorOption
();
usesPubOption
();
argParser
..
addFlag
(
'debug'
,
negatable:
true
,
defaultsTo:
true
,
help:
'Whether to produce a framework for the debug build configuration. '
'By default, all build configurations are built.'
)
..
addFlag
(
'profile'
,
negatable:
true
,
defaultsTo:
true
,
help:
'Whether to produce a framework for the profile build configuration. '
'By default, all build configurations are built.'
)
..
addFlag
(
'release'
,
negatable:
true
,
defaultsTo:
true
,
help:
'Whether to produce a framework for the release build configuration. '
'By default, all build configurations are built.'
)
..
addFlag
(
'universal'
,
help:
'Produce universal frameworks that include all valid architectures. '
'This is true by default.'
,
defaultsTo:
true
,
negatable:
true
)
..
addFlag
(
'xcframework'
,
help:
'Produce xcframeworks that include all valid architectures (Xcode 11 or later).'
,
)
..
addOption
(
'output'
,
abbr:
'o'
,
valueHelp:
'path/to/directory/'
,
help:
'Location to write the frameworks.'
,
);
}
AotBuilder
aotBuilder
;
BundleBuilder
bundleBuilder
;
@override
final
String
name
=
'ios-framework'
;
@override
final
String
description
=
'Produces a .framework directory for a Flutter module '
'and its plugins for integration into existing, plain Xcode projects.
\n
'
'This can only be run on macOS hosts.'
;
@override
Future
<
Set
<
DevelopmentArtifact
>>
get
requiredArtifacts
async
=>
const
<
DevelopmentArtifact
>{
DevelopmentArtifact
.
universal
,
DevelopmentArtifact
.
iOS
,
};
FlutterProject
_project
;
List
<
BuildMode
>
get
buildModes
{
final
List
<
BuildMode
>
buildModes
=
<
BuildMode
>[];
if
(
argResults
[
'debug'
])
{
buildModes
.
add
(
BuildMode
.
debug
);
}
if
(
argResults
[
'profile'
])
{
buildModes
.
add
(
BuildMode
.
profile
);
}
if
(
argResults
[
'release'
])
{
buildModes
.
add
(
BuildMode
.
release
);
}
return
buildModes
;
}
@override
Future
<
void
>
validateCommand
()
async
{
await
super
.
validateCommand
();
_project
=
FlutterProject
.
current
();
if
(!
_project
.
isModule
)
{
throwToolExit
(
'Building frameworks for iOS is only supported from a module.'
);
}
if
(!
platform
.
isMacOS
)
{
throwToolExit
(
'Building frameworks for iOS is only supported on the Mac.'
);
}
if
(!
argResults
[
'universal'
]
&&
!
argResults
[
'xcframework'
])
{
throwToolExit
(
'--universal or --xcframework is required.'
);
}
if
(
argResults
[
'xcframework'
]
&&
xcode
.
majorVersion
<
11
)
{
throwToolExit
(
'--xcframework requires Xcode 11.'
);
}
if
(
buildModes
.
isEmpty
)
{
throwToolExit
(
'At least one of "--debug" or "--profile", or "--release" is required.'
);
}
}
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
String
outputArgument
=
argResults
[
'output'
]
??
fs
.
path
.
join
(
fs
.
currentDirectory
.
path
,
'build'
,
'ios'
,
'framework'
);
if
(
outputArgument
.
isEmpty
)
{
throwToolExit
(
'--output is required.'
);
}
final
BuildableIOSApp
iosProject
=
await
applicationPackages
.
getPackageForPlatform
(
TargetPlatform
.
ios
);
if
(
iosProject
==
null
)
{
throwToolExit
(
"Module's iOS folder missing"
);
}
final
Directory
outputDirectory
=
fs
.
directory
(
fs
.
path
.
normalize
(
outputArgument
));
if
(
outputDirectory
.
existsSync
())
{
outputDirectory
.
deleteSync
(
recursive:
true
);
}
aotBuilder
??=
AotBuilder
();
bundleBuilder
??=
BundleBuilder
();
for
(
BuildMode
mode
in
buildModes
)
{
printStatus
(
'Building framework for
$iosProject
in
${getNameForBuildMode(mode)}
mode...'
);
final
String
xcodeBuildConfiguration
=
toTitleCase
(
getNameForBuildMode
(
mode
));
final
Directory
modeDirectory
=
outputDirectory
.
childDirectory
(
xcodeBuildConfiguration
);
final
Directory
iPhoneBuildOutput
=
modeDirectory
.
childDirectory
(
'iphoneos'
);
final
Directory
simulatorBuildOutput
=
modeDirectory
.
childDirectory
(
'iphonesimulator'
);
// Copy Flutter.framework.
await
_produceFlutterFramework
(
outputDirectory
,
mode
,
iPhoneBuildOutput
,
simulatorBuildOutput
,
modeDirectory
);
// Build aot, create module.framework and copy.
await
_produceAppFramework
(
mode
,
iPhoneBuildOutput
,
modeDirectory
);
// Build and copy plugins.
await
processPodsIfNeeded
(
_project
.
ios
,
getIosBuildDirectory
(),
mode
);
if
(
hasPlugins
(
_project
))
{
await
_producePlugins
(
xcodeBuildConfiguration
,
iPhoneBuildOutput
,
simulatorBuildOutput
,
modeDirectory
,
outputDirectory
);
}
final
Status
status
=
logger
.
startProgress
(
' └─Moving to
${fs.path.relative(modeDirectory.path)}
'
,
timeout:
timeoutConfiguration
.
slowOperation
);
// Delete the intermediaries since they would have been copied into our
// output frameworks.
if
(
iPhoneBuildOutput
.
existsSync
())
{
iPhoneBuildOutput
.
deleteSync
(
recursive:
true
);
}
if
(
simulatorBuildOutput
.
existsSync
())
{
simulatorBuildOutput
.
deleteSync
(
recursive:
true
);
}
status
.
stop
();
}
printStatus
(
'Frameworks written to
${outputDirectory.path}
.'
);
return
null
;
}
Future
<
void
>
_produceFlutterFramework
(
Directory
outputDirectory
,
BuildMode
mode
,
Directory
iPhoneBuildOutput
,
Directory
simulatorBuildOutput
,
Directory
modeDirectory
)
async
{
final
Status
status
=
logger
.
startProgress
(
' ├─Populating Flutter.framework...'
,
timeout:
timeoutConfiguration
.
fastOperation
);
final
String
engineCacheFlutterFrameworkDirectory
=
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
platform:
TargetPlatform
.
ios
,
mode:
mode
);
// Copy universal engine cache framework to mode directory.
final
String
flutterFrameworkFileName
=
fs
.
path
.
basename
(
engineCacheFlutterFrameworkDirectory
);
final
Directory
fatFlutterFrameworkCopy
=
modeDirectory
.
childDirectory
(
flutterFrameworkFileName
);
copyDirectorySync
(
fs
.
directory
(
engineCacheFlutterFrameworkDirectory
),
fatFlutterFrameworkCopy
);
if
(
argResults
[
'xcframework'
])
{
// Copy universal framework to variant directory.
final
Directory
armFlutterFrameworkDirectory
=
iPhoneBuildOutput
.
childDirectory
(
flutterFrameworkFileName
);
final
File
armFlutterFrameworkBinary
=
armFlutterFrameworkDirectory
.
childFile
(
'Flutter'
);
final
File
fatFlutterFrameworkBinary
=
fatFlutterFrameworkCopy
.
childFile
(
'Flutter'
);
copyDirectorySync
(
fatFlutterFrameworkCopy
,
armFlutterFrameworkDirectory
);
// Create iOS framework.
List
<
String
>
lipoCommand
=
<
String
>[
'xcrun'
,
'lipo'
,
fatFlutterFrameworkBinary
.
path
,
'-remove'
,
'x86_64'
,
'-output'
,
armFlutterFrameworkBinary
.
path
];
await
processUtils
.
run
(
lipoCommand
,
workingDirectory:
outputDirectory
.
path
,
allowReentrantFlutter:
false
,
);
// Create simulator framework.
final
Directory
simulatorFlutterFrameworkDirectory
=
simulatorBuildOutput
.
childDirectory
(
flutterFrameworkFileName
);
final
File
simulatorFlutterFrameworkBinary
=
simulatorFlutterFrameworkDirectory
.
childFile
(
'Flutter'
);
copyDirectorySync
(
fatFlutterFrameworkCopy
,
simulatorFlutterFrameworkDirectory
);
lipoCommand
=
<
String
>[
'xcrun'
,
'lipo'
,
fatFlutterFrameworkBinary
.
path
,
'-thin'
,
'x86_64'
,
'-output'
,
simulatorFlutterFrameworkBinary
.
path
];
await
processUtils
.
run
(
lipoCommand
,
workingDirectory:
outputDirectory
.
path
,
allowReentrantFlutter:
false
,
);
// Create XCFramework from iOS and simulator frameworks.
final
List
<
String
>
xcframeworkCommand
=
<
String
>[
'xcrun'
,
'xcodebuild'
,
'-create-xcframework'
,
'-framework'
,
armFlutterFrameworkDirectory
.
path
,
'-framework'
,
simulatorFlutterFrameworkDirectory
.
path
,
'-output'
,
modeDirectory
.
childFile
(
'Flutter.xcframework'
)
.
path
];
await
processUtils
.
run
(
xcframeworkCommand
,
workingDirectory:
outputDirectory
.
path
,
allowReentrantFlutter:
false
,
);
}
if
(!
argResults
[
'universal'
])
{
fatFlutterFrameworkCopy
.
deleteSync
(
recursive:
true
);
}
status
.
stop
();
}
Future
<
void
>
_produceAppFramework
(
BuildMode
mode
,
Directory
iPhoneBuildOutput
,
Directory
modeDirectory
)
async
{
const
String
appFrameworkName
=
'App.framework'
;
final
Directory
destinationAppFrameworkDirectory
=
modeDirectory
.
childDirectory
(
appFrameworkName
);
if
(
mode
==
BuildMode
.
debug
)
{
final
Status
status
=
logger
.
startProgress
(
' ├─Add placeholder App.framework for debug...'
,
timeout:
timeoutConfiguration
.
fastOperation
);
await
createStubAppFramework
(
destinationAppFrameworkDirectory
);
status
.
stop
();
}
else
{
await
_produceAotAppFrameworkIfNeeded
(
mode
,
iPhoneBuildOutput
,
destinationAppFrameworkDirectory
);
}
final
File
sourceInfoPlist
=
_project
.
ios
.
hostAppRoot
.
childDirectory
(
'Flutter'
).
childFile
(
'AppFrameworkInfo.plist'
);
final
File
destinationInfoPlist
=
destinationAppFrameworkDirectory
.
childFile
(
'Info.plist'
)..
createSync
(
recursive:
true
);
destinationInfoPlist
.
writeAsBytesSync
(
sourceInfoPlist
.
readAsBytesSync
());
final
Status
status
=
logger
.
startProgress
(
' ├─Assembling Flutter resources for App.framework...'
,
timeout:
timeoutConfiguration
.
slowOperation
);
await
bundleBuilder
.
build
(
platform:
TargetPlatform
.
ios
,
buildMode:
mode
,
// Relative paths show noise in the compiler https://github.com/dart-lang/sdk/issues/37978.
mainPath:
fs
.
path
.
absolute
(
targetFile
),
assetDirPath:
destinationAppFrameworkDirectory
.
childDirectory
(
'flutter_assets'
).
path
,
precompiledSnapshot:
mode
!=
BuildMode
.
debug
,
);
status
.
stop
();
}
Future
<
void
>
_produceAotAppFrameworkIfNeeded
(
BuildMode
mode
,
Directory
iPhoneBuildOutput
,
Directory
destinationAppFrameworkDirectory
)
async
{
if
(
mode
==
BuildMode
.
debug
)
{
return
;
}
final
Status
status
=
logger
.
startProgress
(
' ├─Building Dart AOT for App.framework...'
,
timeout:
timeoutConfiguration
.
slowOperation
);
await
aotBuilder
.
build
(
platform:
TargetPlatform
.
ios
,
outputPath:
iPhoneBuildOutput
.
path
,
buildMode:
mode
,
// Relative paths show noise in the compiler https://github.com/dart-lang/sdk/issues/37978.
mainDartFile:
fs
.
path
.
absolute
(
targetFile
),
quiet:
true
,
reportTimings:
false
,
iosBuildArchs:
<
DarwinArch
>[
DarwinArch
.
armv7
,
DarwinArch
.
arm64
],
);
const
String
appFrameworkName
=
'App.framework'
;
copyDirectorySync
(
iPhoneBuildOutput
.
childDirectory
(
appFrameworkName
),
destinationAppFrameworkDirectory
);
status
.
stop
();
}
Future
<
void
>
_producePlugins
(
String
xcodeBuildConfiguration
,
Directory
iPhoneBuildOutput
,
Directory
simulatorBuildOutput
,
Directory
modeDirectory
,
Directory
outputDirectory
,
)
async
{
final
Status
status
=
logger
.
startProgress
(
' ├─Building plugins...'
,
timeout:
timeoutConfiguration
.
slowOperation
);
List
<
String
>
pluginsBuildCommand
=
<
String
>[
'xcrun'
,
'xcodebuild'
,
'-alltargets'
,
'-sdk'
,
'iphoneos'
,
'-configuration'
,
xcodeBuildConfiguration
,
'SYMROOT=
${iPhoneBuildOutput.path}
'
,
'ONLY_ACTIVE_ARCH=NO'
// No device targeted, so build all valid architectures.
];
await
processUtils
.
run
(
pluginsBuildCommand
,
workingDirectory:
_project
.
ios
.
hostAppRoot
.
childDirectory
(
'Pods'
).
path
,
allowReentrantFlutter:
false
,
);
pluginsBuildCommand
=
<
String
>[
'xcrun'
,
'xcodebuild'
,
'-alltargets'
,
'-sdk'
,
'iphonesimulator'
,
'-configuration'
,
xcodeBuildConfiguration
,
'SYMROOT=
${simulatorBuildOutput.path}
'
,
'ARCHS=x86_64'
,
'ONLY_ACTIVE_ARCH=NO'
// No device targeted, so build all valid architectures.
];
await
processUtils
.
run
(
pluginsBuildCommand
,
workingDirectory:
_project
.
ios
.
hostAppRoot
.
childDirectory
(
'Pods'
).
path
,
allowReentrantFlutter:
false
,
);
final
Directory
iPhoneBuildConfiguration
=
iPhoneBuildOutput
.
childDirectory
(
'
$xcodeBuildConfiguration
-iphoneos'
);
final
Directory
simulatorBuildConfiguration
=
simulatorBuildOutput
.
childDirectory
(
'
$xcodeBuildConfiguration
-iphonesimulator'
);
for
(
Directory
builtProduct
in
iPhoneBuildConfiguration
.
listSync
(
followLinks:
false
).
whereType
<
Directory
>())
{
for
(
FileSystemEntity
podProduct
in
builtProduct
.
listSync
(
followLinks:
false
))
{
final
String
podFrameworkName
=
podProduct
.
basename
;
if
(
fs
.
path
.
extension
(
podFrameworkName
)
==
'.framework'
)
{
final
String
binaryName
=
fs
.
path
.
basenameWithoutExtension
(
podFrameworkName
);
if
(
argResults
[
'universal'
])
{
copyDirectorySync
(
podProduct
,
modeDirectory
.
childDirectory
(
podFrameworkName
));
final
List
<
String
>
lipoCommand
=
<
String
>[
'xcrun'
,
'lipo'
,
'-create'
,
fs
.
path
.
join
(
podProduct
.
path
,
binaryName
),
simulatorBuildConfiguration
.
childDirectory
(
binaryName
).
childDirectory
(
podFrameworkName
).
childFile
(
binaryName
).
path
,
'-output'
,
modeDirectory
.
childDirectory
(
podFrameworkName
).
childFile
(
binaryName
).
path
];
await
processUtils
.
run
(
lipoCommand
,
workingDirectory:
outputDirectory
.
path
,
allowReentrantFlutter:
false
,
);
}
if
(
argResults
[
'xcframework'
])
{
final
List
<
String
>
xcframeworkCommand
=
<
String
>[
'xcrun'
,
'xcodebuild'
,
'-create-xcframework'
,
'-framework'
,
podProduct
.
path
,
'-framework'
,
simulatorBuildConfiguration
.
childDirectory
(
binaryName
).
childDirectory
(
podFrameworkName
).
path
,
'-output'
,
modeDirectory
.
childFile
(
'
$binaryName
.xcframework'
).
path
];
await
processUtils
.
run
(
xcframeworkCommand
,
workingDirectory:
outputDirectory
.
path
,
allowReentrantFlutter:
false
,
);
}
}
}
}
status
.
stop
();
}
}
packages/flutter_tools/lib/src/ios/bitcode.dart
0 → 100644
View file @
d2e87a5d
// Copyright 2019 The Chromium 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
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/process.dart'
;
import
'../base/version.dart'
;
import
'../build_info.dart'
;
import
'../ios/plist_parser.dart'
;
import
'../macos/xcode.dart'
;
const
bool
kBitcodeEnabledDefault
=
false
;
Future
<
void
>
validateBitcode
(
BuildMode
buildMode
,
TargetPlatform
targetPlatform
)
async
{
final
Artifacts
artifacts
=
Artifacts
.
instance
;
final
String
flutterFrameworkPath
=
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
mode:
buildMode
,
platform:
targetPlatform
,
);
if
(!
fs
.
isDirectorySync
(
flutterFrameworkPath
))
{
throwToolExit
(
'Flutter.framework not found at
$flutterFrameworkPath
'
);
}
final
Xcode
xcode
=
context
.
get
<
Xcode
>();
final
RunResult
clangResult
=
await
xcode
.
clang
(<
String
>[
'--version'
]);
final
String
clangVersion
=
clangResult
.
stdout
.
split
(
'
\n
'
).
first
;
final
String
engineClangVersion
=
PlistParser
.
instance
.
getValueFromFile
(
fs
.
path
.
join
(
flutterFrameworkPath
,
'Info.plist'
),
'ClangVersion'
,
);
final
Version
engineClangSemVer
=
_parseVersionFromClang
(
engineClangVersion
);
final
Version
clangSemVer
=
_parseVersionFromClang
(
clangVersion
);
if
(
engineClangSemVer
>
clangSemVer
)
{
throwToolExit
(
'The Flutter.framework at
$flutterFrameworkPath
was built '
'with "
${engineClangVersion ?? 'unknown'}
", but the current version '
'of clang is "
$clangVersion
". This will result in failures when trying to'
'archive an IPA. To resolve this issue, update your version of Xcode to '
'at least
$engineClangSemVer
.'
,
);
}
}
Version
_parseVersionFromClang
(
String
clangVersion
)
{
final
RegExp
pattern
=
RegExp
(
r'Apple (LLVM|clang) version (\d+\.\d+\.\d+) '
);
void
_invalid
()
{
throwToolExit
(
'Unable to parse Clang version from "
$clangVersion
". '
'Expected a string like "Apple (LLVM|clang) #.#.# (clang-####.#.##.#)".'
);
}
if
(
clangVersion
==
null
||
clangVersion
.
isEmpty
)
{
_invalid
();
}
final
RegExpMatch
match
=
pattern
.
firstMatch
(
clangVersion
);
if
(
match
==
null
||
match
.
groupCount
!=
2
)
{
_invalid
();
}
final
Version
version
=
Version
.
parse
(
match
.
group
(
2
));
if
(
version
==
null
)
{
_invalid
();
}
return
version
;
}
packages/flutter_tools/test/general.shard/commands/build_aot_test.dart
View file @
d2e87a5d
...
...
@@ -7,8 +7,8 @@ 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/build_info.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/bitcode.dart'
;
import
'package:flutter_tools/src/ios/plist_parser.dart'
;
import
'package:flutter_tools/src/macos/xcode.dart'
;
import
'package:mockito/mockito.dart'
;
...
...
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