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,
|
buildDir: buildDirectory,
|
||||||
sourceDir: windowsProject.cmakeFile.parent,
|
sourceDir: windowsProject.cmakeFile.parent,
|
||||||
);
|
);
|
||||||
|
if (visualStudio.displayVersion == '17.1.0') {
|
||||||
|
_fixBrokenCmakeGeneration(buildDirectory);
|
||||||
|
}
|
||||||
await _runBuild(cmakePath, buildDirectory, buildModeName);
|
await _runBuild(cmakePath, buildDirectory, buildModeName);
|
||||||
} finally {
|
} finally {
|
||||||
status.cancel();
|
status.cancel();
|
||||||
@ -335,3 +338,55 @@ void _writeGeneratedFlutterConfig(
|
|||||||
}
|
}
|
||||||
writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, environment);
|
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),
|
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 {
|
testUsingContext('Windows build invokes build and writes generated files', () async {
|
||||||
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
|
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
|
||||||
final BuildWindowsCommand command = BuildWindowsCommand()
|
final BuildWindowsCommand command = BuildWindowsCommand()
|
||||||
@ -604,6 +740,7 @@ class FakeVisualStudio extends Fake implements VisualStudio {
|
|||||||
FakeVisualStudio({
|
FakeVisualStudio({
|
||||||
this.cmakePath = _cmakePath,
|
this.cmakePath = _cmakePath,
|
||||||
this.cmakeGenerator = 'Visual Studio 16 2019',
|
this.cmakeGenerator = 'Visual Studio 16 2019',
|
||||||
|
this.displayVersion = '17.0.0'
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -611,4 +748,7 @@ class FakeVisualStudio extends Fake implements VisualStudio {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
final String cmakeGenerator;
|
final String cmakeGenerator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String displayVersion;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user