Switch Windows to CMake (#60629)

* First pass at CMake files; untested

* First pass of adding CMake generation logic on Windows

* Misc fixes

* Get bundling working, start incoprorating CMake build into tool

* Fix debug, exe name.

* Add resources

* Move cmake.dart

* Rip out all the vcxproj/solution plumbing

* Fix plugin cmake generation

* Build with cmake rather than calling VS directly

* Adjust Windows plugin template to match standard header directory structure

* Pass config selection when building

* Partially fix multi-config handling

* Rev template version

* Share the CMake generation instead of splitting it out

* VS build/run cycle works, with slightly awkward requirement to always build all

* Update manifest

* Plugin template fixes

* Minor adjustments

* Build install as part of build command, instead of separately

* Test cleanup

* Update Linux test for adjusted generated CMake approach

* Plugin test typo fix

* Add missing stub file for project test

* Add a constant for VS generator
diff --git a/packages/flutter_tools/bin/vs_build.bat b/packages/flutter_tools/bin/vs_build.bat
deleted file mode 100644
index ef7129d..0000000
--- a/packages/flutter_tools/bin/vs_build.bat
+++ /dev/null
@@ -1,17 +0,0 @@
-@ECHO off
-REM Copyright 2014 The Flutter Authors. All rights reserved.
-REM Use of this source code is governed by a BSD-style license that can be
-REM found in the LICENSE file.
-
-REM Calls vcvars64.bat to configure a command-line build environment, then builds
-REM a project with msbuild.
-@echo off
-
-set VCVARS=%~1
-set PROJECT=%~2
-set CONFIG=%~3
-
-call "%VCVARS%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-
-msbuild "%PROJECT%" /p:Configuration=%CONFIG%
diff --git a/packages/flutter_tools/lib/src/linux/cmake.dart b/packages/flutter_tools/lib/src/cmake.dart
similarity index 63%
rename from packages/flutter_tools/lib/src/linux/cmake.dart
rename to packages/flutter_tools/lib/src/cmake.dart
index 8a50066..e57b974 100644
--- a/packages/flutter_tools/lib/src/linux/cmake.dart
+++ b/packages/flutter_tools/lib/src/cmake.dart
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '../project.dart';
+import 'project.dart';
 
-/// Extracts the `BINARY_NAME` from a Linux project CMake file.
+/// Extracts the `BINARY_NAME` from a project's CMake file.
 ///
 /// Returns `null` if it cannot be found.
-String getCmakeExecutableName(LinuxProject project) {
+String getCmakeExecutableName(CmakeBasedProject project) {
   if (!project.cmakeFile.existsSync()) {
     return null;
   }
@@ -21,24 +21,30 @@
   return null;
 }
 
+String _escapeBackslashes(String s) {
+  return s.replaceAll(r'\', r'\\');
+}
+
 /// 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.
-void writeGeneratedCmakeConfig(String flutterRoot, LinuxProject project, Map<String, String> environment) {
+void writeGeneratedCmakeConfig(String flutterRoot, CmakeBasedProject project, Map<String, String> environment) {
   // 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.
+  final String escapedFlutterRoot = _escapeBackslashes(flutterRoot);
+  final String escapedProjectDir = _escapeBackslashes(project.parent.directory.path);
   final StringBuffer buffer = StringBuffer('''
 # Generated code do not commit.
-set(FLUTTER_ROOT "$flutterRoot")
-set(PROJECT_DIR "${project.project.directory.path}")
+file(TO_CMAKE_PATH "$escapedFlutterRoot" FLUTTER_ROOT)
+file(TO_CMAKE_PATH "$escapedProjectDir" PROJECT_DIR)
 
 # Environment variables to pass to tool_backend.sh
 list(APPEND FLUTTER_TOOL_ENVIRONMENT
-  "FLUTTER_ROOT=\\"\${FLUTTER_ROOT}\\""
-  "PROJECT_DIR=\\"\${PROJECT_DIR}\\""
+  "FLUTTER_ROOT=\\"$escapedFlutterRoot\\""
+  "PROJECT_DIR=\\"$escapedProjectDir\\""
 ''');
   for (final String key in environment.keys) {
-    final String value = environment[key];
+    final String value = _escapeBackslashes(environment[key]);
     buffer.writeln('  "$key=\\"$value\\""');
   }
   buffer.writeln(')');
diff --git a/packages/flutter_tools/lib/src/linux/application_package.dart b/packages/flutter_tools/lib/src/linux/application_package.dart
index d1a579f..acc80f2 100644
--- a/packages/flutter_tools/lib/src/linux/application_package.dart
+++ b/packages/flutter_tools/lib/src/linux/application_package.dart
@@ -7,9 +7,9 @@
 import '../application_package.dart';
 import '../base/file_system.dart';
 import '../build_info.dart';
+import '../cmake.dart';
 import '../globals.dart' as globals;
 import '../project.dart';
-import 'cmake.dart';
 
 abstract class LinuxApp extends ApplicationPackage {
   LinuxApp({@required String projectBundleId}) : super(id: projectBundleId);
@@ -52,7 +52,7 @@
 }
 
 class BuildableLinuxApp extends LinuxApp {
-  BuildableLinuxApp({this.project}) : super(projectBundleId: project.project.manifest.appName);
+  BuildableLinuxApp({this.project}) : super(projectBundleId: project.parent.manifest.appName);
 
   final LinuxProject project;
 
@@ -68,5 +68,5 @@
   }
 
   @override
-  String get name => project.project.manifest.appName;
+  String get name => project.parent.manifest.appName;
 }
diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart
index 2ff8690..fbbbf9e 100644
--- a/packages/flutter_tools/lib/src/linux/build_linux.dart
+++ b/packages/flutter_tools/lib/src/linux/build_linux.dart
@@ -10,10 +10,10 @@
 import '../base/utils.dart';
 import '../build_info.dart';
 import '../cache.dart';
+import '../cmake.dart';
 import '../globals.dart' as globals;
 import '../plugins.dart';
 import '../project.dart';
-import 'cmake.dart';
 
 /// Builds the Linux project through the Makefile.
 Future<void> buildLinux(
@@ -39,7 +39,7 @@
   }
   writeGeneratedCmakeConfig(Cache.flutterRoot, linuxProject, environmentConfig);
 
-  createPluginSymlinks(linuxProject.project);
+  createPluginSymlinks(linuxProject.parent);
 
   final Status status = globals.logger.startProgress(
     'Building Linux application...',
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index 97e3406..d8b32d9 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -6,6 +6,7 @@
 
 import 'package:meta/meta.dart';
 import 'package:package_config/package_config.dart';
+import 'package:path/path.dart' as path; // ignore: package_path_import
 import 'package:yaml/yaml.dart';
 
 import 'android/gradle.dart';
@@ -17,8 +18,6 @@
 import 'globals.dart' as globals;
 import 'platform_plugins.dart';
 import 'project.dart';
-import 'windows/property_sheet.dart';
-import 'windows/visual_studio_solution_utils.dart';
 
 void _renderTemplateToFile(String template, dynamic context, String filePath) {
   final String renderedTemplate = globals.templateRenderer
@@ -801,7 +800,7 @@
 #include "generated_plugin_registrant.h"
 
 {{#plugins}}
-#include <{{filename}}.h>
+#include <{{name}}/{{filename}}.h>
 {{/plugins}}
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
@@ -848,7 +847,7 @@
 }
 ''';
 
-const String _linuxPluginCmakefileTemplate = r'''
+const String _pluginCmakefileTemplate = r'''
 #
 # Generated file, do not edit.
 #
@@ -862,7 +861,7 @@
 set(PLUGIN_BUNDLED_LIBRARIES)
 
 foreach(plugin ${FLUTTER_PLUGIN_LIST})
-  add_subdirectory({{pluginsDir}}/${plugin}/linux plugins/${plugin})
+  add_subdirectory({{pluginsDir}}/${plugin}/{{os}} plugins/${plugin})
   target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
   list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
   list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
@@ -917,6 +916,7 @@
   // that file's directory.
   final String makefileDirPath = project.linux.cmakeFile.parent.absolute.path;
   final Map<String, dynamic> context = <String, dynamic>{
+    'os': 'linux',
     'plugins': linuxPlugins,
     'pluginsDir': globals.fs.path.relative(
       project.linux.pluginSymlinkDirectory.absolute.path,
@@ -924,7 +924,7 @@
     ),
   };
   await _writeLinuxPluginRegistrant(project.linux.managedDirectory, context);
-  await _writeLinuxPluginCmakefile(project.linux.generatedPluginCmakeFile, context);
+  await _writePluginCmakefile(project.linux.generatedPluginCmakeFile, context);
 }
 
 Future<void> _writeLinuxPluginRegistrant(Directory destination, Map<String, dynamic> templateContext) async {
@@ -941,9 +941,9 @@
   );
 }
 
-Future<void> _writeLinuxPluginCmakefile(File destinationFile, Map<String, dynamic> templateContext) async {
+Future<void> _writePluginCmakefile(File destinationFile, Map<String, dynamic> templateContext) async {
   _renderTemplateToFile(
-    _linuxPluginCmakefileTemplate,
+    _pluginCmakefileTemplate,
     templateContext,
     destinationFile.path,
   );
@@ -984,11 +984,22 @@
 Future<void> _writeWindowsPluginFiles(FlutterProject project, List<Plugin> plugins) async {
   final List<Plugin>nativePlugins = _filterNativePlugins(plugins, WindowsPlugin.kConfigKey);
   final List<Map<String, dynamic>> windowsPlugins = _extractPlatformMaps(nativePlugins, WindowsPlugin.kConfigKey);
+  // The generated file is checked in, so can't use absolute paths. It is
+  // included by the main CMakeLists.txt, so relative paths must be relative to
+  // that file's directory.
+  final String makefileDirPath = project.windows.cmakeFile.parent.absolute.path;
+  final path.Context cmakePathContext = path.Context(style: path.Style.posix);
+  final List<String> relativePathComponents = globals.fs.path.split(globals.fs.path.relative(
+    project.windows.pluginSymlinkDirectory.absolute.path,
+    from: makefileDirPath,
+  ));
   final Map<String, dynamic> context = <String, dynamic>{
+    'os': 'windows',
     'plugins': windowsPlugins,
+    'pluginsDir': cmakePathContext.joinAll(relativePathComponents),
   };
   await _writeCppPluginRegistrant(project.windows.managedDirectory, context);
-  await _writeWindowsPluginProperties(project.windows, windowsPlugins);
+  await _writePluginCmakefile(project.windows.generatedPluginCmakeFile, context);
 }
 
 Future<void> _writeCppPluginRegistrant(Directory destination, Map<String, dynamic> templateContext) async {
@@ -1005,20 +1016,6 @@
   );
 }
 
-Future<void> _writeWindowsPluginProperties(WindowsProject project, List<Map<String, dynamic>> windowsPlugins) async {
-  final List<String> pluginLibraryFilenames = windowsPlugins.map(
-    (Map<String, dynamic> plugin) => '${plugin['name']}_plugin.lib').toList();
-  // Use paths relative to the VS project directory.
-  final String projectDir = project.vcprojFile.parent.path;
-  final String symlinkDirPath = project.pluginSymlinkDirectory.path.substring(projectDir.length + 1);
-  final List<String> pluginIncludePaths = windowsPlugins.map((Map<String, dynamic> plugin) =>
-    globals.fs.path.join(symlinkDirPath, plugin['name'] as String, 'windows')).toList();
-  project.generatedPluginPropertySheetFile.writeAsStringSync(PropertySheet(
-    includePaths: pluginIncludePaths,
-    libraryDependencies: pluginLibraryFilenames,
-  ).toString());
-}
-
 Future<void> _writeWebPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
   final List<Map<String, dynamic>> webPlugins = _extractPlatformMaps(plugins, WebPlugin.kConfigKey);
   final Map<String, dynamic> context = <String, dynamic>{
@@ -1159,9 +1156,6 @@
   }
   if (featureFlags.isWindowsEnabled && project.windows.existsSync()) {
     await _writeWindowsPluginFiles(project, plugins);
-
-    final List<Plugin> nativePlugins = _filterNativePlugins(plugins, WindowsPlugin.kConfigKey);
-    await VisualStudioSolutionUtils(project: project.windows, fileSystem: globals.fs).updatePlugins(nativePlugins);
   }
   for (final XcodeBasedProject subproject in <XcodeBasedProject>[project.ios, project.macos]) {
     if (!project.isModule && (!checkProjects || subproject.existsSync())) {
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 2fe310c..c3b566e 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -329,6 +329,27 @@
   File get podManifestLock;
 }
 
+/// Represents a CMake-based sub-project.
+///
+/// This defines interfaces common to Windows and Linux projects.
+abstract class CmakeBasedProject {
+  /// The parent of this project.
+  FlutterProject get parent;
+
+  /// Whether the subproject (either Windows or Linux) exists in the Flutter project.
+  bool existsSync();
+
+  /// The native project CMake specification.
+  File get cmakeFile;
+
+  /// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
+  /// the build.
+  File get generatedCmakeConfigFile;
+
+  /// Includable CMake with rules and variables for plugin builds.
+  File get generatedPluginCmakeFile;
+}
+
 /// Represents the iOS sub-project of a Flutter project.
 ///
 /// Instances will reflect the contents of the `ios/` sub-folder of
@@ -995,18 +1016,28 @@
 }
 
 /// The Windows sub project
-class WindowsProject extends FlutterProjectPlatform {
-  WindowsProject._(this.project);
+class WindowsProject extends FlutterProjectPlatform implements CmakeBasedProject {
+  WindowsProject._(this.parent);
 
-  final FlutterProject project;
+  @override
+  final FlutterProject parent;
 
   @override
   String get pluginConfigKey => WindowsPlugin.kConfigKey;
 
   @override
-  bool existsSync() => _editableDirectory.existsSync() && solutionFile.existsSync();
+  bool existsSync() => _editableDirectory.existsSync() && cmakeFile.existsSync();
 
-  Directory get _editableDirectory => project.directory.childDirectory('windows');
+  @override
+  File get cmakeFile => _editableDirectory.childFile('CMakeLists.txt');
+
+  @override
+  File get generatedCmakeConfigFile => ephemeralDirectory.childFile('generated_config.cmake');
+
+  @override
+  File get generatedPluginCmakeFile => managedDirectory.childFile('generated_plugins.cmake');
+
+  Directory get _editableDirectory => parent.directory.childDirectory('windows');
 
   /// The directory in the project that is managed by Flutter. As much as
   /// possible, files that are edited by Flutter tooling after initial project
@@ -1018,24 +1049,6 @@
   /// checked in should live here.
   Directory get ephemeralDirectory => managedDirectory.childDirectory('ephemeral');
 
-  /// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
-  /// the build.
-  File get generatedPropertySheetFile => ephemeralDirectory.childFile('Generated.props');
-
-  /// Contains configuration to add plugins to the build.
-  File get generatedPluginPropertySheetFile => managedDirectory.childFile('GeneratedPlugins.props');
-
-  // The MSBuild project file.
-  File get vcprojFile => _editableDirectory.childFile('Runner.vcxproj');
-
-  // The MSBuild solution file.
-  File get solutionFile => _editableDirectory.childFile('Runner.sln');
-
-  /// The file where the VS build will write the name of the built app.
-  ///
-  /// Ideally this will be replaced in the future with inspection of the project.
-  File get nameFile => ephemeralDirectory.childFile('exe_filename');
-
   /// The directory to write plugin symlinks.
   Directory get pluginSymlinkDirectory => ephemeralDirectory.childDirectory('.plugin_symlinks');
 
@@ -1043,15 +1056,16 @@
 }
 
 /// The Linux sub project.
-class LinuxProject extends FlutterProjectPlatform {
-  LinuxProject._(this.project);
+class LinuxProject extends FlutterProjectPlatform implements CmakeBasedProject {
+  LinuxProject._(this.parent);
 
-  final FlutterProject project;
+  @override
+  final FlutterProject parent;
 
   @override
   String get pluginConfigKey => LinuxPlugin.kConfigKey;
 
-  Directory get _editableDirectory => project.directory.childDirectory('linux');
+  Directory get _editableDirectory => parent.directory.childDirectory('linux');
 
   /// The directory in the project that is managed by Flutter. As much as
   /// possible, files that are edited by Flutter tooling after initial project
@@ -1066,14 +1080,13 @@
   @override
   bool existsSync() => _editableDirectory.existsSync();
 
-  /// The Linux project CMake specification.
+  @override
   File get cmakeFile => _editableDirectory.childFile('CMakeLists.txt');
 
-  /// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
-  /// the build.
+  @override
   File get generatedCmakeConfigFile => ephemeralDirectory.childFile('generated_config.cmake');
 
-  /// Includable CMake with rules and variables for plugin builds.
+  @override
   File get generatedPluginCmakeFile => managedDirectory.childFile('generated_plugins.cmake');
 
   /// The directory to write plugin symlinks.
diff --git a/packages/flutter_tools/lib/src/windows/application_package.dart b/packages/flutter_tools/lib/src/windows/application_package.dart
index bd93c80..8051b06 100644
--- a/packages/flutter_tools/lib/src/windows/application_package.dart
+++ b/packages/flutter_tools/lib/src/windows/application_package.dart
@@ -5,10 +5,10 @@
 import 'package:meta/meta.dart';
 
 import '../application_package.dart';
-import '../base/common.dart';
 import '../base/file_system.dart';
 import '../base/utils.dart';
 import '../build_info.dart';
+import '../cmake.dart';
 import '../globals.dart' as globals;
 import '../project.dart';
 
@@ -55,24 +55,21 @@
 class BuildableWindowsApp extends WindowsApp {
   BuildableWindowsApp({
     @required this.project,
-  }) : super(projectBundleId: project.project.manifest.appName);
+  }) : super(projectBundleId: project.parent.manifest.appName);
 
   final WindowsProject project;
 
   @override
   String executable(BuildMode buildMode) {
-    final File exeNameFile = project.nameFile;
-    if (!exeNameFile.existsSync()) {
-      throwToolExit('Failed to find Windows executable name');
-    }
+    final String binaryName = getCmakeExecutableName(project);
     return globals.fs.path.join(
         getWindowsBuildDirectory(),
-        'x64',
+        'runner',
         toTitleCase(getNameForBuildMode(buildMode)),
-        'Runner',
-        exeNameFile.readAsStringSync().trim());
+        '$binaryName.exe',
+    );
   }
 
   @override
-  String get name => project.project.manifest.appName;
+  String get name => project.parent.manifest.appName;
 }
diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart
index 9a3f813..31a9967 100644
--- a/packages/flutter_tools/lib/src/windows/build_windows.dart
+++ b/packages/flutter_tools/lib/src/windows/build_windows.dart
@@ -10,18 +10,23 @@
 import '../base/utils.dart';
 import '../build_info.dart';
 import '../cache.dart';
+import '../cmake.dart';
 import '../globals.dart' as globals;
 import '../plugins.dart';
 import '../project.dart';
-import 'property_sheet.dart';
 import 'visual_studio.dart';
 
+// From https://cmake.org/cmake/help/v3.15/manual/cmake-generators.7.html#visual-studio-generators
+// This may need to become a getter on VisualStudio in the future to support
+// future major versions of Visual Studio.
+const String _cmakeVisualStudioGeneratorIdentifier = 'Visual Studio 16 2019';
+
 /// Builds the Windows project using msbuild.
 Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
   String target,
   VisualStudio visualStudioOverride,
 }) async {
-  if (!windowsProject.solutionFile.existsSync()) {
+  if (!windowsProject.cmakeFile.existsSync()) {
     throwToolExit(
       'No Windows desktop project configured. '
       'See https://github.com/flutter/flutter/wiki/Desktop-shells#create '
@@ -43,8 +48,8 @@
   }
 
   // Ensure that necessary emphemeral files are generated and up to date.
-  _writeGeneratedFlutterProperties(windowsProject, buildInfo, target);
-  createPluginSymlinks(windowsProject.project);
+  _writeGeneratedFlutterConfig(windowsProject, buildInfo, target);
+  createPluginSymlinks(windowsProject.parent);
 
   final VisualStudio visualStudio = visualStudioOverride ?? VisualStudio(
     fileSystem: globals.fs,
@@ -52,57 +57,88 @@
     logger: globals.logger,
     processManager: globals.processManager,
   );
-  final String vcvarsScript = visualStudio.vcvarsPath;
-  if (vcvarsScript == null) {
+  final String cmakePath = visualStudio.cmakePath;
+  if (cmakePath == null) {
     throwToolExit('Unable to find suitable Visual Studio toolchain. '
         'Please run `flutter doctor` for more details.');
   }
 
-  final String buildScript = globals.fs.path.join(
-    Cache.flutterRoot,
-    'packages',
-    'flutter_tools',
-    'bin',
-    'vs_build.bat',
-  );
-
-  final String configuration = toTitleCase(getNameForBuildMode(buildInfo.mode ?? BuildMode.release));
-  final String solutionPath = windowsProject.solutionFile.path;
-  final Stopwatch sw = Stopwatch()..start();
+  final String buildModeName = getNameForBuildMode(buildInfo.mode ?? BuildMode.release);
+  final Directory buildDirectory = globals.fs.directory(getWindowsBuildDirectory());
   final Status status = globals.logger.startProgress(
     'Building Windows application...',
     timeout: null,
   );
+  try {
+    await _runCmakeGeneration(cmakePath, buildDirectory, windowsProject.cmakeFile.parent);
+    await _runBuild(cmakePath, buildDirectory, buildModeName);
+  } finally {
+    status.cancel();
+  }
+}
+
+Future<void> _runCmakeGeneration(String cmakePath, Directory buildDir, Directory sourceDir) async {
+  final Stopwatch sw = Stopwatch()..start();
+
+  await buildDir.create(recursive: true);
   int result;
   try {
-    // Run the script with a relative path to the project using the enclosing
-    // directory as the workingDirectory, to avoid hitting the limit on command
-    // lengths in batch scripts if the absolute path to the project is long.
     result = await processUtils.stream(
       <String>[
-        buildScript,
-        vcvarsScript,
-        globals.fs.path.basename(solutionPath),
-        configuration,
+        cmakePath,
+        '-S',
+        sourceDir.path,
+        '-B',
+        buildDir.path,
+        '-G',
+        _cmakeVisualStudioGeneratorIdentifier,
+      ],
+      trace: true,
+    );
+  } on ArgumentError {
+    throwToolExit("cmake not found. Run 'flutter doctor' for more information.");
+  }
+  if (result != 0) {
+    throwToolExit('Unable to generate build files');
+  }
+  globals.flutterUsage.sendTiming('build', 'windows-cmake-generation', Duration(milliseconds: sw.elapsedMilliseconds));
+}
+
+Future<void> _runBuild(String cmakePath, Directory buildDir, String buildModeName) async {
+  final Stopwatch sw = Stopwatch()..start();
+
+  int result;
+  try {
+    result = await processUtils.stream(
+      <String>[
+        cmakePath,
+        '--build',
+        buildDir.path,
+        '--config',
+        toTitleCase(buildModeName),
+        '--target',
+        'INSTALL',
+        if (globals.logger.isVerbose)
+          '--verbose'
       ],
       environment: <String, String>{
         if (globals.logger.isVerbose)
           'VERBOSE_SCRIPT_LOGGING': 'true'
       },
-      workingDirectory: globals.fs.path.dirname(solutionPath),
       trace: true,
     );
-  } finally {
-    status.cancel();
+  } on ArgumentError {
+    throwToolExit("cmake not found. Run 'flutter doctor' for more information.");
   }
   if (result != 0) {
-    throwToolExit('Build process failed. To view the stack trace, please run `flutter run -d windows -v`.');
+    final String verboseInstructions = globals.logger.isVerbose ? '' : ' To view the stack trace, please run `flutter run -d windows -v`.';
+    throwToolExit('Build process failed.$verboseInstructions');
   }
-  globals.flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
+  globals.flutterUsage.sendTiming('build', 'windows-cmake-build', Duration(milliseconds: sw.elapsedMilliseconds));
 }
 
-/// Writes the generatedPropertySheetFile with the configuration for the given build.
-void _writeGeneratedFlutterProperties(
+/// Writes the generated CMake file with the configuration for the given build.
+void _writeGeneratedFlutterConfig(
   WindowsProject windowsProject,
   BuildInfo buildInfo,
   String target,
@@ -110,7 +146,7 @@
   final Map<String, String> environment = <String, String>{
     'FLUTTER_ROOT': Cache.flutterRoot,
     'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path,
-    'PROJECT_DIR': windowsProject.project.directory.path,
+    'PROJECT_DIR': windowsProject.parent.directory.path,
     if (target != null)
       'FLUTTER_TARGET': target,
     ...buildInfo.toEnvironmentConfig(),
@@ -121,10 +157,7 @@
     environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath));
     environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath);
   }
-
-  final File propsFile = windowsProject.generatedPropertySheetFile;
-  propsFile.createSync(recursive: true);
-  propsFile.writeAsStringSync(PropertySheet(environmentVariables: environment).toString());
+  writeGeneratedCmakeConfig(Cache.flutterRoot, windowsProject, environment);
 }
 
 // Checks the template version of [project] against the current template
diff --git a/packages/flutter_tools/lib/src/windows/property_sheet.dart b/packages/flutter_tools/lib/src/windows/property_sheet.dart
deleted file mode 100644
index e088485..0000000
--- a/packages/flutter_tools/lib/src/windows/property_sheet.dart
+++ /dev/null
@@ -1,121 +0,0 @@
-// 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 'package:xml/xml.dart' as xml;
-
-/// A utility class for building property sheet (.props) files for use
-/// with MSBuild/Visual Studio projects.
-class PropertySheet {
-  /// Creates a PropertySheet with the given properties.
-  const PropertySheet({
-    this.environmentVariables,
-    this.includePaths,
-    this.libraryDependencies,
-  });
-
-  /// Variables to make available both as build macros and as environment
-  /// variables for script steps.
-  final Map<String, String> environmentVariables;
-
-  /// Directories to search for headers.
-  final List<String> includePaths;
-
-  /// Libraries to link against.
-  final List<String> libraryDependencies;
-
-  @override
-  String toString() {
-    // See https://docs.microsoft.com/en-us/cpp/build/reference/vcxproj-file-structure#property-sheet-layout
-
-    final xml.XmlBuilder builder = xml.XmlBuilder();
-    builder.processing('xml', 'version="1.0" encoding="utf-8"');
-    builder.element('Project', nest: () {
-      builder.attribute('ToolsVersion', '4.0');
-      builder.attribute(
-          'xmlns', 'http://schemas.microsoft.com/developer/msbuild/2003');
-
-      builder.element('ImportGroup', nest: () {
-        builder.attribute('Label', 'PropertySheets');
-      });
-      builder.element('PropertyGroup', nest: () {
-        builder.attribute('Label', 'UserMacros');
-
-        _addEnviromentVariableUserMacros(builder);
-      });
-      builder.element('PropertyGroup');
-      builder.element('ItemDefinitionGroup', nest: () {
-        _addIncludePaths(builder);
-        _addLibraryDependencies(builder);
-      });
-      builder.element('ItemGroup', nest: () {
-        _addEnvironmentVariableBuildMacros(builder);
-      });
-    });
-
-    return builder.build().toXmlString(pretty: true, indent: '  ');
-  }
-
-  /// Adds directories to the header search path.
-  ///
-  /// Must be called within the context of the ItemDefinitionGroup.
-  void _addIncludePaths(xml.XmlBuilder builder) {
-    if (includePaths == null || includePaths.isEmpty) {
-      return;
-    }
-    builder.element('ClCompile', nest: () {
-      builder.element('AdditionalIncludeDirectories', nest: () {
-        builder.text('${includePaths.join(';')};%(AdditionalIncludeDirectories)');
-      });
-    });
-  }
-
-  /// Adds libraries to the link step.
-  ///
-  /// Must be called within the context of the ItemDefinitionGroup.
-  void _addLibraryDependencies(xml.XmlBuilder builder) {
-    if (libraryDependencies == null || libraryDependencies.isEmpty) {
-      return;
-    }
-    builder.element('Link', nest: () {
-      builder.element('AdditionalDependencies', nest: () {
-        builder.text('${libraryDependencies.join(';')};%(AdditionalDependencies)');
-      });
-    });
-  }
-
-  /// Writes key/value pairs for any environment variables as user macros.
-  ///
-  /// Must be called within the context of the UserMacros PropertyGroup.
-  void _addEnviromentVariableUserMacros(xml.XmlBuilder builder) {
-    if (environmentVariables == null) {
-      return;
-    }
-    for (final MapEntry<String, String> variable in environmentVariables.entries) {
-      builder.element(variable.key, nest: () {
-        builder.text(variable.value);
-      });
-    }
-  }
-
-  /// Writes the BuildMacros to expose environment variable UserMacros to the
-  /// environment.
-  ///
-  /// Must be called within the context of the ItemGroup.
-  void _addEnvironmentVariableBuildMacros(xml.XmlBuilder builder) {
-    if (environmentVariables == null) {
-      return;
-    }
-    for (final String name in environmentVariables.keys) {
-      builder.element('BuildMacro', nest: () {
-        builder.attribute('Include', name);
-        builder.element('Value', nest: () {
-          builder.text('\$($name)');
-        });
-        builder.element('EnvironmentVariable', nest: () {
-          builder.text('true');
-        });
-      });
-    }
-  }
-}
diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart
index ac2d9fa..6187fee 100644
--- a/packages/flutter_tools/lib/src/windows/visual_studio.dart
+++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart
@@ -147,20 +147,24 @@
     return '2019';
   }
 
-  /// The path to vcvars64.bat, or null if no Visual Studio installation has
+  /// The path to CMake, or null if no Visual Studio installation has
   /// the components necessary to build.
-  String get vcvarsPath {
+  String get cmakePath {
     final Map<String, dynamic> details = _usableVisualStudioDetails;
     if (details.isEmpty) {
       return null;
     }
-    return _fileSystem.path.join(
+    return _fileSystem.path.joinAll(<String>[
       _usableVisualStudioDetails[_installationPathKey] as String,
-      'VC',
-      'Auxiliary',
-      'Build',
-      'vcvars64.bat',
-    );
+      'Common7',
+      'IDE',
+      'CommonExtensions',
+      'Microsoft',
+      'CMake',
+      'CMake',
+      'bin',
+      'cmake.exe',
+    ]);
   }
 
   /// The major version of the Visual Studio install, as an integer.
@@ -212,6 +216,8 @@
     return <String, String>{
       // The C++ toolchain required by the template.
       'Microsoft.VisualStudio.Component.VC.Tools.x86.x64': cppToolchainDescription,
+      // CMake
+      'Microsoft.VisualStudio.Component.VC.CMake.Project': 'C++ CMake tools for Windows',
     };
   }
 
diff --git a/packages/flutter_tools/lib/src/windows/visual_studio_project.dart b/packages/flutter_tools/lib/src/windows/visual_studio_project.dart
deleted file mode 100644
index 47a4f87..0000000
--- a/packages/flutter_tools/lib/src/windows/visual_studio_project.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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 'package:meta/meta.dart';
-import 'package:xml/xml.dart' as xml;
-
-import '../base/file_system.dart';
-
-/// A utility class for interacting with Visual Studio project files (e.g.,
-/// .vcxproj).
-class VisualStudioProject {
-  /// Creates a project object from the project file at [file].
-  VisualStudioProject(this.file, {
-    @required FileSystem fileSystem,
-  }): _fileSystem = fileSystem {
-    try {
-      content = xml.parse(file.readAsStringSync());
-    } on xml.XmlParserException {
-      // Silently continue; formatUnderstood will return false.
-    }
-  }
-
-  final FileSystem _fileSystem;
-
-  /// The file corresponding to this object.
-  final File file;
-
-  /// The content of the project file.
-  xml.XmlDocument content;
-
-  /// Whether or not the project file was correctly parsed.
-  ///
-  /// If false, this could indicate that the project file is damaged, or that
-  /// it's an unsupported project type.
-  bool get formatUnderstood => content != null;
-
-  String _guid;
-
-  /// Returns the ProjectGuid for the project, or null if it's not present.
-  String get guid {
-    return _guid ??= _findGuid();
-  }
-
-  String _findGuid() {
-    if (!formatUnderstood) {
-      return null;
-    }
-    try {
-      final String guidValue = content.findAllElements('ProjectGuid').single.text.trim();
-      // Remove the enclosing {} from the value.
-      return guidValue.substring(1, guidValue.length - 1);
-    } on StateError {
-      // If there is not exactly one ProjectGuid, return null.
-      return null;
-    }
-  }
-
-  String _name;
-
-  /// Returns the ProjectName for the project.
-  ///
-  /// If not explicitly set in the project, uses the basename of the project
-  /// file.
-  String get name {
-    return _name ??= _findName();
-  }
-
-  String _findName() {
-    if (!formatUnderstood) {
-      return null;
-    }
-    try {
-      return content.findAllElements('ProjectName').first.text.trim();
-    } on StateError {
-      // If there is no name, fall back to filename.
-      return _fileSystem.path.basenameWithoutExtension(file.path);
-    }
-  }
-}
diff --git a/packages/flutter_tools/lib/src/windows/visual_studio_solution_utils.dart b/packages/flutter_tools/lib/src/windows/visual_studio_solution_utils.dart
deleted file mode 100644
index f5a40fe..0000000
--- a/packages/flutter_tools/lib/src/windows/visual_studio_solution_utils.dart
+++ /dev/null
@@ -1,345 +0,0 @@
-// 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 'package:meta/meta.dart';
-
-import '../base/common.dart';
-import '../base/file_system.dart';
-import '../convert.dart';
-import '../plugins.dart';
-import '../project.dart';
-import 'visual_studio_project.dart';
-
-// Constants corresponding to specific reference types in a solution file.
-// These values are defined by the .sln format.
-const String _kSolutionTypeGuidFolder = '2150E333-8FDC-42A3-9474-1A3956D46DE8';
-const String _kSolutionTypeGuidVcxproj = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942';
-
-// The GUID for the folder above, managed by this class. This is an arbitrary
-// value that was randomly generated, but it should not be changed since that
-// would cause issues for existing Flutter projects.
-const String _kFlutterPluginSolutionFolderGuid = '5C2E738A-1DD3-445A-AAC8-EEB9648DD07C';
-// The FlutterBuild project GUID. This is an arbitrary
-// value that was randomly generated, but it should not be changed since that
-// would cause issues for existing Flutter projects.
-const String _kFlutterBuildProjectGuid = '6419BF13-6ECD-4CD2-9E85-E566A1F03F8F';
-
-/// Extracts and stores the plugin name and vcxproj GUID for [plugin].
-class _PluginProjectInfo {
-  _PluginProjectInfo(Plugin plugin, {
-    @required FileSystem fileSystem,
-  }) {
-    name = plugin.name;
-    final File projectFile = fileSystem.directory(plugin.path).childDirectory('windows').childFile('plugin.vcxproj');
-    try {
-    guid = VisualStudioProject(projectFile, fileSystem: fileSystem).guid;
-    } on FileSystemException {
-      throwToolExit('Unable to find a plugin.vcxproj for plugin "$name"');
-    }
-    if (guid == null) {
-      throwToolExit('Unable to find a plugin.vcxproj ID for plugin "$name"');
-    }
-  }
-
-  // The name of the plugin, which is also the name of the symlink folder.
-  String name;
-
-  // The GUID of the plugin's project.
-  String guid;
-}
-
-// TODO(stuartmorgan): Consider replacing this class with a real parser. See
-// https://github.com/flutter/flutter/issues/51430.
-
-class VisualStudioSolutionUtils {
-  const VisualStudioSolutionUtils({
-    @required WindowsProject project,
-    @required FileSystem fileSystem,
-  }) : _project = project,
-       _fileSystem = fileSystem;
-
-  final WindowsProject _project;
-  final FileSystem _fileSystem;
-
-  /// Updates the solution file for [project] to have the project references and
-  /// dependencies to include [plugins], removing any previous plugins from the
-  /// solution.
-  Future<void> updatePlugins(List<Plugin> plugins) async {
-    if (!_project.solutionFile.existsSync()) {
-      throwToolExit(
-        'Attempted to update Windows plugins on a project that does not '
-        'support Windows.',
-      );
-    }
-    final String solutionContent = await _project.solutionFile.readAsString();
-
-    // Map of GUID to name for the current plugin list.
-    final Map<String, String> currentPluginInfo = _getWindowsPluginNamesByGuid(plugins);
-
-    // Find any plugins referenced in the project that are no longer used, and
-    // any that are new.
-    //
-    // While the simplest approach to updating the solution would be to remove all
-    // entries associated with plugins, and then add all the current plugins in
-    // one block, Visual Studio has its own (unknown, likely data-structure-hash
-    // based) order that it will use each time it writes out the file due to any
-    // solution-level changes made in the UI. To avoid thrashing, and resulting
-    // confusion (e.g., in review diffs), this update attempts to instead preserve
-    // the ordering that is already there, so that once Visual Studio has
-    // reordered the plugins, that order will be stable.
-    final Set<String> existingPlugins = _findPreviousPluginGuids(solutionContent);
-    final Set<String> currentPlugins = currentPluginInfo.keys.toSet();
-    final Set<String> removedPlugins = existingPlugins.difference(currentPlugins);
-    final Set<String> addedPlugins = currentPlugins.difference(existingPlugins);
-
-    final RegExp projectStartPattern = RegExp(r'^Project\("{' + _kSolutionTypeGuidVcxproj + r'}"\)\s*=\s*".*",\s*"(.*)",\s*"{([A-Fa-f0-9\-]*)}"\s*$');
-    final RegExp pluginsFolderProjectStartPattern = RegExp(r'^Project\("{' + _kSolutionTypeGuidFolder + r'}"\)\s*=.*"{' + _kFlutterPluginSolutionFolderGuid + r'}"\s*$');
-    final RegExp projectEndPattern = RegExp(r'^EndProject\s*$');
-    final RegExp globalStartPattern = RegExp(r'^Global\s*$');
-    final RegExp globalEndPattern = RegExp(r'^EndGlobal\s*$');
-    final RegExp projectDependenciesStartPattern = RegExp(r'^\s*ProjectSection\(ProjectDependencies\)\s*=\s*postProject\s*$');
-    final RegExp globalSectionProjectConfigurationStartPattern = RegExp(r'^\s*GlobalSection\(ProjectConfigurationPlatforms\)\s*=\s*postSolution\s*$');
-    final RegExp globalSectionNestedProjectsStartPattern = RegExp(r'^\s*GlobalSection\(NestedProjects\)\s*=\s*preSolution\s*$');
-
-    final StringBuffer newSolutionContent = StringBuffer();
-    // readAsString drops the BOM; re-add it.
-    newSolutionContent.writeCharCode(unicodeBomCharacterRune);
-
-    final Iterator<String> lineIterator = solutionContent.split('\n').iterator;
-    bool foundFlutterPluginsFolder = false;
-    bool foundNestedProjectsSection = false;
-    bool foundRunnerProject = false;
-    while (lineIterator.moveNext()) {
-      final Match projectStartMatch = projectStartPattern.firstMatch(lineIterator.current);
-      if (projectStartMatch != null) {
-        final String guid = projectStartMatch.group(2);
-        if (currentPlugins.contains(guid)) {
-          // Write an up-to-date version at this location (in case, e.g., the name
-          // has changed).
-          _writePluginProjectEntry(guid, currentPluginInfo[guid], newSolutionContent);
-          // Drop the old copy.
-          _skipUntil(lineIterator, projectEndPattern);
-          continue;
-        } else if (removedPlugins.contains(guid)) {
-          // Drop the stale plugin project.
-          _skipUntil(lineIterator, projectEndPattern);
-          continue;
-        } else if (projectStartMatch.group(1) == _project.vcprojFile.basename) {
-          foundRunnerProject = true;
-          // Update the Runner project's dependencies on the plugins.
-          // Skip to the dependencies section, or if there isn't one the end of
-          // the project.
-          while (!projectDependenciesStartPattern.hasMatch(lineIterator.current) &&
-              !projectEndPattern.hasMatch(lineIterator.current)) {
-            newSolutionContent.writeln(lineIterator.current);
-            lineIterator.moveNext();
-          }
-          // Add/update the dependencies section.
-          if (projectDependenciesStartPattern.hasMatch(lineIterator.current)) {
-            newSolutionContent.writeln(lineIterator.current);
-            _processSectionPluginReferences(removedPlugins, addedPlugins, lineIterator, _writeProjectDependency, newSolutionContent);
-          } else {
-            _writeDependenciesSection(currentPlugins, newSolutionContent);
-          }
-        }
-      }
-
-      if (pluginsFolderProjectStartPattern.hasMatch(lineIterator.current)) {
-          foundFlutterPluginsFolder = true;
-      }
-
-      if (globalStartPattern.hasMatch(lineIterator.current)) {
-        // The Global section is the end of the project list. Add any new plugins
-        // here, since the location VS will use is unknown. They will likely be
-        // reordered the next time VS writes the file.
-        for (final String guid in addedPlugins) {
-          _writePluginProjectEntry(guid, currentPluginInfo[guid], newSolutionContent);
-        }
-        // Also add the plugins folder if there wasn't already one.
-        if (!foundFlutterPluginsFolder) {
-          _writePluginFolderProjectEntry(newSolutionContent);
-        }
-      }
-
-      // Update the ProjectConfiguration section once it is reached.
-      if (globalSectionProjectConfigurationStartPattern.hasMatch(lineIterator.current)) {
-        newSolutionContent.writeln(lineIterator.current);
-        _processSectionPluginReferences(removedPlugins, addedPlugins, lineIterator, _writePluginConfigurationEntries, newSolutionContent);
-      }
-
-      // Update the NestedProjects section once it is reached.
-      if (globalSectionNestedProjectsStartPattern.hasMatch(lineIterator.current)) {
-        newSolutionContent.writeln(lineIterator.current);
-        _processSectionPluginReferences(removedPlugins, addedPlugins, lineIterator, _writePluginNestingEntry, newSolutionContent);
-        foundNestedProjectsSection = true;
-      }
-
-      // If there wasn't a NestedProjects global section, add one at the end.
-      if (!foundNestedProjectsSection && globalEndPattern.hasMatch(lineIterator.current)) {
-        newSolutionContent.writeln('\tGlobalSection(NestedProjects) = preSolution\r');
-        for (final String guid in currentPlugins) {
-          _writePluginNestingEntry(guid, newSolutionContent);
-        }
-        newSolutionContent.writeln('\tEndGlobalSection\r');
-      }
-
-      // Re-output anything that hasn't been explicitly skipped above.
-      newSolutionContent.writeln(lineIterator.current);
-    }
-
-    if (!foundRunnerProject) {
-      throwToolExit(
-          'Could not add plugins to Windows project:\n'
-          'Unable to find a "${_project.vcprojFile.basename}" project in ${_project.solutionFile.path}');
-    }
-
-    await _project.solutionFile.writeAsString(newSolutionContent.toString().trimRight());
-  }
-
-  /// Advances [iterator] it reaches an element that matches [pattern].
-  ///
-  /// Note that the current element at the time of calling is *not* checked.
-  void _skipUntil(Iterator<String> iterator, RegExp pattern) {
-    while (iterator.moveNext()) {
-      if (pattern.hasMatch(iterator.current)) {
-        return;
-      }
-    }
-  }
-
-  /// Writes the main project entry for the plugin with the given [guid] and
-  /// [name].
-  void _writePluginProjectEntry(String guid, String name, StringBuffer output) {
-    output.write('''
-Project("{$_kSolutionTypeGuidVcxproj}") = "$name", "Flutter\\ephemeral\\.plugin_symlinks\\$name\\windows\\plugin.vcxproj", "{$guid}"\r
-\tProjectSection(ProjectDependencies) = postProject\r
-\t\t{$_kFlutterBuildProjectGuid} = {$_kFlutterBuildProjectGuid}\r
-\tEndProjectSection\r
-EndProject\r
-''');
-  }
-
-  /// Writes the main project entry for the Flutter Plugins solution folder.
-  void _writePluginFolderProjectEntry(StringBuffer output) {
-    const String folderName = 'Flutter Plugins';
-    output.write('''
-Project("{$_kSolutionTypeGuidFolder}") = "$folderName", "$folderName", "{$_kFlutterPluginSolutionFolderGuid}"\r
-EndProject\r
-''');
-  }
-
-  /// Writes a project dependencies section, depending on all the GUIDs in
-  /// [dependencies].
-  void _writeDependenciesSection(Iterable<String> dependencies, StringBuffer output) {
-    output.writeln('ProjectSection(ProjectDependencies) = postProject\r');
-    for (final String guid in dependencies) {
-      _writeProjectDependency(guid, output);
-    }
-    output.writeln('EndProjectSection\r');
-  }
-
-  /// Returns the GUIDs of all the Flutter plugin projects in the given solution.
-  Set<String> _findPreviousPluginGuids(String solutionContent) {
-    // Find the plugin folder's known GUID in ProjectDependencies lines.
-    // Each line in that section has the form:
-    //   {project GUID} = {solution folder GUID}
-    final RegExp pluginFolderChildrenPattern = RegExp(
-        r'^\s*{([A-Fa-f0-9\-]*)}\s*=\s*{' + _kFlutterPluginSolutionFolderGuid + r'}\s*$',
-        multiLine: true,
-    );
-    return pluginFolderChildrenPattern
-        .allMatches(solutionContent)
-        .map((Match match) => match.group(1)).toSet();
-  }
-
-  /// Returns a mapping of plugin project GUID to name for all the Windows plugins
-  /// in [plugins].
-  Map<String, String> _getWindowsPluginNamesByGuid(List<Plugin> plugins) {
-    final Map<String, String> currentPluginInfo = <String, String>{};
-    for (final Plugin plugin in plugins) {
-      if (plugin.platforms.containsKey(_project.pluginConfigKey)) {
-        final _PluginProjectInfo info = _PluginProjectInfo(plugin, fileSystem: _fileSystem);
-        if (currentPluginInfo.containsKey(info.guid)) {
-          throwToolExit('The plugins "${currentPluginInfo[info.guid]}" and "${info.name}" '
-              'have the same ProjectGuid, which prevents them from being used together.\n\n'
-              'Please contact the plugin authors to resolve this, and/or remove one of the '
-              'plugins from your project.');
-        }
-        currentPluginInfo[info.guid] = info.name;
-      }
-    }
-    return currentPluginInfo;
-  }
-
-  /// Walks a GlobalSection or ProjectSection, removing entries related to removed
-  /// plugins and adding entries for new plugins at the end using
-  /// [newEntryWriter], which takes the guid of the plugin to write entries for.
-  ///
-  /// The caller is responsible for printing the section start line, which should
-  /// be [lineIterator.current] when this is called, and the section end line,
-  /// which will be [lineIterator.current] on return.
-  void _processSectionPluginReferences(
-      Set<String> removedPlugins,
-      Set<String> addedPlugins,
-      Iterator<String> lineIterator,
-      Function(String, StringBuffer) newEntryWriter,
-      StringBuffer output,
-  ) {
-    // Extracts the guid of the project that a line refers to. Currently all
-    // sections this function is used for start with "{project guid}", even though
-    // the rest of the line varies by section, so the pattern can currently be
-    // shared rather than parameterized.
-    final RegExp entryPattern = RegExp(r'^\s*{([A-Fa-f0-9\-]*)}');
-    final RegExp sectionEndPattern = RegExp(r'^\s*End\w*Section\s*$');
-    while (lineIterator.moveNext()) {
-      if (sectionEndPattern.hasMatch(lineIterator.current)) {
-        // The end of the section; add entries for new plugins, then exit.
-        for (final String guid in addedPlugins) {
-          newEntryWriter(guid, output);
-        }
-        return;
-      }
-      // Otherwise it's the sectino body. Drop any lines associated with old
-      // plugins, but pass everything else through as output.
-      final Match entryMatch = entryPattern.firstMatch(lineIterator.current);
-      if (entryMatch != null && removedPlugins.contains(entryMatch.group(1))) {
-        continue;
-      }
-      output.writeln(lineIterator.current);
-    }
-  }
-
-  /// Writes all the configuration entries for the plugin project with the given
-  /// [guid].
-  ///
-  /// Should be called within the context of writing
-  /// GlobalSection(ProjectConfigurationPlatforms).
-  void _writePluginConfigurationEntries(String guid, StringBuffer output) {
-    final List<String> configurations = <String>['Debug', 'Profile', 'Release'];
-    final List<String> entryTypes = <String>['ActiveCfg', 'Build.0'];
-    for (final String configuration in configurations) {
-      for (final String entryType in entryTypes) {
-        output.writeln('\t\t{$guid}.$configuration|x64.$entryType = $configuration|x64\r');
-      }
-    }
-  }
-
-  /// Writes the entries to nest the plugin projects with the given [guid] under
-  /// the Flutter Plugins solution folder.
-  ///
-  /// Should be called within the context of writing
-  /// GlobalSection(NestedProjects).
-  void _writePluginNestingEntry(String guid, StringBuffer output) {
-    output.writeln('\t\t{$guid} = {$_kFlutterPluginSolutionFolderGuid}\r');
-  }
-
-  /// Writes the entrie to make a project depend on another project with the
-  /// given [guid].
-  ///
-  /// Should be called within the context of writing
-  /// ProjectSection(ProjectDependencies).
-  void _writeProjectDependency(String guid, StringBuffer output) {
-    output.writeln('\t\t{$guid} = {$guid}\r');
-  }
-}
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/AppConfiguration.props.tmpl b/packages/flutter_tools/templates/app/windows.tmpl/AppConfiguration.props.tmpl
deleted file mode 100644
index 9ba9108..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/AppConfiguration.props.tmpl
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <TargetName>{{projectName}}</TargetName>
-  </PropertyGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app/windows.tmpl/CMakeLists.txt.tmpl
new file mode 100644
index 0000000..7c0065f
--- /dev/null
+++ b/packages/flutter_tools/templates/app/windows.tmpl/CMakeLists.txt.tmpl
@@ -0,0 +1,95 @@
+cmake_minimum_required(VERSION 3.15)
+project({{projectName}} LANGUAGES CXX)
+
+set(BINARY_NAME "{{projectName}}")
+
+cmake_policy(SET CMP0063 NEW)
+
+set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
+
+# Configure build options.
+get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(IS_MULTICONFIG)
+  set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
+    CACHE STRING "" FORCE)
+else()
+  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    set(CMAKE_BUILD_TYPE "Debug" CACHE
+      STRING "Flutter build mode" FORCE)
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+      "Debug" "Profile" "Release")
+  endif()
+endif()
+
+set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
+
+# Use Unicode for all projects.
+add_definitions(-DUNICODE -D_UNICODE)
+
+# Compilation settings that should be applied to most targets.
+function(APPLY_STANDARD_SETTINGS TARGET)
+  target_compile_features(${TARGET} PUBLIC cxx_std_17)
+  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
+  target_compile_options(${TARGET} PRIVATE /EHsc)
+  target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
+  target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
+endfunction()
+
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
+
+# Flutter library and tool build rules.
+add_subdirectory(${FLUTTER_MANAGED_DIR})
+
+# Application build
+add_subdirectory("runner")
+
+# Generated plugin build rules, which manage building the plugins and adding
+# them to the application.
+include(flutter/generated_plugins.cmake)
+
+
+# === Installation ===
+# Support files are copied into place next to the executable, so that it can
+# run in place. This is done instead of making a separate bundle (as on Linux)
+# so that building and running from within Visual Studio will work.
+set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
+# Make the "install" step default, as it's required to run.
+set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
+endif()
+
+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
+
+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+  COMPONENT Runtime)
+
+if(PLUGIN_BUNDLED_LIBRARIES)
+  install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
+    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endif()
+
+# Fully re-copy the assets directory on each build to avoid having stale files
+# from a previous install.
+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
+install(CODE "
+  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
+  " COMPONENT Runtime)
+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
+  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
+
+# Install the AOT library on non-Debug builds only.
+install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  CONFIGURATIONS Profile;Release
+  COMPONENT Runtime)
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/FlutterBuild.vcxproj b/packages/flutter_tools/templates/app/windows.tmpl/FlutterBuild.vcxproj
deleted file mode 100644
index 8ef93f9..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/FlutterBuild.vcxproj
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Profile|x64">
-      <Configuration>Profile</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    <ProjectGuid>{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}</ProjectGuid>
-    <ProjectName>Flutter Build</ProjectName>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Label="Configuration">
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="flutter\ephemeral\Generated.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup />
-  <ItemDefinitionGroup>
-    <CustomBuildStep>
-      <Command>"$(ProjectDir)scripts\prepare_dependencies" $(Configuration)</Command>
-      <Message>Running Flutter backend build</Message>
-      <Outputs>force_to_run_every_time</Outputs>
-    </CustomBuildStep>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/Runner.sln b/packages/flutter_tools/templates/app/windows.tmpl/Runner.sln
deleted file mode 100644
index 00fb3d3..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/Runner.sln
+++ /dev/null
@@ -1,39 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29709.97
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{5A827760-CF8B-408A-99A3-B6C0AD2271E7}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Flutter Build", "FlutterBuild.vcxproj", "{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x64 = Debug|x64
-		Profile|x64 = Profile|x64
-		Release|x64 = Release|x64
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.ActiveCfg = Debug|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.Build.0 = Debug|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Profile|x64.ActiveCfg = Profile|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Profile|x64.Build.0 = Profile|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.ActiveCfg = Release|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.Build.0 = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.ActiveCfg = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.Build.0 = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.ActiveCfg = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.Build.0 = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.ActiveCfg = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.Build.0 = Release|x64
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {B8A69CB0-A974-4774-9EBD-1E5EECACD186}
-	EndGlobalSection
-EndGlobal
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.filters b/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.filters
deleted file mode 100644
index 761db86..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.filters
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Filter Include="Source Files">
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-    </Filter>
-    <Filter Include="Header Files">
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
-    </Filter>
-    <Filter Include="Resource Files">
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
-    </Filter>
-    <Filter Include="Source Files\Client Wrapper">
-      <UniqueIdentifier>{2761a4b5-57b2-4d50-a677-d20ddc17a7f1}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="runner\main.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="runner\run_loop.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="runner\flutter_window.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="runner\utils.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="runner\win32_window.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="runner\window_configuration.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="flutter\generated_plugin_registrant.cc">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc">
-      <Filter>Source Files\Client Wrapper</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\flutter_view_controller.cc">
-      <Filter>Source Files\Client Wrapper</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc">
-      <Filter>Source Files\Client Wrapper</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="runner\run_loop.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="runner\flutter_window.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="runner\utils.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="runner\win32_window.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="runner\window_configuration.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="runner\resource.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="flutter\generated_plugin_registrant.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <Manifest Include="runner.exe.manifest" />
-  </ItemGroup>
-  <ItemGroup>
-    <ResourceCompile Include="Runner.rc">
-      <Filter>Resource Files</Filter>
-    </ResourceCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <Image Include="resources\app_icon.ico">
-      <Filter>Resource Files</Filter>
-    </Image>
-  </ItemGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.tmpl b/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.tmpl
deleted file mode 100644
index 38a9213..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.tmpl
+++ /dev/null
@@ -1,262 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Profile|x64">
-      <Configuration>Profile</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    <ProjectGuid>{5A827760-CF8B-408A-99A3-B6C0AD2271E7}</ProjectGuid>
-    <RootNamespace>{{projectName}}</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="flutter\ephemeral\Generated.props" />
-    <Import Project="AppConfiguration.props" />
-    <Import Project="flutter\GeneratedPlugins.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="flutter\ephemeral\Generated.props" />
-    <Import Project="AppConfiguration.props" />
-    <Import Project="flutter\GeneratedPlugins.props" />
-  </ImportGroup>
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="flutter\ephemeral\Generated.props" />
-    <Import Project="AppConfiguration.props" />
-    <Import Project="flutter\GeneratedPlugins.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <OutDir>$(ProjectDir)..\build\windows\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
-    <IntDir>$(ProjectDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <OutDir>$(ProjectDir)..\build\windows\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
-    <IntDir>$(ProjectDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">
-    <OutDir>$(ProjectDir)..\build\windows\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
-    <IntDir>$(ProjectDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
-      <ConformanceMode>true</ConformanceMode>
-      <AdditionalIncludeDirectories>$(ProjectDir);$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_MBCS;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);$(OutDir)..\Plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <PreLinkEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreLinkEvent>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-    <CustomBuildStep>
-      <Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>Bundling dependencies</Message>
-      <Outputs>Dummy_Run_Always</Outputs>
-      <Inputs>
-      </Inputs>
-    </CustomBuildStep>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <ConformanceMode>true</ConformanceMode>
-      <AdditionalIncludeDirectories>$(ProjectDir);$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_MBCS;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);$(OutDir)..\Plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <PreLinkEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreLinkEvent>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-    <CustomBuildStep>
-      <Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>Bundling dependencies</Message>
-      <Outputs>Dummy_Run_Always</Outputs>
-      <Inputs>
-      </Inputs>
-    </CustomBuildStep>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">
-    <ClCompile>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <ConformanceMode>true</ConformanceMode>
-      <AdditionalIncludeDirectories>$(ProjectDir);$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_MBCS;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);$(OutDir)..\Plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <PreLinkEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreLinkEvent>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-    <CustomBuildStep>
-      <Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)" "$(Configuration)"</Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>Bundling dependencies</Message>
-      <Outputs>Dummy_Run_Always</Outputs>
-      <Inputs>
-      </Inputs>
-    </CustomBuildStep>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-    <ClCompile Include="runner\main.cpp" />
-    <ClCompile Include="flutter\generated_plugin_registrant.cc" />
-    <ClCompile Include="runner\run_loop.cpp" />
-    <ClCompile Include="runner\utils.cpp" />
-    <ClCompile Include="runner\window_configuration.cpp" />
-    <ClCompile Include="runner\win32_window.cpp" />
-    <ClCompile Include="runner\flutter_window.cpp" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\flutter_view_controller.cc" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="flutter\generated_plugin_registrant.h" />
-    <ClInclude Include="runner\resource.h" />
-    <ClInclude Include="runner\run_loop.h" />
-    <ClInclude Include="runner\utils.h" />
-    <ClInclude Include="runner\win32_window.h" />
-    <ClInclude Include="runner\flutter_window.h" />
-    <ClInclude Include="runner\window_configuration.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <Manifest Include="runner\runner.exe.manifest" />
-  </ItemGroup>
-  <ItemGroup>
-    <ResourceCompile Include="runner\Runner.rc" />
-  </ItemGroup>
-  <ItemGroup>
-    <Image Include="runner\resources\app_icon.ico" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-  <PropertyGroup>
-    <LocalDebuggerWorkingDirectory>$(SolutionDir)</LocalDebuggerWorkingDirectory>
-  </PropertyGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/flutter/.template_version b/packages/flutter_tools/templates/app/windows.tmpl/flutter/.template_version
index 00750ed..b8626c4 100644
--- a/packages/flutter_tools/templates/app/windows.tmpl/flutter/.template_version
+++ b/packages/flutter_tools/templates/app/windows.tmpl/flutter/.template_version
@@ -1 +1 @@
-3
+4
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/flutter/CMakeLists.txt b/packages/flutter_tools/templates/app/windows.tmpl/flutter/CMakeLists.txt
new file mode 100644
index 0000000..3c1726f
--- /dev/null
+++ b/packages/flutter_tools/templates/app/windows.tmpl/flutter/CMakeLists.txt
@@ -0,0 +1,98 @@
+cmake_minimum_required(VERSION 3.15)
+
+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
+
+# Configuration provided via flutter tool.
+include(${EPHEMERAL_DIR}/generated_config.cmake)
+
+# TODO: Move the rest of this into files in ephemeral. See
+# https://github.com/flutter/flutter/issues/57146.
+set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
+
+# === Flutter Library ===
+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
+
+# Published to parent scope for install step.
+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
+set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
+
+list(APPEND FLUTTER_LIBRARY_HEADERS
+  "flutter_export.h"
+  "flutter_windows.h"
+  "flutter_messenger.h"
+  "flutter_plugin_registrar.h"
+)
+list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
+add_library(flutter INTERFACE)
+target_include_directories(flutter INTERFACE
+  "${EPHEMERAL_DIR}"
+)
+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
+add_dependencies(flutter flutter_assemble)
+
+# === Wrapper ===
+list(APPEND CPP_WRAPPER_SOURCES_CORE
+  "engine_method_result.cc"
+	"standard_codec.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
+  "plugin_registrar.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_APP
+  "flutter_view_controller.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
+
+# Wrapper sources needed for a plugin.
+add_library(flutter_wrapper_plugin STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+)
+apply_standard_settings(flutter_wrapper_plugin)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  POSITION_INDEPENDENT_CODE ON)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
+target_include_directories(flutter_wrapper_plugin PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_plugin flutter_assemble)
+
+# Wrapper sources needed for the runner.
+add_library(flutter_wrapper_app STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
+apply_standard_settings(flutter_wrapper_app)
+target_link_libraries(flutter_wrapper_app PUBLIC flutter)
+target_include_directories(flutter_wrapper_app PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_app flutter_assemble)
+
+# === Flutter tool backend ===
+# _phony_ is a non-existent file to force this command to run every time,
+# since currently there's no way to get a full input/output list from the
+# flutter tool.
+add_custom_command(
+  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
+    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
+    ${CPP_WRAPPER_SOURCES_APP}
+    ${CMAKE_CURRENT_BINARY_DIR}/_phony_
+  COMMAND ${CMAKE_COMMAND} -E env
+    ${FLUTTER_TOOL_ENVIRONMENT}
+    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
+      windows-x64 $<CONFIG>
+)
+add_custom_target(flutter_assemble DEPENDS
+  "${FLUTTER_LIBRARY}"
+  ${FLUTTER_LIBRARY_HEADERS}
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/runner/CMakeLists.txt b/packages/flutter_tools/templates/app/windows.tmpl/runner/CMakeLists.txt
new file mode 100644
index 0000000..83e5acaa
--- /dev/null
+++ b/packages/flutter_tools/templates/app/windows.tmpl/runner/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.15)
+project(runner LANGUAGES CXX)
+
+add_executable(${BINARY_NAME} WIN32
+  "flutter_window.cpp"
+  "main.cpp"
+  "run_loop.cpp"
+  "utils.cpp"
+  "win32_window.cpp"
+  "window_configuration.cpp"
+  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
+  "Runner.rc"
+  "runner.exe.manifest"
+)
+apply_standard_settings(${BINARY_NAME})
+target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+add_dependencies(${BINARY_NAME} flutter_assemble)
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/scripts/bundle_assets_and_deps.bat b/packages/flutter_tools/templates/app/windows.tmpl/scripts/bundle_assets_and_deps.bat
deleted file mode 100644
index 9efa28f..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/scripts/bundle_assets_and_deps.bat
+++ /dev/null
@@ -1,44 +0,0 @@
-@echo off
-
-set FLUTTER_CACHE_DIR=%~1
-set BUNDLE_DIR=%~2
-set PLUGIN_DIR=%~3
-set EXE_NAME=%~4
-set BUILD_MODE=%~5
-
-set DATA_DIR=%BUNDLE_DIR%data
-
-if not exist "%DATA_DIR%" call mkdir "%DATA_DIR%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-
-:: Write the executable name to the location expected by the Flutter tool.
-echo %EXE_NAME%>"%FLUTTER_CACHE_DIR%exe_filename"
-
-:: Copy the Flutter assets to the data directory.
-set FLUTTER_BUILD_DIR=%~dp0..\..\build\
-set ASSET_DIR_NAME=flutter_assets
-set TARGET_ASSET_DIR=%DATA_DIR%\%ASSET_DIR_NAME%
-if exist "%TARGET_ASSET_DIR%" call rmdir /s /q "%TARGET_ASSET_DIR%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-call xcopy /s /e /i /q "%FLUTTER_BUILD_DIR%%ASSET_DIR_NAME%" "%TARGET_ASSET_DIR%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-
-:: Copy the icudtl.dat file from the Flutter tree to the data directory.
-call xcopy /y /d /q "%FLUTTER_CACHE_DIR%icudtl.dat" "%DATA_DIR%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-
-:: For non-debug modes, copy app.so into the data directory.
-if not %BUILD_MODE% == "Debug" (
-  call xcopy /y /d /q "%FLUTTER_BUILD_DIR%windows\app.so" "%DATA_DIR%"
-  if %errorlevel% neq 0 exit /b %errorlevel%
-)
-
-:: Copy the Flutter DLL to the target location.
-call xcopy /y /d /q "%FLUTTER_CACHE_DIR%flutter_windows.dll" "%BUNDLE_DIR%"
-if %errorlevel% neq 0 exit /b %errorlevel%
-
-:: Copy any Plugin DLLs to the target location.
-if exist "%PLUGIN_DIR%" (
-  call xcopy /y /d /q "%PLUGIN_DIR%"*.dll "%BUNDLE_DIR%"
-  if %errorlevel% neq 0 exit /b %errorlevel%
-)
diff --git a/packages/flutter_tools/templates/app/windows.tmpl/scripts/prepare_dependencies.bat b/packages/flutter_tools/templates/app/windows.tmpl/scripts/prepare_dependencies.bat
deleted file mode 100644
index d05238b..0000000
--- a/packages/flutter_tools/templates/app/windows.tmpl/scripts/prepare_dependencies.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@echo off
-
-:: Run flutter tool backend.
-set BUILD_MODE=%~1
-"%FLUTTER_ROOT%\packages\flutter_tools\bin\tool_backend" windows-x64 %BUILD_MODE%
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl
new file mode 100644
index 0000000..1399a82
--- /dev/null
+++ b/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.15)
+set(PROJECT_NAME "{{projectName}}")
+project(${PROJECT_NAME} LANGUAGES CXX)
+
+set(PLUGIN_NAME "${PROJECT_NAME}_plugin")
+
+add_library(${PLUGIN_NAME} SHARED
+  "${PLUGIN_NAME}.cpp"
+)
+apply_standard_settings(${PLUGIN_NAME})
+set_target_properties(${PLUGIN_NAME} PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
+target_include_directories(${PLUGIN_NAME} INTERFACE
+  "${CMAKE_CURRENT_SOURCE_DIR}/include")
+target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
+
+# List of absolute paths to libraries that should be bundled with the plugin
+set({{projectName}}_bundled_libraries
+  ""
+  PARENT_SCOPE
+)
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/PluginInfo.props.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/PluginInfo.props.tmpl
deleted file mode 100644
index 636a88b..0000000
--- a/packages/flutter_tools/templates/plugin/windows.tmpl/PluginInfo.props.tmpl
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ImportGroup Label="PropertySheets" />
-  <PropertyGroup Label="UserMacros">
-    <FlutterPluginName>{{projectName}}</FlutterPluginName>
-  </PropertyGroup>
-  <PropertyGroup />
-  <ItemDefinitionGroup />
-  <ItemGroup>
-    <BuildMacro Include="FlutterPluginName">
-      <Value>$(FlutterPluginName)</Value>
-    </BuildMacro>
-  </ItemGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.h.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/include/projectName.tmpl/projectName_plugin.h.tmpl
similarity index 89%
rename from packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.h.tmpl
rename to packages/flutter_tools/templates/plugin/windows.tmpl/include/projectName.tmpl/projectName_plugin.h.tmpl
index 35eef89..68c1a61 100644
--- a/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.h.tmpl
+++ b/packages/flutter_tools/templates/plugin/windows.tmpl/include/projectName.tmpl/projectName_plugin.h.tmpl
@@ -1,5 +1,5 @@
 #ifndef FLUTTER_PLUGIN_{{pluginClassCapitalSnakeCase}}_H_
-#defineFLUTTER_PLUGIN_{{pluginClassCapitalSnakeCase}}_H_
+#define FLUTTER_PLUGIN_{{pluginClassCapitalSnakeCase}}_H_
 
 #include <flutter_plugin_registrar.h>
 
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.filters b/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.filters
deleted file mode 100644
index 0f8c708..0000000
--- a/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.filters
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Filter Include="Source Files">
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-    </Filter>
-    <Filter Include="Header Files">
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
-    </Filter>
-    <Filter Include="Resource Files">
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
-    </Filter>
-    <Filter Include="Source Files\cpp_client_wrapper">
-      <UniqueIdentifier>{dbe2dac9-4a21-4849-bef5-2069d695609d}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="stdafx.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="targetver.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
-    <ClInclude Include="$(FlutterPluginName)_plugin.h">
-      <Filter>Source Files</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc">
-      <Filter>Source Files\cpp_client_wrapper</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\standard_codec.cc">
-      <Filter>Source Files\cpp_client_wrapper</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc">
-      <Filter>Source Files\cpp_client_wrapper</Filter>
-    </ClCompile>
-    <ClCompile Include="$(FlutterPluginName)_plugin.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-  </ItemGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.tmpl
deleted file mode 100644
index c9e56be..0000000
--- a/packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.tmpl
+++ /dev/null
@@ -1,247 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Profile|x64">
-      <Configuration>Profile</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    <ProjectGuid>{{{pluginProjectUUID}}}</ProjectGuid>
-    <Keyword>Win32Proj</Keyword>
-    <RootNamespace>{{projectName}}</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-    <ProjectName>{{projectName}}</ProjectName>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
-    <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)flutter\ephemeral\Generated.props" />
-    <Import Project="PluginInfo.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)flutter\ephemeral\Generated.props" />
-    <Import Project="PluginInfo.props" />
-  </ImportGroup>
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)flutter\ephemeral\Generated.props" />
-    <Import Project="PluginInfo.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <LinkIncremental>true</LinkIncremental>
-    <OutDir>$(SolutionDir)..\build\windows\$(Platform)\$(Configuration)\Plugins\</OutDir>
-    <IntDir>$(SolutionDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-    <CustomBuildBeforeTargets>
-    </CustomBuildBeforeTargets>
-    <TargetName>$(ProjectName)_plugin</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <LinkIncremental>false</LinkIncremental>
-    <OutDir>$(SolutionDir)..\build\windows\$(Platform)\$(Configuration)\Plugins\</OutDir>
-    <IntDir>$(SolutionDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-    <CustomBuildBeforeTargets>
-    </CustomBuildBeforeTargets>
-    <TargetName>$(ProjectName)_plugin</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">
-    <LinkIncremental>false</LinkIncremental>
-    <OutDir>$(SolutionDir)..\build\windows\$(Platform)\$(Configuration)\Plugins\</OutDir>
-    <IntDir>$(SolutionDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
-    <CustomBuildBeforeTargets />
-    <TargetName>$(ProjectName)_plugin</TargetName>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>_DEBUG;FLUTTER_PLUGIN_IMPL;_WINDOWS;_USRDLL;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ConformanceMode>true</ConformanceMode>
-      <ExceptionHandling>false</ExceptionHandling>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-      <AdditionalIncludeDirectories>$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <CustomBuildStep>
-      <Command>
-      </Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>
-      </Message>
-      <Outputs>
-      </Outputs>
-    </CustomBuildStep>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>NDEBUG;FLUTTER_PLUGIN_IMPL;_WINDOWS;_USRDLL;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ConformanceMode>true</ConformanceMode>
-      <ExceptionHandling>false</ExceptionHandling>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-      <AdditionalIncludeDirectories>$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <CustomBuildStep>
-      <Command>
-      </Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>
-      </Message>
-      <Outputs>
-      </Outputs>
-    </CustomBuildStep>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level4</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>NDEBUG;FLUTTER_PLUGIN_IMPL;_WINDOWS;_USRDLL;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ConformanceMode>true</ConformanceMode>
-      <ExceptionHandling>false</ExceptionHandling>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100</DisableSpecificWarnings>
-      <AdditionalIncludeDirectories>$(FLUTTER_EPHEMERAL_DIR);$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>flutter_windows.dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>$(FLUTTER_EPHEMERAL_DIR);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-    </Link>
-    <PreBuildEvent>
-      <Command>
-      </Command>
-      <Message>
-      </Message>
-    </PreBuildEvent>
-    <CustomBuildStep>
-      <Command>
-      </Command>
-    </CustomBuildStep>
-    <CustomBuildStep>
-      <Message>
-      </Message>
-      <Outputs>
-      </Outputs>
-    </CustomBuildStep>
-    <PostBuildEvent>
-      <Command>
-      </Command>
-    </PostBuildEvent>
-    <PostBuildEvent>
-      <Message>
-      </Message>
-    </PostBuildEvent>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-    <ClInclude Include="$(FlutterPluginName)_plugin.h" />
-    <ClInclude Include="stdafx.h" />
-    <ClInclude Include="targetver.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="$(FlutterPluginName)_plugin.cpp" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc" />
-    <ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\standard_codec.cc" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-</Project>
diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl
index 665c916..a2af158 100644
--- a/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl
+++ b/packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl
@@ -1,4 +1,4 @@
-#include "{{projectName}}_plugin.h"
+#include "include/{{projectName}}/{{projectName}}_plugin.h"
 
 // This must be included before many other Windows headers.
 #include <windows.h>
diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json
index cf8779c..cbd09dd 100644
--- a/packages/flutter_tools/templates/template_manifest.json
+++ b/packages/flutter_tools/templates/template_manifest.json
@@ -122,9 +122,10 @@
         "templates/app/web/index.html.tmpl",
         "templates/app/web/manifest.json.tmpl",
         "templates/app/windows.tmpl/.gitignore",
-        "templates/app/windows.tmpl/AppConfiguration.props.tmpl",
+        "templates/app/windows.tmpl/CMakeLists.txt.tmpl",
         "templates/app/windows.tmpl/flutter/.template_version",
-        "templates/app/windows.tmpl/FlutterBuild.vcxproj",
+        "templates/app/windows.tmpl/flutter/CMakeLists.txt",
+        "templates/app/windows.tmpl/runner/CMakeLists.txt",
         "templates/app/windows.tmpl/runner/flutter_window.cpp",
         "templates/app/windows.tmpl/runner/flutter_window.h",
         "templates/app/windows.tmpl/runner/main.cpp",
@@ -140,11 +141,6 @@
         "templates/app/windows.tmpl/runner/win32_window.h",
         "templates/app/windows.tmpl/runner/window_configuration.cpp.tmpl",
         "templates/app/windows.tmpl/runner/window_configuration.h",
-        "templates/app/windows.tmpl/Runner.sln",
-        "templates/app/windows.tmpl/Runner.vcxproj.filters",
-        "templates/app/windows.tmpl/Runner.vcxproj.tmpl",
-        "templates/app/windows.tmpl/scripts/bundle_assets_and_deps.bat",
-        "templates/app/windows.tmpl/scripts/prepare_dependencies.bat",
         "templates/cocoapods/Podfile-ios-objc",
         "templates/cocoapods/Podfile-ios-swift",
         "templates/cocoapods/Podfile-macos",
@@ -281,11 +277,9 @@
         "templates/plugin/README.md.tmpl",
         "templates/plugin/test/projectName_test.dart.tmpl",
         "templates/plugin/windows.tmpl/.gitignore",
-        "templates/plugin/windows.tmpl/plugin.vcxproj.filters",
-        "templates/plugin/windows.tmpl/plugin.vcxproj.tmpl",
-        "templates/plugin/windows.tmpl/PluginInfo.props.tmpl",
+        "templates/plugin/windows.tmpl/CMakeLists.txt.tmpl",
+        "templates/plugin/windows.tmpl/include/projectName.tmpl/projectName_plugin.h.tmpl",
         "templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl",
-        "templates/plugin/windows.tmpl/projectName_plugin.h.tmpl",
         "templates/plugin/lib/projectName_web.dart.tmpl"
     ]
-}
\ No newline at end of file
+}
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart
index 184a3b3..d6959a2 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart
@@ -9,10 +9,10 @@
 import 'package:flutter_tools/src/base/platform.dart';
 import 'package:flutter_tools/src/base/utils.dart';
 import 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/cmake.dart';
 import 'package:flutter_tools/src/commands/build.dart';
 import 'package:flutter_tools/src/commands/build_linux.dart';
 import 'package:flutter_tools/src/features.dart';
-import 'package:flutter_tools/src/linux/cmake.dart';
 import 'package:flutter_tools/src/project.dart';
 import 'package:process/process.dart';
 
@@ -267,7 +267,7 @@
     FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
   });
 
-  testUsingContext('Linux build configures Makefile exports', () async {
+  testUsingContext('Linux build configures CMake exports', () async {
     final BuildCommand command = BuildCommand();
     setUpMockProjectFilesForBuild();
     processManager = FakeProcessManager.list(<FakeCommand>[
@@ -305,8 +305,8 @@
     final List<String> configLines = cmakeConfig.readAsLinesSync();
 
     expect(configLines, containsAll(<String>[
-      'set(FLUTTER_ROOT "$_kTestFlutterRoot")',
-      'set(PROJECT_DIR "${fileSystem.currentDirectory.path}")',
+      'file(TO_CMAKE_PATH "$_kTestFlutterRoot" FLUTTER_ROOT)',
+      'file(TO_CMAKE_PATH "${fileSystem.currentDirectory.path}" PROJECT_DIR)',
       '  "DART_DEFINES=\\"foo.bar%3D2,fizz.far%3D3\\""',
       '  "DART_OBFUSCATION=\\"true\\""',
       '  "EXTRA_FRONT_END_OPTIONS=\\"--enable-experiment%3Dnon-nullable\\""',
@@ -314,8 +314,8 @@
       '  "SPLIT_DEBUG_INFO=\\"foo/\\""',
       '  "TRACK_WIDGET_CREATION=\\"true\\""',
       '  "TREE_SHAKE_ICONS=\\"true\\""',
-      '  "FLUTTER_ROOT=\\"\${FLUTTER_ROOT}\\""',
-      '  "PROJECT_DIR=\\"\${PROJECT_DIR}\\""',
+      '  "FLUTTER_ROOT=\\"$_kTestFlutterRoot\\""',
+      '  "PROJECT_DIR=\\"${fileSystem.currentDirectory.path}\\""',
       '  "FLUTTER_TARGET=\\"lib/other.dart\\""',
       '  "BUNDLE_SKSL_PATH=\\"foo/bar.sksl.json\\""',
     ]));
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
index 36bb208..e6fc64c 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart
@@ -9,12 +9,10 @@
 import 'package:flutter_tools/src/base/platform.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/commands/build_windows.dart';
-import 'package:flutter_tools/src/convert.dart';
 import 'package:flutter_tools/src/features.dart';
 import 'package:flutter_tools/src/windows/visual_studio.dart';
 import 'package:mockito/mockito.dart';
 import 'package:process/process.dart';
-import 'package:xml/xml.dart' as xml;
 
 import '../../src/common.dart';
 import '../../src/context.dart';
@@ -22,9 +20,9 @@
 import '../../src/testbed.dart';
 
 const String flutterRoot = r'C:\flutter';
-const String solutionPath = r'C:\windows\Runner.sln';
+const String buildFilePath = r'C:\windows\CMakeLists.txt';
 const String visualStudioPath = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community';
-const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat';
+const String cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe';
 
 final Platform windowsPlatform = FakePlatform(
   operatingSystem: 'windows',
@@ -43,8 +41,7 @@
 void main() {
   FileSystem fileSystem;
 
-  MockProcessManager mockProcessManager;
-  MockProcess mockProcess;
+  ProcessManager processManager;
   MockVisualStudio mockVisualStudio;
 
   setUpAll(() {
@@ -54,18 +51,7 @@
   setUp(() {
     fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
     Cache.flutterRoot = flutterRoot;
-    mockProcessManager = MockProcessManager();
-    mockProcess = MockProcess();
     mockVisualStudio = MockVisualStudio();
-    when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
-      return 0;
-    });
-    when(mockProcess.stderr).thenAnswer((Invocation invocation) {
-      return const Stream<List<int>>.empty();
-    });
-    when(mockProcess.stdout).thenAnswer((Invocation invocation) {
-      return Stream<List<int>>.fromIterable(<List<int>>[utf8.encode('STDOUT STUFF')]);
-    });
   });
 
   // Creates the mock files necessary to look like a Flutter project.
@@ -77,7 +63,7 @@
 
   // Creates the mock files necessary to run a build.
   void setUpMockProjectFilesForBuild({int templateVersion}) {
-    fileSystem.file(solutionPath).createSync(recursive: true);
+    fileSystem.file(buildFilePath).createSync(recursive: true);
     setUpMockCoreProjectFiles();
 
     final String versionFileSubpath = fileSystem.path.join('flutter', '.template_version');
@@ -101,6 +87,50 @@
     projectTemplateVersionFile.writeAsStringSync(templateVersion.toString());
   }
 
+  // Returns the command matching the build_windows call to generate CMake
+  // files.
+  FakeCommand cmakeGenerationCommand({void Function() onRun}) {
+    return FakeCommand(
+      command: <String>[
+        cmakePath,
+        '-S',
+        fileSystem.path.dirname(buildFilePath),
+        '-B',
+        r'build\windows',
+        '-G',
+        'Visual Studio 16 2019',
+      ],
+      onRun: onRun,
+    );
+  }
+
+  // Returns the command matching the build_windows call to build.
+  FakeCommand buildCommand(String buildMode, {
+    bool verbose = false,
+    void Function() onRun,
+    String stdout = '',
+  }) {
+    return FakeCommand(
+      command: <String>[
+        cmakePath,
+        '--build',
+        r'build\windows',
+        '--config',
+        buildMode,
+        '--target',
+        'INSTALL',
+        if (verbose)
+          '--verbose'
+      ],
+      environment: <String, String>{
+        if (verbose)
+          'VERBOSE_SCRIPT_LOGGING': 'true'
+      },
+      onRun: onRun,
+      stdout: stdout,
+    );
+  }
+
   testUsingContext('Windows build fails when there is no vcvars64.bat', () async {
     final BuildWindowsCommand command = BuildWindowsCommand()
       ..visualStudioOverride = mockVisualStudio;
@@ -122,7 +152,7 @@
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockCoreProjectFiles();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
     expect(createTestCommandRunner(command).run(
       const <String>['windows', '--no-pub']
@@ -139,7 +169,7 @@
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockProjectFilesForBuild();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
     expect(createTestCommandRunner(command).run(
       const <String>['windows', '--no-pub']
@@ -188,19 +218,14 @@
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockProjectFilesForBuild();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
-    when(mockProcessManager.start(<String>[
-        fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
-        vcvarsPath,
-        fileSystem.path.basename(solutionPath),
-        'Release',
-      ],
-      environment: <String, String>{},
-      workingDirectory: fileSystem.path.dirname(solutionPath))
-    ).thenAnswer((Invocation invocation) async {
-      return mockProcess;
-    });
+    processManager = FakeProcessManager.list(<FakeCommand>[
+      cmakeGenerationCommand(),
+      buildCommand('Release',
+        stdout: 'STDOUT STUFF',
+      ),
+    ]);
 
     await createTestCommandRunner(command).run(
       const <String>['windows', '--no-pub']
@@ -209,7 +234,7 @@
     expect(testLogger.traceText, contains('STDOUT STUFF'));
   }, overrides: <Type, Generator>{
     FileSystem: () => fileSystem,
-    ProcessManager: () => mockProcessManager,
+    ProcessManager: () => processManager,
     Platform: () => windowsPlatform,
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
@@ -219,21 +244,15 @@
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockProjectFilesForBuild();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
-    when(mockProcessManager.start(<String>[
-        fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
-        vcvarsPath,
-        fileSystem.path.basename(solutionPath),
-        'Release',
-      ],
-      environment: <String, String>{
-        'VERBOSE_SCRIPT_LOGGING': 'true',
-      },
-      workingDirectory: fileSystem.path.dirname(solutionPath))
-    ).thenAnswer((Invocation invocation) async {
-      return mockProcess;
-    });
+    processManager = FakeProcessManager.list(<FakeCommand>[
+      cmakeGenerationCommand(),
+      buildCommand('Release',
+        verbose: true,
+        stdout: 'STDOUT STUFF',
+      ),
+    ]);
 
     await createTestCommandRunner(command).run(
       const <String>['windows', '--no-pub', '-v']
@@ -242,29 +261,24 @@
     expect(testLogger.traceText, isNot(contains('STDOUT STUFF')));
   }, overrides: <Type, Generator>{
     FileSystem: () => fileSystem,
-    ProcessManager: () => mockProcessManager,
+    ProcessManager: () => processManager,
     Platform: () => windowsPlatform,
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
 
-  testUsingContext('Windows build invokes msbuild and writes generated files', () async {
+  testUsingContext('Windows build invokes build and writes generated files', () async {
     final BuildWindowsCommand command = BuildWindowsCommand()
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockProjectFilesForBuild();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
-    when(mockProcessManager.start(<String>[
-        fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
-        vcvarsPath,
-        fileSystem.path.basename(solutionPath),
-        'Release',
-      ],
-      environment: <String, String>{},
-      workingDirectory: fileSystem.path.dirname(solutionPath))
-    ).thenAnswer((Invocation invocation) async {
-      return mockProcess;
-    });
+    processManager = FakeProcessManager.list(<FakeCommand>[
+      cmakeGenerationCommand(),
+      buildCommand('Release'),
+    ]);
+    fileSystem.file(fileSystem.path.join('lib', 'other.dart'))
+      .createSync(recursive: true);
 
     await createTestCommandRunner(command).run(
       const <String>[
@@ -278,30 +292,40 @@
         '--dart-define=foo=a',
         '--dart-define=bar=b',
         r'--bundle-sksl-path=foo\bar.sksl.json',
-        r'--target=lib\main.dart',
+        r'--target=lib\other.dart',
       ]
     );
 
-    // Spot-check important elements from the properties file.
-    final File propsFile = fileSystem.file(r'C:\windows\flutter\ephemeral\Generated.props');
-    expect(propsFile, exists);
+    final File cmakeConfig = fileSystem.currentDirectory
+      .childDirectory('windows')
+      .childDirectory('flutter')
+      .childDirectory('ephemeral')
+      .childFile('generated_config.cmake');
 
-    final xml.XmlDocument props = xml.parse(propsFile.readAsStringSync());
-    expect(props.findAllElements('PropertyGroup').first.getAttribute('Label'), 'UserMacros');
-    expect(props.findAllElements('ItemGroup').length, 1);
-    expect(props.findAllElements('FLUTTER_ROOT').first.text, flutterRoot);
-    expect(props.findAllElements('TRACK_WIDGET_CREATION').first.text, 'true');
-    expect(props.findAllElements('TREE_SHAKE_ICONS').first.text, 'true');
-    expect(props.findAllElements('EXTRA_GEN_SNAPSHOT_OPTIONS').first.text, '--enable-experiment%3Dnon-nullable');
-    expect(props.findAllElements('EXTRA_FRONT_END_OPTIONS').first.text, '--enable-experiment%3Dnon-nullable');
-    expect(props.findAllElements('DART_DEFINES').first.text, 'foo%3Da,bar%3Db');
-    expect(props.findAllElements('DART_OBFUSCATION').first.text, 'true');
-    expect(props.findAllElements('SPLIT_DEBUG_INFO').first.text, r'C:\foo\');
-    expect(props.findAllElements('FLUTTER_TARGET').first.text, r'lib\main.dart');
-    expect(props.findAllElements('BUNDLE_SKSL_PATH').first.text, r'foo\bar.sksl.json');
+    expect(cmakeConfig, exists);
+
+    final List<String> configLines = cmakeConfig.readAsLinesSync();
+
+    // Backslashes are escaped in the file, which is why this uses both raw
+    // strings and double backslashes.
+    expect(configLines, containsAll(<String>[
+      r'file(TO_CMAKE_PATH "C:\\flutter" FLUTTER_ROOT)',
+      r'file(TO_CMAKE_PATH "C:\\" PROJECT_DIR)',
+      r'  "DART_DEFINES=\"foo%3Da,bar%3Db\""',
+      r'  "DART_OBFUSCATION=\"true\""',
+      r'  "EXTRA_FRONT_END_OPTIONS=\"--enable-experiment%3Dnon-nullable\""',
+      r'  "EXTRA_GEN_SNAPSHOT_OPTIONS=\"--enable-experiment%3Dnon-nullable\""',
+      r'  "SPLIT_DEBUG_INFO=\"C:\\foo\\\""',
+      r'  "TRACK_WIDGET_CREATION=\"true\""',
+      r'  "TREE_SHAKE_ICONS=\"true\""',
+      r'  "FLUTTER_ROOT=\"C:\\flutter\""',
+      r'  "PROJECT_DIR=\"C:\\\""',
+      r'  "FLUTTER_TARGET=\"lib\\other.dart\""',
+      r'  "BUNDLE_SKSL_PATH=\"foo\\bar.sksl.json\""',
+    ]));
   }, overrides: <Type, Generator>{
     FileSystem: () => fileSystem,
-    ProcessManager: () => mockProcessManager,
+    ProcessManager: () => processManager,
     Platform: () => windowsPlatform,
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
@@ -311,26 +335,19 @@
       ..visualStudioOverride = mockVisualStudio;
     applyMocksToCommand(command);
     setUpMockProjectFilesForBuild();
-    when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
+    when(mockVisualStudio.cmakePath).thenReturn(cmakePath);
 
-    when(mockProcessManager.start(<String>[
-        fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
-        vcvarsPath,
-        fileSystem.path.basename(solutionPath),
-        'Profile',
-      ],
-      environment: <String, String>{},
-      workingDirectory: fileSystem.path.dirname(solutionPath))
-    ).thenAnswer((Invocation invocation) async {
-      return mockProcess;
-    });
+    processManager = FakeProcessManager.list(<FakeCommand>[
+      cmakeGenerationCommand(),
+      buildCommand('Profile'),
+    ]);
 
     await createTestCommandRunner(command).run(
       const <String>['windows', '--profile', '--no-pub']
     );
   }, overrides: <Type, Generator>{
     FileSystem: () => fileSystem,
-    ProcessManager: () => mockProcessManager,
+    ProcessManager: () => processManager,
     Platform: () => windowsPlatform,
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart
index 2f52ae0..8f39a74 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart
@@ -777,7 +777,7 @@
 
     await runner.run(<String>['create', '--no-pub', projectDir.path]);
 
-    expect(projectDir.childDirectory('windows').childFile('Runner.sln').existsSync(), true);
+    expect(projectDir.childDirectory('windows').childFile('CMakeLists.txt').existsSync(), true);
   }, overrides: <Type, Generator>{
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
   });
@@ -792,7 +792,7 @@
 
     await runner.run(<String>['create', '--no-pub', projectDir.path]);
 
-    expect(projectDir.childDirectory('windows').childFile('Runner.sln').existsSync(), false);
+    expect(projectDir.childDirectory('windows').childFile('CMakeLists.txt').existsSync(), false);
   }, overrides: <Type, Generator>{
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: false),
   });
@@ -807,7 +807,7 @@
 
     await runner.run(<String>['create', '--no-pub', '--template=plugin', '--platforms=windows', projectDir.path]);
 
-    expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), true);
+    expect(projectDir.childDirectory('windows').childFile('CMakeLists.txt').existsSync(), true);
     expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), true);
     validatePubspecForPlugin(projectDir: projectDir.absolute.path, expectedPlatforms: const <String>[
       'windows'
@@ -827,7 +827,7 @@
 
     await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
 
-    expect(projectDir.childDirectory('windows').childFile('plugin.vcxproj').existsSync(), false);
+    expect(projectDir.childDirectory('windows').childFile('CMakeLists.txt').existsSync(), false);
     expect(projectDir.childDirectory('example').childDirectory('windows').existsSync(), false);
   }, overrides: <Type, Generator>{
     FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: false),
diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart
index 3710040..d155b36 100644
--- a/packages/flutter_tools/test/general.shard/plugins_test.dart
+++ b/packages/flutter_tools/test/general.shard/plugins_test.dart
@@ -80,10 +80,9 @@
       when(windowsProject.pluginConfigKey).thenReturn('windows');
       final Directory windowsManagedDirectory = flutterProject.directory.childDirectory('windows').childDirectory('flutter');
       when(windowsProject.managedDirectory).thenReturn(windowsManagedDirectory);
-      when(windowsProject.vcprojFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.vcxproj'));
-      when(windowsProject.solutionFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.sln'));
+      when(windowsProject.cmakeFile).thenReturn(windowsManagedDirectory.parent.childFile('CMakeLists.txt'));
+      when(windowsProject.generatedPluginCmakeFile).thenReturn(windowsManagedDirectory.childFile('generated_plugins.mk'));
       when(windowsProject.pluginSymlinkDirectory).thenReturn(windowsManagedDirectory.childDirectory('ephemeral').childDirectory('.plugin_symlinks'));
-      when(windowsProject.generatedPluginPropertySheetFile).thenReturn(windowsManagedDirectory.childFile('GeneratedPlugins.props'));
       when(windowsProject.existsSync()).thenReturn(false);
       linuxProject = MockLinuxProject();
       when(flutterProject.linux).thenReturn(linuxProject);
@@ -323,44 +322,6 @@
       project.podManifestLock.createSync(recursive: true);
     }
 
-    // Creates a Windows solution file sufficient to allow plugin injection
-    // to run without failing.
-    void createDummyWindowsSolutionFile() {
-      windowsProject.solutionFile.createSync(recursive: true);
-      // This isn't a valid solution file, but it's just enough to work with the
-      // plugin injection.
-      windowsProject.solutionFile.writeAsStringSync('''
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{3842E94C-E348-463A-ADBE-625A2B69B628}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-	EndGlobalSection
-EndGlobal''');
-    }
-
-    // Creates a Windows project file for dummyPackageDirectory sufficient to
-    // allow plugin injection to run without failing.
-    void createDummyPluginWindowsProjectFile() {
-      final File projectFile = dummyPackageDirectory
-        .parent
-        .childDirectory('windows')
-        .childFile('plugin.vcxproj');
-      projectFile.createSync(recursive: true);
-      // This isn't a valid project file, but it's just enough to work with the
-      // plugin injection.
-      projectFile.writeAsStringSync('''
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{5919689F-A5D5-462C-AF50-D405CCEF89B8}</ProjectGuid>'}
-    <ProjectName>apackage</ProjectName>
-  </PropertyGroup>
-</Project>''');
-    }
-
     group('refreshPlugins', () {
       testUsingContext('Refreshing the plugin list is a no-op when the plugins list stays empty', () async {
         await refreshPluginsList(flutterProject);
@@ -1051,8 +1012,6 @@
         when(featureFlags.isWindowsEnabled).thenReturn(true);
         when(flutterProject.isModule).thenReturn(false);
         configureDummyPackageAsPlugin();
-        createDummyWindowsSolutionFile();
-        createDummyPluginWindowsProjectFile();
 
         await injectPlugins(flutterProject, checkProjects: true);
 
@@ -1083,9 +1042,6 @@
         dartPluginClass: SomePlugin
     ''');
 
-        createDummyWindowsSolutionFile();
-        createDummyPluginWindowsProjectFile();
-
         await injectPlugins(flutterProject, checkProjects: true);
 
         final File registrantImpl = windowsProject.managedDirectory.childFile('generated_plugin_registrant.cc');
@@ -1114,9 +1070,6 @@
         dartPluginClass: SomePlugin
     ''');
 
-        createDummyWindowsSolutionFile();
-        createDummyPluginWindowsProjectFile();
-
         await injectPlugins(flutterProject, checkProjects: true);
 
         final File registrantImpl = windowsProject.managedDirectory.childFile('generated_plugin_registrant.cc');
@@ -1130,39 +1083,22 @@
         FeatureFlags: () => featureFlags,
       });
 
-      testUsingContext('Injecting creates generated Windows plugin properties', () async {
+      testUsingContext('Injecting creates generated Windows plugin CMake file', () async {
         when(windowsProject.existsSync()).thenReturn(true);
         when(featureFlags.isWindowsEnabled).thenReturn(true);
         when(flutterProject.isModule).thenReturn(false);
         configureDummyPackageAsPlugin();
-        createDummyWindowsSolutionFile();
-        createDummyPluginWindowsProjectFile();
 
         await injectPlugins(flutterProject, checkProjects: true);
 
-        final File properties = windowsProject.generatedPluginPropertySheetFile;
-        final String includePath = fs.path.join('flutter', 'ephemeral', '.plugin_symlinks', 'apackage', 'windows');
+        final File pluginMakefile = windowsProject.generatedPluginCmakeFile;
 
-        expect(properties.existsSync(), isTrue);
-        expect(properties.readAsStringSync(), contains('apackage_plugin.lib'));
-        expect(properties.readAsStringSync(), contains('>$includePath;'));
-      }, overrides: <Type, Generator>{
-        FileSystem: () => fs,
-        ProcessManager: () => FakeProcessManager.any(),
-        FeatureFlags: () => featureFlags,
-      });
-
-      testUsingContext('Injecting updates Windows solution file', () async {
-        when(windowsProject.existsSync()).thenReturn(true);
-        when(featureFlags.isWindowsEnabled).thenReturn(true);
-        when(flutterProject.isModule).thenReturn(false);
-        configureDummyPackageAsPlugin();
-        createDummyWindowsSolutionFile();
-        createDummyPluginWindowsProjectFile();
-
-        await injectPlugins(flutterProject, checkProjects: true);
-
-        expect(windowsProject.solutionFile.readAsStringSync(), contains(r'apackage\windows\plugin.vcxproj'));
+        expect(pluginMakefile.existsSync(), isTrue);
+        final String contents = pluginMakefile.readAsStringSync();
+        expect(contents, contains('apackage'));
+        expect(contents, contains('target_link_libraries(\${BINARY_NAME} PRIVATE \${plugin}_plugin)'));
+        expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \$<TARGET_FILE:\${plugin}_plugin>)'));
+        expect(contents, contains('list(APPEND PLUGIN_BUNDLED_LIBRARIES \${\${plugin}_bundled_libraries})'));
       }, overrides: <Type, Generator>{
         FileSystem: () => fs,
         ProcessManager: () => FakeProcessManager.any(),
diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart
index 21b8f35..52bc3d6 100644
--- a/packages/flutter_tools/test/general.shard/project_test.dart
+++ b/packages/flutter_tools/test/general.shard/project_test.dart
@@ -223,7 +223,7 @@
       });
       testUsingContext('injects plugins for Linux', () async {
         final FlutterProject project = await someProject();
-        project.linux.managedDirectory.createSync(recursive: true);
+        project.linux.cmakeFile.createSync(recursive: true);
         await project.ensureReadyForPlatformSpecificTooling();
         expectExists(project.linux.managedDirectory.childFile('generated_plugin_registrant.h'));
         expectExists(project.linux.managedDirectory.childFile('generated_plugin_registrant.cc'));
@@ -238,21 +238,7 @@
       });
       testUsingContext('injects plugins for Windows', () async {
         final FlutterProject project = await someProject();
-        project.windows.managedDirectory.createSync(recursive: true);
-        project.windows.solutionFile.createSync(recursive: true);
-        // Just enough solution file to allow injection to pass.
-        // TODO(stuartmorgan): Consider allowing injecting a mock solution util
-        // class into the test environment instead.
-        project.windows.solutionFile.writeAsStringSync('''
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{3842E94C-E348-463A-ADBE-625A2B69B628}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-	EndGlobalSection
-EndGlobal''');
+        project.windows.cmakeFile.createSync(recursive: true);
         await project.ensureReadyForPlatformSpecificTooling();
         expectExists(project.windows.managedDirectory.childFile('generated_plugin_registrant.h'));
         expectExists(project.windows.managedDirectory.childFile('generated_plugin_registrant.cc'));
diff --git a/packages/flutter_tools/test/general.shard/windows/property_sheet_test.dart b/packages/flutter_tools/test/general.shard/windows/property_sheet_test.dart
deleted file mode 100644
index 8b9fec2..0000000
--- a/packages/flutter_tools/test/general.shard/windows/property_sheet_test.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 'package:flutter_tools/src/windows/property_sheet.dart';
-
-import '../../src/common.dart';
-
-void main() {
-  group('Property Sheet', () {
-    test('Base file matches expected format', () async {
-      const String baseFile = '''
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ImportGroup Label="PropertySheets"/>
-  <PropertyGroup Label="UserMacros"/>
-  <PropertyGroup/>
-  <ItemDefinitionGroup/>
-  <ItemGroup/>
-</Project>''';
-      const PropertySheet sheet = PropertySheet();
-      expect(sheet.toString(), baseFile);
-    });
-
-    test('Environment variable generate the correct elements', () async {
-      const Map<String, String> environment = <String, String>{'FOO': 'Bar'};
-      const PropertySheet sheet = PropertySheet(environmentVariables: environment);
-      final String propsContent = sheet.toString();
-      expect(propsContent, contains('<FOO>Bar</FOO>'));
-      expect(propsContent, contains('''
-    <BuildMacro Include="FOO">
-      <Value>\$(FOO)</Value>
-      <EnvironmentVariable>true</EnvironmentVariable>
-    </BuildMacro>'''));
-    });
-
-    test('Include paths generate the correct elements', () async {
-      const PropertySheet sheet = PropertySheet(includePaths: <String>['foo/bar', 'baz']);
-      final String propsContent = sheet.toString();
-      expect(propsContent, contains('<AdditionalIncludeDirectories>foo/bar;baz;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>'));
-    });
-
-    test('Library dependencies generate the correct elements', () async {
-      const PropertySheet sheet = PropertySheet(libraryDependencies: <String>['foo.lib', 'bar.lib']);
-      final String propsContent = sheet.toString();
-      expect(propsContent, contains('<AdditionalDependencies>foo.lib;bar.lib;%(AdditionalDependencies)</AdditionalDependencies>'));
-    });
-  });
-}
diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_project_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_project_test.dart
deleted file mode 100644
index 47abaeb..0000000
--- a/packages/flutter_tools/test/general.shard/windows/visual_studio_project_test.dart
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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 'package:file/memory.dart';
-import 'package:file_testing/file_testing.dart';
-import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/windows/visual_studio_project.dart';
-
-import '../../src/common.dart';
-
-void main() {
-  group('Visual Studio Project', () {
-    String generateProjectContents({String guid, String name}) {
-      // A bare-bones project.
-      return '''
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    ${guid == null ? '' : '<ProjectGuid>{$guid}</ProjectGuid>'}
-    ${name == null ? '' : '<ProjectName>$name</ProjectName>'}
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Label="Configuration">
-    <PlatformToolset>v142</PlatformToolset>
-  </PropertyGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" />
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup />
-  <ItemDefinitionGroup />
-  <ItemGroup>
-  </ItemGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-</Project>''';
-    }
-
-    test('Property extraction works on a simple vcxproj', () async {
-      final FileSystem fileSystem = MemoryFileSystem();
-      const String guid = '017C4BAC-FEBA-406D-8A2C-3099FFE9D811';
-      const String name = 'Test';
-      final File projectFile = fileSystem.file('aproject.vcxproj');
-      projectFile.writeAsStringSync(generateProjectContents(guid: guid, name: name));
-
-      final VisualStudioProject project = VisualStudioProject(projectFile, fileSystem: fileSystem);
-      expect(project.formatUnderstood, true);
-      expect(project.guid, guid);
-      expect(project.name, name);
-    });
-
-    test('Missing GUID returns null', () async {
-      final FileSystem fileSystem = MemoryFileSystem();
-      final File projectFile = fileSystem.file('aproject.vcxproj');
-      projectFile.writeAsStringSync(generateProjectContents());
-
-      final VisualStudioProject project = VisualStudioProject(projectFile, fileSystem: fileSystem);
-      expect(project.formatUnderstood, true);
-      expect(project.guid, null);
-    });
-
-    test('Missing project name uses filename', () async {
-      final FileSystem fileSystem = MemoryFileSystem();
-      final File projectFile = fileSystem.file('aproject.vcxproj');
-      projectFile.writeAsStringSync(generateProjectContents());
-
-      final VisualStudioProject project = VisualStudioProject(projectFile, fileSystem: fileSystem);
-      expect(project.formatUnderstood, true);
-      expect(project.name, 'aproject');
-    });
-
-    test('Unknown file contents creates an object, and return false for formatUnderstood', () async {
-      final FileSystem fileSystem = MemoryFileSystem();
-      final File projectFile = fileSystem.file('aproject.vcxproj');
-      projectFile.writeAsStringSync('This is not XML!');
-
-      final VisualStudioProject project = VisualStudioProject(projectFile, fileSystem: fileSystem);
-      expect(project.formatUnderstood, false);
-    });
-
-    test('Missing project file throws on creation', () async {
-      final FileSystem fileSystem = MemoryFileSystem();
-      final File projectFile = fileSystem.file('aproject.vcxproj');
-
-      expect(() => VisualStudioProject(projectFile, fileSystem: fileSystem), throwsFileSystemException());
-    });
-  });
-}
diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_solution_utils_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_solution_utils_test.dart
deleted file mode 100644
index 2a0ea4f..0000000
--- a/packages/flutter_tools/test/general.shard/windows/visual_studio_solution_utils_test.dart
+++ /dev/null
@@ -1,454 +0,0 @@
-// 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 'package:file/memory.dart';
-import 'package:file_testing/file_testing.dart';
-import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/convert.dart';
-import 'package:flutter_tools/src/plugins.dart';
-import 'package:flutter_tools/src/platform_plugins.dart';
-import 'package:flutter_tools/src/project.dart';
-import 'package:flutter_tools/src/windows/visual_studio_solution_utils.dart';
-import 'package:mockito/mockito.dart';
-
-import '../../src/common.dart';
-
-void main() {
-  group('Visual Studio Solution Utils', () {
-    // Magic values; see visual_studio_solution_utils.dart.
-    const String solutionTypeGuidFolder = '2150E333-8FDC-42A3-9474-1A3956D46DE8';
-    const String solutionTypeGuidVcxproj = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942';
-    const String flutterPluginSolutionFolderGuid = '5C2E738A-1DD3-445A-AAC8-EEB9648DD07C';
-
-    // Arbitrary random GUIDs to use for fake plugins.
-    const String pluginAGuid = '9F200BC4-A747-43D1-8B72-B778F2C4D048';
-    const String pluginBGuid = '39AC79B8-28A6-4526-B5FF-9C83F59B3AF0';
-    const String pluginCGuid = '8E010714-28FF-416A-BC6F-9CDE336A02A7';
-    const String pluginDGuid = '304F1860-7E8B-4C99-8E1D-F5E55259F5C3';
-
-    FileSystem fileSystem;
-    MockWindowsProject project;
-
-    setUp(() async {
-      fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
-
-      project = MockWindowsProject();
-      when(project.pluginConfigKey).thenReturn('windows');
-      final Directory windowsManagedDirectory = fileSystem.directory('C:').childDirectory('windows').childDirectory('flutter');
-      when(project.solutionFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.sln'));
-      when(project.vcprojFile).thenReturn(windowsManagedDirectory.parent.childFile('Runner.vcxproj'));
-      when(project.pluginSymlinkDirectory).thenReturn(windowsManagedDirectory.childDirectory('ephemeral').childDirectory('.plugin_symlinks'));
-    });
-
-    // Returns a solution file contents for a solution without any plugins.
-    void writeSolutionWithoutPlugins() {
-      project.solutionFile.createSync(recursive: true);
-      project.solutionFile.writeAsStringSync('''
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29709.97
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{3842E94C-E348-463A-ADBE-625A2B69B628}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Flutter Build", "FlutterBuild.vcxproj", "{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x64 = Debug|x64
-		Profile|x64 = Profile|x64
-		Release|x64 = Release|x64
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Debug|x64.ActiveCfg = Debug|x64
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Debug|x64.Build.0 = Debug|x64
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Profile|x64.ActiveCfg = Profile|x64
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Profile|x64.Build.0 = Profile|x64
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Release|x64.ActiveCfg = Release|x64
-		{3842E94C-E348-463A-ADBE-625A2B69B628}.Release|x64.Build.0 = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.ActiveCfg = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.Build.0 = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.ActiveCfg = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.Build.0 = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.ActiveCfg = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.Build.0 = Release|x64
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {B8A69CB0-A974-4774-9EBD-1E5EECACD186}
-	EndGlobalSection
-EndGlobal''');
-    }
-
-    // Returns a solution file contents for a solution with plugins A, B, and C
-    // already added.
-    void writeSolutionWithPlugins() {
-      const String pluginSymlinkSubdirPath = r'Flutter\ephemeral\.plugin_symlinks';
-      const String pluginProjectSubpath = r'windows\plugin.vcxproj';
-      project.solutionFile.createSync(recursive: true);
-      project.solutionFile.writeAsStringSync('''
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29709.97
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{5A827760-CF8B-408A-99A3-B6C0AD2271E7}"
-	ProjectSection(ProjectDependencies) = postProject
-		{$pluginAGuid} = {$pluginAGuid}
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-		{$pluginBGuid} = {$pluginBGuid}
-		{$pluginCGuid} = {$pluginCGuid}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin_a", "$pluginSymlinkSubdirPath\\plugin_a\\$pluginProjectSubpath", "{$pluginAGuid}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Flutter Build", "FlutterBuild.vcxproj", "{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin_b", "$pluginSymlinkSubdirPath\\plugin_b\\$pluginProjectSubpath", "{$pluginBGuid}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin_c", "$pluginSymlinkSubdirPath\\plugin_c\\$pluginProjectSubpath", "{$pluginCGuid}"
-	ProjectSection(ProjectDependencies) = postProject
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
-	EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flutter Plugins", "Flutter Plugins", "{5C2E738A-1DD3-445A-AAC8-EEB9648DD07C}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x64 = Debug|x64
-		Profile|x64 = Profile|x64
-		Release|x64 = Release|x64
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.ActiveCfg = Debug|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.Build.0 = Debug|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Profile|x64.ActiveCfg = Profile|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Profile|x64.Build.0 = Profile|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.ActiveCfg = Release|x64
-		{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.Build.0 = Release|x64
-		{$pluginAGuid}.Debug|x64.ActiveCfg = Debug|x64
-		{$pluginAGuid}.Debug|x64.Build.0 = Debug|x64
-		{$pluginAGuid}.Profile|x64.ActiveCfg = Profile|x64
-		{$pluginAGuid}.Profile|x64.Build.0 = Profile|x64
-		{$pluginAGuid}.Release|x64.ActiveCfg = Release|x64
-		{$pluginAGuid}.Release|x64.Build.0 = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.ActiveCfg = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.Build.0 = Debug|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.ActiveCfg = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Profile|x64.Build.0 = Profile|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.ActiveCfg = Release|x64
-		{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.Build.0 = Release|x64
-		{$pluginBGuid}.Debug|x64.ActiveCfg = Debug|x64
-		{$pluginBGuid}.Debug|x64.Build.0 = Debug|x64
-		{$pluginBGuid}.Profile|x64.ActiveCfg = Profile|x64
-		{$pluginBGuid}.Profile|x64.Build.0 = Profile|x64
-		{$pluginBGuid}.Release|x64.ActiveCfg = Release|x64
-		{$pluginBGuid}.Release|x64.Build.0 = Release|x64
-		{$pluginCGuid}.Debug|x64.ActiveCfg = Debug|x64
-		{$pluginCGuid}.Debug|x64.Build.0 = Debug|x64
-		{$pluginCGuid}.Profile|x64.ActiveCfg = Profile|x64
-		{$pluginCGuid}.Profile|x64.Build.0 = Profile|x64
-		{$pluginCGuid}.Release|x64.ActiveCfg = Release|x64
-		{$pluginCGuid}.Release|x64.Build.0 = Release|x64
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(NestedProjects) = preSolution
-		{$pluginCGuid} = {$flutterPluginSolutionFolderGuid}
-		{$pluginBGuid} = {$flutterPluginSolutionFolderGuid}
-		{$pluginAGuid} = {$flutterPluginSolutionFolderGuid}
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {6C8A8041-10D8-4BEB-B73D-C02BCE62120B}
-	EndGlobalSection
-EndGlobal''');
-    }
-
-    void writeDummyPluginProject(String pluginName, String guid) {
-      final File pluginProjectFile = project.pluginSymlinkDirectory
-          .childDirectory(pluginName)
-          .childDirectory('windows')
-          .childFile('plugin.vcxproj');
-      pluginProjectFile.createSync(recursive: true);
-      pluginProjectFile.writeAsStringSync('''
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <VCProjectVersion>15.0</VCProjectVersion>
-    <ProjectGuid>{$guid}</ProjectGuid>
-    <ProjectName>$pluginName</ProjectName>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Label="Configuration">
-    <PlatformToolset>v142</PlatformToolset>
-  </PropertyGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" />
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup />
-  <ItemDefinitionGroup />
-  <ItemGroup>
-  </ItemGroup>
-  <Import Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-</Project>''');
-    }
-
-    // Configures and returns a mock plugin with the given name and GUID in the
-    // project's plugin symlink directory.
-    Plugin getMockPlugin(String name, String guid, {bool createProject = true}) {
-      final MockPlugin plugin = MockPlugin();
-      when(plugin.platforms).thenReturn(<String, PluginPlatform>{project.pluginConfigKey: null});
-      when(plugin.name).thenReturn(name);
-      when(plugin.path).thenReturn(project.pluginSymlinkDirectory.childDirectory(name).path);
-      if (createProject) {
-        writeDummyPluginProject(name, guid);
-      }
-      return plugin;
-    }
-
-    test('Adding the first plugin to a solution adds the expected references', () async {
-      writeSolutionWithoutPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-
-      // Check for:
-      // - Plugin project.
-      final String pluginSubpath = fileSystem.path.join('Flutter', 'ephemeral', '.plugin_symlinks', 'plugin_a', 'windows', 'plugin.vcxproj');
-      expect(newSolutionContents, contains('Project("{$solutionTypeGuidVcxproj}") = "plugin_a", "$pluginSubpath", "{$pluginAGuid}"'));
-      // - A dependency on the plugin project (from the Runner).
-      expect(newSolutionContents, contains('{$pluginAGuid} = {$pluginAGuid}'));
-      // - Plugin project configurations.
-      expect(newSolutionContents, contains('{$pluginAGuid}.Debug|x64.ActiveCfg = Debug|x64'));
-      expect(newSolutionContents, contains('{$pluginAGuid}.Debug|x64.Build.0 = Debug|x64'));
-      expect(newSolutionContents, contains('{$pluginAGuid}.Profile|x64.ActiveCfg = Profile|x64'));
-      expect(newSolutionContents, contains('{$pluginAGuid}.Profile|x64.Build.0 = Profile|x64'));
-      expect(newSolutionContents, contains('{$pluginAGuid}.Release|x64.ActiveCfg = Release|x64'));
-      expect(newSolutionContents, contains('{$pluginAGuid}.Release|x64.Build.0 = Release|x64'));
-      // - A plugin folder, and a child reference for the plugin.
-      expect(newSolutionContents, contains('Project("{$solutionTypeGuidFolder}") = "Flutter Plugins", "Flutter Plugins", "{$flutterPluginSolutionFolderGuid}"'));
-      expect(newSolutionContents, contains('{$pluginAGuid} = {$flutterPluginSolutionFolderGuid}'));
-    });
-
-    test('Removing a plugin removes entries as expected', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid),
-        getMockPlugin('plugin_c', pluginCGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-
-      // There should be no references to plugin B anywhere.
-      expect(newSolutionContents.contains(pluginBGuid), false);
-
-      // All the plugin A & C references should still be present in modified
-      // sections.
-      for (final String guid in <String>[pluginAGuid, pluginCGuid]) {
-        expect(newSolutionContents, contains('{$guid} = {$guid}'));
-        expect(newSolutionContents, contains('{$guid}.Debug|x64.ActiveCfg = Debug|x64'));
-        expect(newSolutionContents, contains('{$guid} = {$flutterPluginSolutionFolderGuid}'));
-      }
-    });
-
-    test('Removing all plugins works', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins( plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-
-      // There should be no references to any of the plugins.
-      expect(newSolutionContents.contains(pluginAGuid), false);
-      expect(newSolutionContents.contains(pluginBGuid), false);
-      expect(newSolutionContents.contains(pluginCGuid), false);
-      // Nor any plugins in the Flutter Plugins folder.
-      expect(newSolutionContents.contains('= {$flutterPluginSolutionFolderGuid}'), false);
-    });
-
-    test('Adjusting the plugin list by adding and removing adjusts entries as expected', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_b', pluginBGuid),
-        getMockPlugin('plugin_c', pluginCGuid),
-        getMockPlugin('plugin_d', pluginDGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-
-      // There should be no references to plugin A anywhere.
-      expect(newSolutionContents.contains(pluginAGuid), false);
-
-      // All the plugin B & C references should still be present in modified
-      // sections.
-      for (final String guid in <String>[pluginBGuid, pluginCGuid]) {
-        expect(newSolutionContents, contains('{$guid} = {$guid}'));
-        expect(newSolutionContents, contains('{$guid}.Debug|x64.ActiveCfg = Debug|x64'));
-        expect(newSolutionContents, contains('{$guid} = {$flutterPluginSolutionFolderGuid}'));
-      }
-
-      // All the plugin D values should be added:
-      // - Plugin project.
-      final String pluginSubpath = fileSystem.path.join('Flutter', 'ephemeral', '.plugin_symlinks', 'plugin_d', 'windows', 'plugin.vcxproj');
-      expect(newSolutionContents, contains('Project("{$solutionTypeGuidVcxproj}") = "plugin_d", "$pluginSubpath", "{$pluginDGuid}"'));
-      // - A dependency on the plugin project (from the Runner).
-      expect(newSolutionContents, contains('{$pluginDGuid} = {$pluginDGuid}'));
-      // - Plugin project configurations.
-      expect(newSolutionContents, contains('{$pluginDGuid}.Debug|x64.ActiveCfg = Debug|x64'));
-      expect(newSolutionContents, contains('{$pluginDGuid}.Debug|x64.Build.0 = Debug|x64'));
-      expect(newSolutionContents, contains('{$pluginDGuid}.Profile|x64.ActiveCfg = Profile|x64'));
-      expect(newSolutionContents, contains('{$pluginDGuid}.Profile|x64.Build.0 = Profile|x64'));
-      expect(newSolutionContents, contains('{$pluginDGuid}.Release|x64.ActiveCfg = Release|x64'));
-      expect(newSolutionContents, contains('{$pluginDGuid}.Release|x64.Build.0 = Release|x64'));
-      // - A child reference for the plugin in the Flutter Plugins folder.
-      expect(newSolutionContents, contains('{$pluginDGuid} = {$flutterPluginSolutionFolderGuid}'));
-    });
-
-    test('Adding plugins doesn\'t create duplicate entries', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid),
-        getMockPlugin('plugin_b', pluginBGuid),
-        getMockPlugin('plugin_c', pluginCGuid),
-        getMockPlugin('plugin_d', pluginDGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-      // There should only be:
-      // - one Flutter Plugins folder.
-      expect('Project("{$solutionTypeGuidFolder}")'.allMatches(newSolutionContents).length, 1);
-      // - one copy of plugin A's project.
-      expect('Project("{$solutionTypeGuidVcxproj}") = "plugin_a"'.allMatches(newSolutionContents).length, 1);
-      // - one copy of plugin A's configuration entries.
-      expect('{$pluginAGuid}.Debug|x64.ActiveCfg = Debug|x64'.allMatches(newSolutionContents).length, 1);
-      // - one dependency from the Runner to plugin A.
-      expect('{$pluginAGuid} = {$pluginAGuid}'.allMatches(newSolutionContents).length, 1);
-      // - one copy of plugin A in Flutter Plugins.
-      expect('{$pluginAGuid} = {$flutterPluginSolutionFolderGuid}'.allMatches(newSolutionContents).length, 1);
-    });
-
-    test('Adding plugins doesn\'t change ordering', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid),
-        getMockPlugin('plugin_b', pluginBGuid),
-        getMockPlugin('plugin_c', pluginCGuid),
-        getMockPlugin('plugin_d', pluginDGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-      // Plugin A should still be before Flutter Build in the Runner dependencies.
-      expect(newSolutionContents.indexOf('{$pluginAGuid} = {$pluginAGuid}'),
-          lessThan(newSolutionContents.indexOf('{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}')));
-      // ... and in the build configuration list.
-      expect(newSolutionContents.indexOf('{$pluginAGuid}.Debug|x64.ActiveCfg = Debug|x64'),
-          lessThan(newSolutionContents.indexOf('{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.ActiveCfg = Debug|x64')));
-      // And plugin C should still be before plugin A in the Flutter Plugins nesting list.
-      expect(newSolutionContents.indexOf('{$pluginCGuid} = {$flutterPluginSolutionFolderGuid}'),
-          lessThan(newSolutionContents.indexOf('{$pluginAGuid} = {$flutterPluginSolutionFolderGuid}')));
-    });
-
-    test('Updating solution preserves BOM', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      // Visual Studio expects sln files to start with a BOM.
-      final List<int> solutionStartingBytes = project.solutionFile.readAsBytesSync().take(3).toList();
-      final List<int> bomBytes = utf8.encode(String.fromCharCode(unicodeBomCharacterRune));
-      expect(solutionStartingBytes, bomBytes);
-    });
-
-    test('Updating solution dosen\'t introduce unexpected whitespace', () async {
-      writeSolutionWithPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid),
-        getMockPlugin('plugin_b', pluginBGuid),
-      ];
-      await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins);
-
-      final String newSolutionContents = project.solutionFile.readAsStringSync();
-      // Project, EndProject, Global, and EndGlobal should be at the start of
-      // lines.
-      expect(RegExp(r'^[ \t]+Project\(', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^[ \t]+EndProject\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^[ \t]+Global\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^[ \t]+EndGlobal\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-      // ProjectSection, GlobalSection, and their ends should be indented
-      // exactly one tab.
-      expect(RegExp(r'^([ \t]+\t|\t[ \t]+)ProjectSection\(', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^([ \t]+\t|\t[ \t]+)EndProjectSection\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^([ \t]+\t|\t[ \t]+)GlobalSection\(\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-      expect(RegExp(r'^([ \t]+\t|\t[ \t]+)EndGlobalSection\s*$', multiLine: true).hasMatch(newSolutionContents), false);
-    });
-
-    test('A plugin without a project exits without crashing', () async {
-      writeSolutionWithoutPlugins();
-
-      final List<Plugin> plugins = <Plugin>[
-        getMockPlugin('plugin_a', pluginAGuid, createProject: false),
-      ];
-      expect(() => VisualStudioSolutionUtils(project: project, fileSystem: fileSystem).updatePlugins(plugins),
-        throwsToolExit());
-    });
-
-    test('A Windows project with a missing Runner.sln file throws a ToolExit', () async {
-      final MockWindowsProject windowsProject = MockWindowsProject();
-      final File file = fileSystem.file('does_not_exist');
-
-      expect(file, isNot(exists));
-
-      when(windowsProject.solutionFile).thenReturn(file);
-
-      expect(() async => await VisualStudioSolutionUtils(project: project, fileSystem: fileSystem)
-        .updatePlugins(<Plugin>[]), throwsToolExit());
-    });
-  });
-}
-
-class MockWindowsProject extends Mock implements WindowsProject {}
-class MockPlugin extends Mock implements Plugin {}
diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
index 42b9b04..6eac769 100644
--- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
+++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
@@ -17,7 +17,7 @@
 
 const String programFilesPath = r'C:\Program Files (x86)';
 const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community';
-const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat';
+const String cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe';
 const String vswherePath = programFilesPath + r'\Microsoft Visual Studio\Installer\vswhere.exe';
 
 final Platform windowsPlatform = FakePlatform(
@@ -71,6 +71,7 @@
 const List<String> _requirements = <String>[
   'Microsoft.VisualStudio.Workload.NativeDesktop',
   'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+  'Microsoft.VisualStudio.Component.VC.CMake.Project',
 ];
 
 // Sets up the mock environment so that searching for Visual Studio with
@@ -85,7 +86,7 @@
   String responseOverride,
 ]) {
   fileSystem.file(vswherePath).createSync(recursive: true);
-  fileSystem.file(vcvarsPath).createSync(recursive: true);
+  fileSystem.file(cmakePath).createSync(recursive: true);
   final String finalResponse = responseOverride
     ?? json.encode(<Map<String, dynamic>>[response]);
   final List<String> requirementArguments = requiredComponents == null
@@ -249,7 +250,7 @@
       expect(visualStudio.isInstalled, false);
     });
 
-    testWithoutContext('vcvarsPath returns null when vswhere is missing', () {
+    testWithoutContext('cmakePath returns null when vswhere is missing', () {
       final MockProcessManager mockProcessManager = MockProcessManager();
       when(mockProcessManager.runSync(
         any,
@@ -265,7 +266,7 @@
         processManager: mockProcessManager,
       );
 
-      expect(visualStudio.vcvarsPath, isNull);
+      expect(visualStudio.cmakePath, isNull);
     });
 
     testWithoutContext(
@@ -587,7 +588,7 @@
       expect(visualStudio.hasNecessaryComponents, false);
     });
 
-    testWithoutContext('vcvarsPath returns null when VS is present but missing components', () {
+    testWithoutContext('cmakePath returns null when VS is present but missing components', () {
       final VisualStudioFixture fixture = setUpVisualStudio();
       final VisualStudio visualStudio = fixture.visualStudio;
 
@@ -607,10 +608,10 @@
         fixture.processManager,
       );
 
-      expect(visualStudio.vcvarsPath, isNull);
+      expect(visualStudio.cmakePath, isNull);
     });
 
-    testWithoutContext('vcvarsPath returns null when VS is present but with require components but installation is faulty', () {
+    testWithoutContext('cmakePath returns null when VS is present but with require components but installation is faulty', () {
       final VisualStudioFixture fixture = setUpVisualStudio();
       final VisualStudio visualStudio = fixture.visualStudio;
 
@@ -627,7 +628,7 @@
         fixture.processManager,
       );
 
-      expect(visualStudio.vcvarsPath, isNull);
+      expect(visualStudio.cmakePath, isNull);
     });
 
     testWithoutContext('hasNecessaryComponents returns false when VS is present with required components but installation is faulty', () {
@@ -676,7 +677,7 @@
       expect(visualStudio.fullVersion, equals('16.2.29306.81'));
     });
 
-    testWithoutContext('vcvarsPath returns null when VS is present but when vswhere returns invalid JSON', () {
+    testWithoutContext('cmakePath returns null when VS is present but when vswhere returns invalid JSON', () {
       final VisualStudioFixture fixture = setUpVisualStudio();
       final VisualStudio visualStudio = fixture.visualStudio;
 
@@ -696,7 +697,7 @@
         fixture.processManager,
       );
 
-      expect(visualStudio.vcvarsPath, isNull);
+      expect(visualStudio.cmakePath, isNull);
     });
 
     testWithoutContext('Everything returns good values when VS is present with all components', () {
@@ -722,7 +723,7 @@
       expect(visualStudio.isInstalled, true);
       expect(visualStudio.isAtLeastMinimumVersion, true);
       expect(visualStudio.hasNecessaryComponents, true);
-      expect(visualStudio.vcvarsPath, equals(vcvarsPath));
+      expect(visualStudio.cmakePath, equals(cmakePath));
     });
 
     testWithoutContext('Metadata is for compatible version when latest is missing components', () {
diff --git a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart
index 2641677..18f0f6b 100644
--- a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart
+++ b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart
@@ -71,7 +71,7 @@
       globals.fs.file('pubspec.yaml').createSync();
       globals.fs.file('.packages').createSync();
       globals.fs.directory('windows').createSync();
-      globals.fs.file(globals.fs.path.join('windows', 'Runner.sln')).createSync();
+      globals.fs.file(globals.fs.path.join('windows', 'CMakeLists.txt')).createSync();
       final FlutterProject flutterProject = FlutterProject.current();
 
       expect(WindowsDevice().isSupportedForProject(flutterProject), true);
@@ -91,7 +91,7 @@
       ProcessManager: () => FakeProcessManager.any(),
     });
 
-    testUsingContext('isSupportedForProject is false with no Runner.sln', () async {
+    testUsingContext('isSupportedForProject is false with no build file', () async {
       globals.fs.file('pubspec.yaml').createSync();
       globals.fs.file('.packages').createSync();
       globals.fs.directory('windows').createSync();