1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:pub_semver/pub_semver.dart' ; |
6 | |
7 | import 'base/logger.dart'; |
8 | import 'build_info.dart'; |
9 | import 'cmake_project.dart'; |
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 | if (!project.cmakeFile.existsSync()) { |
16 | return null; |
17 | } |
18 | final RegExp nameSetPattern = RegExp(r'^\s*set\(BINARY_NAME\s*"(.*)"\s*\)\s*$' ); |
19 | for (final String line in project.cmakeFile.readAsLinesSync()) { |
20 | final RegExpMatch? match = nameSetPattern.firstMatch(line); |
21 | if (match != null) { |
22 | return match.group(1); |
23 | } |
24 | } |
25 | return null; |
26 | } |
27 | |
28 | String _escapeBackslashes(String s) { |
29 | return s.replaceAll(r'\' , r'\\' ); |
30 | } |
31 | |
32 | String _determineVersionString(CmakeBasedProject project, BuildInfo buildInfo) { |
33 | // Prefer the build arguments for version information. |
34 | final String buildName = buildInfo.buildName ?? project.parent.manifest.buildName ?? '1.0.0' ; |
35 | final String? buildNumber = |
36 | buildInfo.buildName != null |
37 | ? buildInfo.buildNumber |
38 | : (buildInfo.buildNumber ?? project.parent.manifest.buildNumber); |
39 | |
40 | return buildNumber != null ? ' $buildName+ $buildNumber' : buildName; |
41 | } |
42 | |
43 | Version _determineVersion(CmakeBasedProject project, BuildInfo buildInfo, Logger logger) { |
44 | final String version = _determineVersionString(project, buildInfo); |
45 | try { |
46 | return Version.parse(version); |
47 | } on FormatException { |
48 | logger.printWarning('Warning: could not parse version $version, defaulting to 1.0.0.' ); |
49 | |
50 | return Version(1, 0, 0); |
51 | } |
52 | } |
53 | |
54 | /// Attempts to map a Dart version's build identifier (the part after a +) into |
55 | /// a single integer. Returns null for complex build identifiers like `foo` or `1.2`. |
56 | int? _tryDetermineBuildVersion(Version version) { |
57 | if (version.build.isEmpty) { |
58 | return 0; |
59 | } |
60 | |
61 | if (version.build.length != 1) { |
62 | return null; |
63 | } |
64 | |
65 | final Object buildIdentifier = version.build.first; |
66 | return buildIdentifier is int ? buildIdentifier : null; |
67 | } |
68 | |
69 | /// Writes a generated CMake configuration file for [project], including |
70 | /// variables expected by the build template and an environment variable list |
71 | /// for calling back into Flutter. |
72 | void writeGeneratedCmakeConfig( |
73 | String flutterRoot, |
74 | CmakeBasedProject project, |
75 | BuildInfo buildInfo, |
76 | Map<String, String> environment, |
77 | Logger logger, |
78 | ) { |
79 | // Only a limited set of variables are needed by the CMake files themselves, |
80 | // the rest are put into a list to pass to the re-entrant build step. |
81 | final String escapedFlutterRoot = _escapeBackslashes(flutterRoot); |
82 | final String escapedProjectDir = _escapeBackslashes(project.parent.directory.path); |
83 | |
84 | final Version version = _determineVersion(project, buildInfo, logger); |
85 | final int? buildVersion = _tryDetermineBuildVersion(version); |
86 | |
87 | // Since complex Dart build identifiers cannot be converted into integers, |
88 | // different Dart versions may be converted into the same Windows numeric version. |
89 | // Warn the user as some Windows installers, like MSI, don't update files if their versions are equal. |
90 | if (buildVersion == null && project is WindowsProject) { |
91 | final String buildIdentifier = version.build.join('.' ); |
92 | logger.printWarning( |
93 | 'Warning: build identifier $buildIdentifier in version $version is not numeric ' |
94 | 'and cannot be converted into a Windows build version number. Defaulting to 0.\n' |
95 | 'This may cause issues with Windows installers.' , |
96 | ); |
97 | } |
98 | |
99 | final StringBuffer buffer = StringBuffer(''' |
100 | # Generated code do not commit. |
101 | file(TO_CMAKE_PATH " $escapedFlutterRoot" FLUTTER_ROOT) |
102 | file(TO_CMAKE_PATH " $escapedProjectDir" PROJECT_DIR) |
103 | |
104 | set(FLUTTER_VERSION " $version" PARENT_SCOPE) |
105 | set(FLUTTER_VERSION_MAJOR ${version.major} PARENT_SCOPE) |
106 | set(FLUTTER_VERSION_MINOR ${version.minor} PARENT_SCOPE) |
107 | set(FLUTTER_VERSION_PATCH ${version.patch} PARENT_SCOPE) |
108 | set(FLUTTER_VERSION_BUILD ${buildVersion ?? 0} PARENT_SCOPE) |
109 | |
110 | # Environment variables to pass to tool_backend.sh |
111 | list(APPEND FLUTTER_TOOL_ENVIRONMENT |
112 | "FLUTTER_ROOT= $escapedFlutterRoot" |
113 | "PROJECT_DIR= $escapedProjectDir" |
114 | ''' ); |
115 | environment.forEach((String key, String value) { |
116 | final String configValue = _escapeBackslashes(value); |
117 | buffer.writeln(' " $key= $configValue"' ); |
118 | }); |
119 | buffer.writeln(')' ); |
120 | |
121 | project.generatedCmakeConfigFile |
122 | ..createSync(recursive: true) |
123 | ..writeAsStringSync(buffer.toString()); |
124 | } |
125 | |