blob: a18fd1b2a8b87fd754ea6a8e0728fdec86e283fc [file] [log] [blame]
// 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.
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../globals.dart' as globals;
import '../ios/xcodeproj.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import 'cocoapod_utils.dart';
/// Builds the macOS project through xcodebuild.
// TODO(jonahwilliams): refactor to share code with the existing iOS code.
Future<void> buildMacOS({
FlutterProject flutterProject,
BuildInfo buildInfo,
String targetOverride,
}) async {
if (!flutterProject.macos.xcodeWorkspace.existsSync()) {
throwToolExit('No macOS desktop project configured. '
'See '
'to learn about adding macOS support to a project.');
final Directory flutterBuildDir =;
if (!flutterBuildDir.existsSync()) {
flutterBuildDir.createSync(recursive: true);
// Write configuration to an xconfig file in a standard location.
await updateGeneratedXcodeProperties(
project: flutterProject,
buildInfo: buildInfo,
targetOverride: targetOverride,
useMacOSConfig: true,
setSymroot: false,
await processPodsIfNeeded(flutterProject.macos, getMacOSBuildDirectory(), buildInfo.mode);
// If the xcfilelists do not exist, create empty version.
if (!flutterProject.macos.inputFileList.existsSync()) {
flutterProject.macos.inputFileList.createSync(recursive: true);
if (!flutterProject.macos.outputFileList.existsSync()) {
flutterProject.macos.outputFileList.createSync(recursive: true);
final Directory xcodeProject = flutterProject.macos.xcodeProject;
// If the standard project exists, specify it to getInfo to handle the case where there are
// other Xcode projects in the macos/ directory. Otherwise pass no name, which will work
// regardless of the project name so long as there is exactly one project.
final String xcodeProjectName = xcodeProject.existsSync() ? xcodeProject.basename : null;
final XcodeProjectInfo projectInfo = await xcodeProjectInterpreter.getInfo(
projectFilename: xcodeProjectName,
final String scheme = projectInfo.schemeFor(buildInfo);
if (scheme == null) {
throwToolExit('Unable to find expected scheme in Xcode project.');
final String configuration = projectInfo.buildConfigurationFor(buildInfo, scheme);
if (configuration == null) {
throwToolExit('Unable to find expected configuration in Xcode project.');
// Run the Xcode build.
final Stopwatch sw = Stopwatch()..start();
final Status status = globals.logger.startProgress(
'Building macOS application...',
timeout: null,
int result;
try {
result = await<String>[
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-configuration', '$configuration',
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
'OBJROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}',
'SYMROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}',
], trace: true);
} finally {
if (result != 0) {
throwToolExit('Build process failed');
flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));