Work around VS CMake generation bug (#98945)
This commit is contained in:
parent
35df3aa439
commit
80660b2d5e
@ -74,6 +74,9 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
|
||||
buildDir: buildDirectory,
|
||||
sourceDir: windowsProject.cmakeFile.parent,
|
||||
);
|
||||
if (visualStudio.displayVersion == '17.1.0') {
|
||||
_fixBrokenCmakeGeneration(buildDirectory);
|
||||
}
|
||||
await _runBuild(cmakePath, buildDirectory, buildModeName);
|
||||
} finally {
|
||||
status.cancel();
|
||||
@ -335,3 +338,55 @@ void _writeGeneratedFlutterConfig(
|
||||
}
|
||||
writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, environment);
|
||||
}
|
||||
|
||||
// Works around the Visual Studio 17.1.0 CMake bug described in
|
||||
// https://github.com/flutter/flutter/issues/97086
|
||||
//
|
||||
// Rather than attempt to remove all the duplicate entries within the
|
||||
// <CustomBuild> element, which would require a more complicated parser, this
|
||||
// just fixes the incorrect duplicates to have the correct `$<CONFIG>` value,
|
||||
// making the duplication harmless.
|
||||
//
|
||||
// TODO(stuartmorgan): Remove this workaround either once 17.1.0 is
|
||||
// sufficiently old that we no longer need to support it, or when
|
||||
// dropping VS 2022 support.
|
||||
void _fixBrokenCmakeGeneration(Directory buildDirectory) {
|
||||
final File assembleProject = buildDirectory
|
||||
.childDirectory('flutter')
|
||||
.childFile('flutter_assemble.vcxproj');
|
||||
if (assembleProject.existsSync()) {
|
||||
// E.g.: <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
final RegExp commandRegex = RegExp(
|
||||
r'<Command Condition=.*\(Configuration\)\|\$\(Platform\).==.(Debug|Profile|Release)\|');
|
||||
// E.g.: [...]/flutter_tools/bin/tool_backend.bat windows-x64 Debug
|
||||
final RegExp assembleCallRegex = RegExp(
|
||||
r'^.*/tool_backend\.bat windows[^ ]* (Debug|Profile|Release)');
|
||||
String? lastCommandConditionConfig;
|
||||
final StringBuffer newProjectContents = StringBuffer();
|
||||
// vcxproj files contain a BOM, which readAsLinesSync drops; re-add it.
|
||||
newProjectContents.writeCharCode(unicodeBomCharacterRune);
|
||||
for (final String line in assembleProject.readAsLinesSync()) {
|
||||
final RegExpMatch? commandMatch = commandRegex.firstMatch(line);
|
||||
if (commandMatch != null) {
|
||||
lastCommandConditionConfig = commandMatch.group(1);
|
||||
} else if (lastCommandConditionConfig != null) {
|
||||
final RegExpMatch? assembleCallMatch = assembleCallRegex.firstMatch(line);
|
||||
if (assembleCallMatch != null) {
|
||||
final String callConfig = assembleCallMatch.group(1)!;
|
||||
if (callConfig != lastCommandConditionConfig) {
|
||||
// The config is the end of the line; make sure to replace that one,
|
||||
// in case config-matching strings appear anywhere else in the line
|
||||
// (e.g., the project path).
|
||||
final int badConfigIndex = line.lastIndexOf(assembleCallMatch.group(1)!);
|
||||
final String correctedLine = line.replaceFirst(
|
||||
callConfig, lastCommandConditionConfig, badConfigIndex);
|
||||
newProjectContents.writeln('$correctedLine\r');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
newProjectContents.writeln('$line\r');
|
||||
}
|
||||
assembleProject.writeAsStringSync(newProjectContents.toString());
|
||||
}
|
||||
}
|
||||
|
@ -309,6 +309,142 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier
|
||||
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
|
||||
});
|
||||
|
||||
testUsingContext('Windows build works around CMake generation bug', () async {
|
||||
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(displayVersion: '17.1.0');
|
||||
final BuildWindowsCommand command = BuildWindowsCommand()
|
||||
..visualStudioOverride = fakeVisualStudio;
|
||||
setUpMockProjectFilesForBuild();
|
||||
|
||||
processManager = FakeProcessManager.list(<FakeCommand>[
|
||||
cmakeGenerationCommand(),
|
||||
buildCommand('Release'),
|
||||
]);
|
||||
fileSystem.file(fileSystem.path.join('lib', 'other.dart'))
|
||||
.createSync(recursive: true);
|
||||
fileSystem.file(fileSystem.path.join('foo', 'bar.sksl.json'))
|
||||
.createSync(recursive: true);
|
||||
|
||||
// Relevant portions of an incorrectly generated project, with some
|
||||
// irrelevant details removed for length.
|
||||
const String fakeBadProjectContent = r'''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="somepath\build\windows\CMakeFiles\8b570225f626c250e12bc1ede88babae\flutter_windows.dll.rule">
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Profile
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generating some files</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">setlocal
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Release
|
||||
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
|
||||
:cmErrorLevel
|
||||
exit /b %1
|
||||
:cmDone
|
||||
if %errorlevel% neq 0 goto :VCEnd</Command>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
''';
|
||||
final File assembleProject = fileSystem.currentDirectory
|
||||
.childDirectory('build')
|
||||
.childDirectory('windows')
|
||||
.childDirectory('flutter')
|
||||
.childFile('flutter_assemble.vcxproj');
|
||||
assembleProject.createSync(recursive: true);
|
||||
assembleProject.writeAsStringSync(fakeBadProjectContent);
|
||||
|
||||
await createTestCommandRunner(command).run(
|
||||
const <String>['windows', '--no-pub']
|
||||
);
|
||||
|
||||
final List<String> projectLines = assembleProject.readAsLinesSync();
|
||||
|
||||
const String commandBase = r'"C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" '
|
||||
r'-E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64';
|
||||
// The duplicate commands will still be present, but with the order matching
|
||||
// the condition order (cycling through the configurations), rather than
|
||||
// three copies of Debug, then three copies of Profile, then three copies
|
||||
// of Release.
|
||||
expect(projectLines, containsAllInOrder(<String>[
|
||||
'$commandBase Debug\r',
|
||||
'$commandBase Profile\r',
|
||||
'$commandBase Release\r',
|
||||
'$commandBase Debug\r',
|
||||
'$commandBase Profile\r',
|
||||
'$commandBase Release\r',
|
||||
'$commandBase Debug\r',
|
||||
'$commandBase Profile\r',
|
||||
'$commandBase Release\r',
|
||||
]));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => processManager,
|
||||
Platform: () => windowsPlatform,
|
||||
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
|
||||
});
|
||||
|
||||
testUsingContext('Windows build invokes build and writes generated files', () async {
|
||||
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
|
||||
final BuildWindowsCommand command = BuildWindowsCommand()
|
||||
@ -604,6 +740,7 @@ class FakeVisualStudio extends Fake implements VisualStudio {
|
||||
FakeVisualStudio({
|
||||
this.cmakePath = _cmakePath,
|
||||
this.cmakeGenerator = 'Visual Studio 16 2019',
|
||||
this.displayVersion = '17.0.0'
|
||||
});
|
||||
|
||||
@override
|
||||
@ -611,4 +748,7 @@ class FakeVisualStudio extends Fake implements VisualStudio {
|
||||
|
||||
@override
|
||||
final String cmakeGenerator;
|
||||
|
||||
@override
|
||||
final String displayVersion;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user