Add an ephemeral directory to Windows projects (#40194)

Moves files generated in windows/flutter/ as part of the build to an ephemeral/ subdirectory, matching the approach used on macOS (and in the future, Windows).

Adds that directory to the generated properties file to minimize hard-coding of paths in the project.
diff --git a/packages/flutter_tools/bin/tool_backend.dart b/packages/flutter_tools/bin/tool_backend.dart
index 09de95b..3a247d8 100644
--- a/packages/flutter_tools/bin/tool_backend.dart
+++ b/packages/flutter_tools/bin/tool_backend.dart
@@ -40,7 +40,7 @@
       cacheDirectory = 'linux/flutter';
       break;
     case 'windows-x64':
-      cacheDirectory = 'windows/flutter';
+      cacheDirectory = 'windows/flutter/ephemeral';
       break;
     default:
       stderr.write('Unsupported target platform $targetPlatform');
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index e53d187..8322ab8 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -752,11 +752,19 @@
 
   Directory get _editableDirectory => project.directory.childDirectory('windows');
 
-  Directory get _cacheDirectory => _editableDirectory.childDirectory('flutter');
+  /// The directory in the project that is managed by Flutter. As much as
+  /// possible, files that are edited by Flutter tooling after initial project
+  /// creation should live here.
+  Directory get managedDirectory => _editableDirectory.childDirectory('flutter');
+
+  /// The subdirectory of [managedDirectory] that contains files that are
+  /// generated on the fly. All generated files that are not intended to be
+  /// 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 => _cacheDirectory.childFile('Generated.props');
+  File get generatedPropertySheetFile => ephemeralDirectory.childFile('Generated.props');
 
   // The MSBuild project file.
   File get vcprojFile => _editableDirectory.childFile('Runner.vcxproj');
@@ -767,7 +775,7 @@
   /// 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 => _cacheDirectory.childFile('exe_filename');
+  File get nameFile => ephemeralDirectory.childFile('exe_filename');
 }
 
 /// The Linux sub project.
@@ -778,6 +786,8 @@
 
   Directory get editableHostAppDirectory => project.directory.childDirectory('linux');
 
+  // TODO(stuartmorgan): Move to using an ephemeralDirectory to match the other
+  // desktop projects.
   Directory get cacheDirectory => editableHostAppDirectory.childDirectory('flutter');
 
   bool existsSync() => editableHostAppDirectory.existsSync();
diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart
index 0c51060..7f2f41f 100644
--- a/packages/flutter_tools/lib/src/windows/build_windows.dart
+++ b/packages/flutter_tools/lib/src/windows/build_windows.dart
@@ -22,6 +22,7 @@
 Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {String target}) async {
   final Map<String, String> environment = <String, String>{
     'FLUTTER_ROOT': Cache.flutterRoot,
+    'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path,
     'PROJECT_DIR': windowsProject.project.directory.path,
     'TRACK_WIDGET_CREATION': (buildInfo?.trackWidgetCreation == true).toString(),
   };
diff --git a/packages/flutter_tools/test/general.shard/commands/build_windows_test.dart b/packages/flutter_tools/test/general.shard/commands/build_windows_test.dart
index 344c0be..508db29 100644
--- a/packages/flutter_tools/test/general.shard/commands/build_windows_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/build_windows_test.dart
@@ -129,7 +129,7 @@
     );
 
     // Spot-check important elements from the properties file.
-    final File propsFile = fs.file(r'C:\windows\flutter\Generated.props');
+    final File propsFile = fs.file(r'C:\windows\flutter\ephemeral\Generated.props');
     expect(propsFile.existsSync(), true);
     final xml.XmlDocument props = xml.parse(propsFile.readAsStringSync());
     expect(props.findAllElements('PropertyGroup').first.getAttribute('Label'), 'UserMacros');