cmake.dart 4.42 KB
Newer Older
1 2 3 4
// 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.

5 6 7
import 'package:pub_semver/pub_semver.dart';

import 'build_info.dart';
8
import 'cmake_project.dart';
9
import 'globals.dart' as globals;
10

11
/// Extracts the `BINARY_NAME` from a project's CMake file.
12 13
///
/// Returns `null` if it cannot be found.
14
String? getCmakeExecutableName(CmakeBasedProject project) {
15 16 17 18 19
  if (!project.cmakeFile.existsSync()) {
    return null;
  }
  final RegExp nameSetPattern = RegExp(r'^\s*set\(BINARY_NAME\s*"(.*)"\s*\)\s*$');
  for (final String line in project.cmakeFile.readAsLinesSync()) {
20
    final RegExpMatch? match = nameSetPattern.firstMatch(line);
21 22 23 24 25 26 27
    if (match != null) {
      return match.group(1);
    }
  }
  return null;
}

28 29 30 31
String _escapeBackslashes(String s) {
  return s.replaceAll(r'\', r'\\');
}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
String _determineVersionString(CmakeBasedProject project, BuildInfo buildInfo) {
  // Prefer the build arguments for version information.
  final String buildName = buildInfo.buildName ?? project.parent.manifest.buildName ?? '1.0.0';
  final String? buildNumber = buildInfo.buildName != null
    ? buildInfo.buildNumber
    : (buildInfo.buildNumber ?? project.parent.manifest.buildNumber);

  return buildNumber != null
    ? '$buildName+$buildNumber'
    : buildName;
}

Version _determineVersion(CmakeBasedProject project, BuildInfo buildInfo) {
  final String version = _determineVersionString(project, buildInfo);
  try {
    return Version.parse(version);
  } on FormatException {
    globals.printWarning('Warning: could not parse version $version, defaulting to 1.0.0.');

    return Version(1, 0, 0);
  }
}

/// Attempts to map a Dart version's build identifier (the part after a +) into
/// a single integer. Returns null for complex build identifiers like `foo` or `1.2`.
int? _tryDetermineBuildVersion(Version version) {
  if (version.build.isEmpty) {
    return 0;
  }

  if (version.build.length != 1) {
    return null;
  }

  final Object buildIdentifier = version.build.first as Object;
  return buildIdentifier is int ? buildIdentifier : null;
}

70 71 72
/// Writes a generated CMake configuration file for [project], including
/// variables expected by the build template and an environment variable list
/// for calling back into Flutter.
73 74 75 76 77
void writeGeneratedCmakeConfig(
  String flutterRoot,
  CmakeBasedProject project,
  BuildInfo buildInfo,
  Map<String, String> environment) {
78 79
  // Only a limited set of variables are needed by the CMake files themselves,
  // the rest are put into a list to pass to the re-entrant build step.
80 81
  final String escapedFlutterRoot = _escapeBackslashes(flutterRoot);
  final String escapedProjectDir = _escapeBackslashes(project.parent.directory.path);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

  final Version version = _determineVersion(project, buildInfo);
  final int? buildVersion = _tryDetermineBuildVersion(version);

  // Since complex Dart build identifiers cannot be converted into integers,
  // different Dart versions may be converted into the same Windows numeric version.
  // Warn the user as some Windows installers, like MSI, don't update files if their versions are equal.
  if (buildVersion == null && project is WindowsProject) {
      final String buildIdentifier = version.build.join('.');
      globals.printWarning(
        'Warning: build identifier $buildIdentifier in version $version is not numeric '
        'and cannot be converted into a Windows build version number. Defaulting to 0.\n'
        'This may cause issues with Windows installers.'
      );
  }

98 99
  final StringBuffer buffer = StringBuffer('''
# Generated code do not commit.
100 101
file(TO_CMAKE_PATH "$escapedFlutterRoot" FLUTTER_ROOT)
file(TO_CMAKE_PATH "$escapedProjectDir" PROJECT_DIR)
102

103 104 105 106 107 108
set(FLUTTER_VERSION "$version" PARENT_SCOPE)
set(FLUTTER_VERSION_MAJOR ${version.major} PARENT_SCOPE)
set(FLUTTER_VERSION_MINOR ${version.minor} PARENT_SCOPE)
set(FLUTTER_VERSION_PATCH ${version.patch} PARENT_SCOPE)
set(FLUTTER_VERSION_BUILD ${buildVersion ?? 0} PARENT_SCOPE)

109 110
# Environment variables to pass to tool_backend.sh
list(APPEND FLUTTER_TOOL_ENVIRONMENT
111 112
  "FLUTTER_ROOT=$escapedFlutterRoot"
  "PROJECT_DIR=$escapedProjectDir"
113
''');
114 115 116 117
  environment.forEach((String key, String value) {
    final String configValue = _escapeBackslashes(value);
    buffer.writeln('  "$key=$configValue"');
  });
118 119 120 121 122 123
  buffer.writeln(')');

  project.generatedCmakeConfigFile
    ..createSync(recursive: true)
    ..writeAsStringSync(buffer.toString());
}