Unverified Commit 15c591a1 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Split out XcodeProjectInterpreter from xcode_build_settings (#80399)

parent 3eeadc28
......@@ -30,6 +30,7 @@ import 'migrations/project_base_configuration_migration.dart';
import 'migrations/project_build_location_migration.dart';
import 'migrations/remove_framework_link_and_embedding_migration.dart';
import 'migrations/xcode_build_system_migration.dart';
import 'xcode_build_settings.dart';
import 'xcodeproj.dart';
class IMobileDevice {
......
// Copyright 2014 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.
// @dart = 2.8
import 'package:meta/meta.dart';
import '../artifacts.dart';
import '../base/file_system.dart';
import '../build_info.dart';
import '../cache.dart';
import '../flutter_manifest.dart';
import '../globals.dart' as globals;
import '../project.dart';
String flutterMacOSFrameworkDir(BuildMode mode, FileSystem fileSystem,
Artifacts artifacts) {
final String flutterMacOSFramework = artifacts.getArtifactPath(
Artifact.flutterMacOSFramework,
platform: TargetPlatform.darwin_x64,
mode: mode,
);
return fileSystem.path
.normalize(fileSystem.path.dirname(flutterMacOSFramework));
}
/// Writes or rewrites Xcode property files with the specified information.
///
/// useMacOSConfig: Optional parameter that controls whether we use the macOS
/// project file instead. Defaults to false.
///
/// setSymroot: Optional parameter to control whether to set SYMROOT.
///
/// targetOverride: Optional parameter, if null or unspecified the default value
/// from xcode_backend.sh is used 'lib/main.dart'.
Future<void> updateGeneratedXcodeProperties({
@required FlutterProject project,
@required BuildInfo buildInfo,
String targetOverride,
bool useMacOSConfig = false,
bool setSymroot = true,
String buildDirOverride,
}) async {
final List<String> xcodeBuildSettings = _xcodeBuildSettingsLines(
project: project,
buildInfo: buildInfo,
targetOverride: targetOverride,
useMacOSConfig: useMacOSConfig,
setSymroot: setSymroot,
buildDirOverride: buildDirOverride,
);
_updateGeneratedXcodePropertiesFile(
project: project,
xcodeBuildSettings: xcodeBuildSettings,
useMacOSConfig: useMacOSConfig,
);
_updateGeneratedEnvironmentVariablesScript(
project: project,
xcodeBuildSettings: xcodeBuildSettings,
useMacOSConfig: useMacOSConfig,
);
}
/// Generate a xcconfig file to inherit FLUTTER_ build settings
/// for Xcode targets that need them.
/// See [XcodeBasedProject.generatedXcodePropertiesFile].
void _updateGeneratedXcodePropertiesFile({
@required FlutterProject project,
@required List<String> xcodeBuildSettings,
bool useMacOSConfig = false,
}) {
final StringBuffer localsBuffer = StringBuffer();
localsBuffer.writeln('// This is a generated file; do not edit or check into version control.');
xcodeBuildSettings.forEach(localsBuffer.writeln);
final File generatedXcodePropertiesFile = useMacOSConfig
? project.macos.generatedXcodePropertiesFile
: project.ios.generatedXcodePropertiesFile;
generatedXcodePropertiesFile.createSync(recursive: true);
generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
}
/// Generate a script to export all the FLUTTER_ environment variables needed
/// as flags for Flutter tools.
/// See [XcodeBasedProject.generatedEnvironmentVariableExportScript].
void _updateGeneratedEnvironmentVariablesScript({
@required FlutterProject project,
@required List<String> xcodeBuildSettings,
bool useMacOSConfig = false,
}) {
final StringBuffer localsBuffer = StringBuffer();
localsBuffer.writeln('#!/bin/sh');
localsBuffer.writeln('# This is a generated file; do not edit or check into version control.');
for (final String line in xcodeBuildSettings) {
if (!line.contains('[')) { // Exported conditional Xcode build settings do not work.
localsBuffer.writeln('export "$line"');
}
}
final File generatedModuleBuildPhaseScript = useMacOSConfig
? project.macos.generatedEnvironmentVariableExportScript
: project.ios.generatedEnvironmentVariableExportScript;
generatedModuleBuildPhaseScript.createSync(recursive: true);
generatedModuleBuildPhaseScript.writeAsStringSync(localsBuffer.toString());
globals.os.chmod(generatedModuleBuildPhaseScript, '755');
}
/// Build name parsed and validated from build info and manifest. Used for CFBundleShortVersionString.
String parsedBuildName({
@required FlutterManifest manifest,
@required BuildInfo buildInfo,
}) {
final String buildNameToParse = buildInfo?.buildName ?? manifest.buildName;
return validatedBuildNameForPlatform(TargetPlatform.ios, buildNameToParse, globals.logger);
}
/// Build number parsed and validated from build info and manifest. Used for CFBundleVersion.
String parsedBuildNumber({
@required FlutterManifest manifest,
@required BuildInfo buildInfo,
}) {
String buildNumberToParse = buildInfo?.buildNumber ?? manifest.buildNumber;
final String buildNumber = validatedBuildNumberForPlatform(
TargetPlatform.ios,
buildNumberToParse,
globals.logger,
);
if (buildNumber != null && buildNumber.isNotEmpty) {
return buildNumber;
}
// Drop back to parsing build name if build number is not present. Build number is optional in the manifest, but
// FLUTTER_BUILD_NUMBER is required as the backing value for the required CFBundleVersion.
buildNumberToParse = buildInfo?.buildName ?? manifest.buildName;
return validatedBuildNumberForPlatform(
TargetPlatform.ios,
buildNumberToParse,
globals.logger,
);
}
/// List of lines of build settings. Example: 'FLUTTER_BUILD_DIR=build'
List<String> _xcodeBuildSettingsLines({
@required FlutterProject project,
@required BuildInfo buildInfo,
String targetOverride,
bool useMacOSConfig = false,
bool setSymroot = true,
String buildDirOverride,
}) {
final List<String> xcodeBuildSettings = <String>[];
final String flutterRoot = globals.fs.path.normalize(Cache.flutterRoot);
xcodeBuildSettings.add('FLUTTER_ROOT=$flutterRoot');
// This holds because requiresProjectRoot is true for this command
xcodeBuildSettings.add('FLUTTER_APPLICATION_PATH=${globals.fs.path.normalize(project.directory.path)}');
// Tell CocoaPods behavior to codesign in parallel with rest of scripts to speed it up.
// Value must be "true", not "YES". https://github.com/CocoaPods/CocoaPods/pull/6088
xcodeBuildSettings.add('COCOAPODS_PARALLEL_CODE_SIGN=true');
// Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current].
if (targetOverride != null) {
xcodeBuildSettings.add('FLUTTER_TARGET=$targetOverride');
}
// The build outputs directory, relative to FLUTTER_APPLICATION_PATH.
xcodeBuildSettings.add('FLUTTER_BUILD_DIR=${buildDirOverride ?? getBuildDirectory()}');
if (setSymroot) {
xcodeBuildSettings.add('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
}
final String buildName = parsedBuildName(manifest: project.manifest, buildInfo: buildInfo) ?? '1.0.0';
xcodeBuildSettings.add('FLUTTER_BUILD_NAME=$buildName');
final String buildNumber = parsedBuildNumber(manifest: project.manifest, buildInfo: buildInfo) ?? '1';
xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber');
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts;
final String engineOutPath = localEngineArtifacts.engineOutPath;
xcodeBuildSettings.add('FLUTTER_ENGINE=${globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath))}');
final String localEngineName = globals.fs.path.basename(engineOutPath);
xcodeBuildSettings.add('LOCAL_ENGINE=$localEngineName');
// Tell Xcode not to build universal binaries for local engines, which are
// single-architecture.
//
// NOTE: this assumes that local engine binary paths are consistent with
// the conventions uses in the engine: 32-bit iOS engines are built to
// paths ending in _arm, 64-bit builds are not.
//
// Skip this step for macOS builds.
if (!useMacOSConfig) {
String arch;
if (localEngineName.endsWith('_arm')) {
arch = 'armv7';
} else if (localEngineName.contains('_sim')) {
// Apple Silicon ARM simulators not yet supported.
arch = 'x86_64';
} else {
arch = 'arm64';
}
xcodeBuildSettings.add('ARCHS=$arch');
}
}
if (useMacOSConfig) {
// ARM not yet supported https://github.com/flutter/flutter/issues/69221
xcodeBuildSettings.add('EXCLUDED_ARCHS=arm64');
} else {
// Apple Silicon ARM simulators not yet supported.
xcodeBuildSettings.add('EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64 i386');
}
for (final MapEntry<String, String> config in buildInfo.toEnvironmentConfig().entries) {
xcodeBuildSettings.add('${config.key}=${config.value}');
}
return xcodeBuildSettings;
}
......@@ -8,7 +8,6 @@ import 'package:file/memory.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
......@@ -19,226 +18,11 @@ import '../base/process.dart';
import '../base/terminal.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
import '../flutter_manifest.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
final RegExp _settingExpr = RegExp(r'(\w+)\s*=\s*(.*)$');
final RegExp _varExpr = RegExp(r'\$\(([^)]*)\)');
String flutterMacOSFrameworkDir(BuildMode mode, FileSystem fileSystem,
Artifacts artifacts) {
final String flutterMacOSFramework = artifacts.getArtifactPath(
Artifact.flutterMacOSFramework,
platform: TargetPlatform.darwin_x64,
mode: mode,
);
return fileSystem.path
.normalize(fileSystem.path.dirname(flutterMacOSFramework));
}
/// Writes or rewrites Xcode property files with the specified information.
///
/// useMacOSConfig: Optional parameter that controls whether we use the macOS
/// project file instead. Defaults to false.
///
/// setSymroot: Optional parameter to control whether to set SYMROOT.
///
/// targetOverride: Optional parameter, if null or unspecified the default value
/// from xcode_backend.sh is used 'lib/main.dart'.
Future<void> updateGeneratedXcodeProperties({
@required FlutterProject project,
@required BuildInfo buildInfo,
String targetOverride,
bool useMacOSConfig = false,
bool setSymroot = true,
String buildDirOverride,
}) async {
final List<String> xcodeBuildSettings = _xcodeBuildSettingsLines(
project: project,
buildInfo: buildInfo,
targetOverride: targetOverride,
useMacOSConfig: useMacOSConfig,
setSymroot: setSymroot,
buildDirOverride: buildDirOverride,
);
_updateGeneratedXcodePropertiesFile(
project: project,
xcodeBuildSettings: xcodeBuildSettings,
useMacOSConfig: useMacOSConfig,
);
_updateGeneratedEnvironmentVariablesScript(
project: project,
xcodeBuildSettings: xcodeBuildSettings,
useMacOSConfig: useMacOSConfig,
);
}
/// Generate a xcconfig file to inherit FLUTTER_ build settings
/// for Xcode targets that need them.
/// See [XcodeBasedProject.generatedXcodePropertiesFile].
void _updateGeneratedXcodePropertiesFile({
@required FlutterProject project,
@required List<String> xcodeBuildSettings,
bool useMacOSConfig = false,
}) {
final StringBuffer localsBuffer = StringBuffer();
localsBuffer.writeln('// This is a generated file; do not edit or check into version control.');
xcodeBuildSettings.forEach(localsBuffer.writeln);
final File generatedXcodePropertiesFile = useMacOSConfig
? project.macos.generatedXcodePropertiesFile
: project.ios.generatedXcodePropertiesFile;
generatedXcodePropertiesFile.createSync(recursive: true);
generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
}
/// Generate a script to export all the FLUTTER_ environment variables needed
/// as flags for Flutter tools.
/// See [XcodeBasedProject.generatedEnvironmentVariableExportScript].
void _updateGeneratedEnvironmentVariablesScript({
@required FlutterProject project,
@required List<String> xcodeBuildSettings,
bool useMacOSConfig = false,
}) {
final StringBuffer localsBuffer = StringBuffer();
localsBuffer.writeln('#!/bin/sh');
localsBuffer.writeln('# This is a generated file; do not edit or check into version control.');
for (final String line in xcodeBuildSettings) {
if (!line.contains('[')) { // Exported conditional Xcode build settings do not work.
localsBuffer.writeln('export "$line"');
}
}
final File generatedModuleBuildPhaseScript = useMacOSConfig
? project.macos.generatedEnvironmentVariableExportScript
: project.ios.generatedEnvironmentVariableExportScript;
generatedModuleBuildPhaseScript.createSync(recursive: true);
generatedModuleBuildPhaseScript.writeAsStringSync(localsBuffer.toString());
globals.os.chmod(generatedModuleBuildPhaseScript, '755');
}
/// Build name parsed and validated from build info and manifest. Used for CFBundleShortVersionString.
String parsedBuildName({
@required FlutterManifest manifest,
@required BuildInfo buildInfo,
}) {
final String buildNameToParse = buildInfo?.buildName ?? manifest.buildName;
return validatedBuildNameForPlatform(TargetPlatform.ios, buildNameToParse, globals.logger);
}
/// Build number parsed and validated from build info and manifest. Used for CFBundleVersion.
String parsedBuildNumber({
@required FlutterManifest manifest,
@required BuildInfo buildInfo,
}) {
String buildNumberToParse = buildInfo?.buildNumber ?? manifest.buildNumber;
final String buildNumber = validatedBuildNumberForPlatform(
TargetPlatform.ios,
buildNumberToParse,
globals.logger,
);
if (buildNumber != null && buildNumber.isNotEmpty) {
return buildNumber;
}
// Drop back to parsing build name if build number is not present. Build number is optional in the manifest, but
// FLUTTER_BUILD_NUMBER is required as the backing value for the required CFBundleVersion.
buildNumberToParse = buildInfo?.buildName ?? manifest.buildName;
return validatedBuildNumberForPlatform(
TargetPlatform.ios,
buildNumberToParse,
globals.logger,
);
}
/// List of lines of build settings. Example: 'FLUTTER_BUILD_DIR=build'
List<String> _xcodeBuildSettingsLines({
@required FlutterProject project,
@required BuildInfo buildInfo,
String targetOverride,
bool useMacOSConfig = false,
bool setSymroot = true,
String buildDirOverride,
}) {
final List<String> xcodeBuildSettings = <String>[];
final String flutterRoot = globals.fs.path.normalize(Cache.flutterRoot);
xcodeBuildSettings.add('FLUTTER_ROOT=$flutterRoot');
// This holds because requiresProjectRoot is true for this command
xcodeBuildSettings.add('FLUTTER_APPLICATION_PATH=${globals.fs.path.normalize(project.directory.path)}');
// Tell CocoaPods behavior to codesign in parallel with rest of scripts to speed it up.
// Value must be "true", not "YES". https://github.com/CocoaPods/CocoaPods/pull/6088
xcodeBuildSettings.add('COCOAPODS_PARALLEL_CODE_SIGN=true');
// Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current].
if (targetOverride != null) {
xcodeBuildSettings.add('FLUTTER_TARGET=$targetOverride');
}
// The build outputs directory, relative to FLUTTER_APPLICATION_PATH.
xcodeBuildSettings.add('FLUTTER_BUILD_DIR=${buildDirOverride ?? getBuildDirectory()}');
if (setSymroot) {
xcodeBuildSettings.add('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
}
final String buildName = parsedBuildName(manifest: project.manifest, buildInfo: buildInfo) ?? '1.0.0';
xcodeBuildSettings.add('FLUTTER_BUILD_NAME=$buildName');
final String buildNumber = parsedBuildNumber(manifest: project.manifest, buildInfo: buildInfo) ?? '1';
xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber');
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts;
final String engineOutPath = localEngineArtifacts.engineOutPath;
xcodeBuildSettings.add('FLUTTER_ENGINE=${globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath))}');
final String localEngineName = globals.fs.path.basename(engineOutPath);
xcodeBuildSettings.add('LOCAL_ENGINE=$localEngineName');
// Tell Xcode not to build universal binaries for local engines, which are
// single-architecture.
//
// NOTE: this assumes that local engine binary paths are consistent with
// the conventions uses in the engine: 32-bit iOS engines are built to
// paths ending in _arm, 64-bit builds are not.
//
// Skip this step for macOS builds.
if (!useMacOSConfig) {
String arch;
if (localEngineName.endsWith('_arm')) {
arch = 'armv7';
} else if (localEngineName.contains('_sim')) {
// Apple Silicon ARM simulators not yet supported.
arch = 'x86_64';
} else {
arch = 'arm64';
}
xcodeBuildSettings.add('ARCHS=$arch');
}
}
if (useMacOSConfig) {
// ARM not yet supported https://github.com/flutter/flutter/issues/69221
xcodeBuildSettings.add('EXCLUDED_ARCHS=arm64');
} else {
// Apple Silicon ARM simulators not yet supported.
xcodeBuildSettings.add('EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64 i386');
}
for (final MapEntry<String, String> config in buildInfo.toEnvironmentConfig().entries) {
xcodeBuildSettings.add('${config.key}=${config.value}');
}
return xcodeBuildSettings;
}
/// Interpreter of Xcode projects.
class XcodeProjectInterpreter {
factory XcodeProjectInterpreter({
......
......@@ -14,6 +14,7 @@ import '../base/project_migrator.dart';
import '../build_info.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import '../ios/xcode_build_settings.dart';
import '../ios/xcodeproj.dart';
import '../project.dart';
import 'cocoapod_utils.dart';
......
......@@ -21,7 +21,7 @@ import 'flutter_manifest.dart';
import 'flutter_plugins.dart';
import 'globals.dart' as globals;
import 'ios/plist_parser.dart';
import 'ios/xcodeproj.dart' as xcode;
import 'ios/xcode_build_settings.dart' as xcode;
import 'ios/xcodeproj.dart';
import 'platform_plugins.dart';
import 'template.dart';
......@@ -544,7 +544,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
if (allBuildSettings != null) {
if (fromPlist != null) {
// Perform variable substitution using build settings.
return xcode.substituteXcodeVariables(fromPlist, allBuildSettings);
return substituteXcodeVariables(fromPlist, allBuildSettings);
}
return allBuildSettings['PRODUCT_BUNDLE_IDENTIFIER'];
}
......
......@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/ios/xcode_build_settings.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment