Remove need for build/name scripts on Linux desktop (#31567)

diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index d0ad3d6..6db4f0e 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -392,6 +392,11 @@
   return fs.path.join(getBuildDirectory(), 'web');
 }
 
+/// Returns the linux build output directory.
+String getLinuxBuildDirectory() {
+  return fs.path.join(getBuildDirectory(), 'linux');
+}
+
 /// Returns directory used by incremental compiler (IKG - incremental kernel
 /// generator) to store cached intermediate state.
 String getIncrementalCompilerByteStoreDirectory() {
diff --git a/packages/flutter_tools/lib/src/linux/application_package.dart b/packages/flutter_tools/lib/src/linux/application_package.dart
index 7bf5c6a..83d2e62 100644
--- a/packages/flutter_tools/lib/src/linux/application_package.dart
+++ b/packages/flutter_tools/lib/src/linux/application_package.dart
@@ -5,12 +5,10 @@
 import 'package:meta/meta.dart';
 
 import '../application_package.dart';
-import '../base/common.dart';
 import '../base/file_system.dart';
-import '../base/io.dart';
-import '../base/process_manager.dart';
 import '../build_info.dart';
 import '../project.dart';
+import 'makefile.dart';
 
 abstract class LinuxApp extends ApplicationPackage {
   LinuxApp({@required String projectBundleId}) : super(id: projectBundleId);
@@ -59,14 +57,12 @@
 
   @override
   String executable(BuildMode buildMode) {
-    final ProcessResult result = processManager.runSync(<String>[
-      project.nameScript.path,
-      buildMode == BuildMode.debug ? 'debug' : 'release',
-    ]);
-    if (result.exitCode != 0) {
-      throwToolExit('Failed to find Linux project name');
+    final String binaryName = makefileExecutableName(project);
+    if (buildMode == BuildMode.debug) {
+      return fs.path.join(getLinuxBuildDirectory(), 'debug', binaryName);
+    } else {
+      return fs.path.join(getLinuxBuildDirectory(), 'release', binaryName);
     }
-    return result.stdout.toString().trim();
   }
 
   @override
diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart
index 465259e..c71d11a 100644
--- a/packages/flutter_tools/lib/src/linux/build_linux.dart
+++ b/packages/flutter_tools/lib/src/linux/build_linux.dart
@@ -12,13 +12,22 @@
 import '../globals.dart';
 import '../project.dart';
 
-/// Builds the Linux project through the project shell script.
+/// Builds the Linux project through the Makefile.
 Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo) async {
+  /// Cache flutter root in linux directory.
+  linuxProject.editableHostAppDirectory.childFile('.generated_flutter_root')
+    ..createSync(recursive: true)
+    ..writeAsStringSync(Cache.flutterRoot);
+
+  final String buildFlag = buildInfo?.isDebug == true ? 'debug' : 'release';
+  final String bundleFlags = buildInfo?.trackWidgetCreation == true ? '--track-widget-creation' : '';
   final Process process = await processManager.start(<String>[
-    linuxProject.buildScript.path,
-    Cache.flutterRoot,
-    buildInfo?.isDebug == true ? 'debug' : 'release',
-    buildInfo?.trackWidgetCreation == true ? 'track-widget-creation' : 'no-track-widget-creation',
+    'make',
+    '-C',
+    linuxProject.editableHostAppDirectory.path,
+    'BUILD=$buildFlag',
+    'FLUTTER_ROOT=${Cache.flutterRoot}',
+    'FLUTTER_BUNDLE_FLAGS=$bundleFlags',
   ], runInShell: true);
   final Status status = logger.startProgress(
     'Building Linux application...',
diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart
index 9fa2065..d98afc4 100644
--- a/packages/flutter_tools/lib/src/linux/linux_device.dart
+++ b/packages/flutter_tools/lib/src/linux/linux_device.dart
@@ -71,6 +71,7 @@
     bool usesTerminalUi = true,
     bool ipv6 = false,
   }) async {
+    _lastBuiltMode = debuggingOptions.buildInfo.mode;
     if (!prebuiltApplication) {
       await buildLinux((await FlutterProject.current()).linux, debuggingOptions.buildInfo);
     }
@@ -96,8 +97,7 @@
 
   @override
   Future<bool> stopApp(covariant LinuxApp app) async {
-    // Assume debug for now.
-    return killProcess(app.executable(BuildMode.debug));
+    return killProcess(app.executable(_lastBuiltMode));
   }
 
   @override
@@ -107,6 +107,9 @@
   // to uninstall the application.
   @override
   Future<bool> uninstallApp(ApplicationPackage app) async => true;
+
+  // Track the last built mode from startApp.
+  BuildMode _lastBuiltMode;
 }
 
 class LinuxDevices extends PollingDeviceDiscovery {
diff --git a/packages/flutter_tools/lib/src/linux/makefile.dart b/packages/flutter_tools/lib/src/linux/makefile.dart
new file mode 100644
index 0000000..f42330d
--- /dev/null
+++ b/packages/flutter_tools/lib/src/linux/makefile.dart
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium 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 '../project.dart';
+
+// The setting that controls the executable name in the linux makefile.
+const String _kBinaryNameVariable = 'BINARY_NAME=';
+
+/// Extracts the `BINARY_NAME` from a linux project Makefile.
+///
+/// Returns `null` if it cannot be found.
+String makefileExecutableName(LinuxProject project) {
+  for (String line in project.makeFile.readAsLinesSync()) {
+    if (line.startsWith(_kBinaryNameVariable)) {
+      return line.split(_kBinaryNameVariable).last.trim();
+    }
+  }
+  return null;
+}
\ No newline at end of file
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 307eaf1..641c281 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -584,11 +584,10 @@
 
   final FlutterProject project;
 
-  bool existsSync() => project.directory.childDirectory('linux').existsSync();
+  Directory get editableHostAppDirectory => project.directory.childDirectory('linux');
 
-  // Note: The build script file exists as a temporary shim.
-  File get buildScript => project.directory.childDirectory('linux').childFile('build.sh');
+  bool existsSync() => editableHostAppDirectory.existsSync();
 
-  // Note: The name script file exists as a temporary shim.
-  File get nameScript => project.directory.childDirectory('linux').childFile('name_output.sh');
+  /// The Linux project makefile.
+  File get makeFile => editableHostAppDirectory.childFile('Makefile');
 }
\ No newline at end of file
diff --git a/packages/flutter_tools/test/commands/build_linux_test.dart b/packages/flutter_tools/test/commands/build_linux_test.dart
index 4dd5a46..adbc146 100644
--- a/packages/flutter_tools/test/commands/build_linux_test.dart
+++ b/packages/flutter_tools/test/commands/build_linux_test.dart
@@ -9,6 +9,8 @@
 import 'package:flutter_tools/src/base/platform.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/commands/build.dart';
+import 'package:flutter_tools/src/linux/makefile.dart';
+import 'package:flutter_tools/src/project.dart';
 import 'package:mockito/mockito.dart';
 import 'package:process/process.dart';
 
@@ -62,17 +64,19 @@
     FileSystem: () => memoryFilesystem,
   });
 
-  testUsingContext('Linux build invokes build script', () async {
+  testUsingContext('Linux build invokes make', () async {
     final BuildCommand command = BuildCommand();
     applyMocksToCommand(command);
     fs.file('linux/build.sh').createSync(recursive: true);
     fs.file('pubspec.yaml').createSync();
     fs.file('.packages').createSync();
     when(mockProcessManager.start(<String>[
-      '/linux/build.sh',
-      '/',
-      'release',
-      'no-track-widget-creation',
+      'make',
+      '-C',
+      '/linux',
+      'BUILD=release',
+      'FLUTTER_ROOT=/',
+      'FLUTTER_BUNDLE_FLAGS=',
     ], runInShell: true)).thenAnswer((Invocation invocation) async {
       return mockProcess;
     });
@@ -85,6 +89,21 @@
     ProcessManager: () => mockProcessManager,
     Platform: () => linuxPlatform,
   });
+
+  testUsingContext('linux can extract binary name from Makefile', () async {
+    fs.file('linux/Makefile')
+      ..createSync(recursive: true)
+      ..writeAsStringSync(r'''
+# Comment
+SOMETHING_ELSE=FOO
+BINARY_NAME=fizz_bar
+''');
+    fs.file('pubspec.yaml').createSync();
+    fs.file('.packages').createSync();
+    final FlutterProject flutterProject = await FlutterProject.current();
+
+    expect(makefileExecutableName(flutterProject.linux), 'fizz_bar');
+  }, overrides: <Type, Generator>{FileSystem: () => MemoryFileSystem()});
 }
 
 class MockProcessManager extends Mock implements ProcessManager {}