forked from firka/flutter
Generate a makefile for Linux plugins (#51520)
When generating the plugin registrant for Linux, also generate a makefile that can be included in the app-level Makefile to manage all of the plugin targets and flags, exporting them in a few known variables for use in the outer makefile. Part of #32720
This commit is contained in:
@@ -801,6 +801,40 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
}
|
||||
''';
|
||||
|
||||
const String _linuxPluginMakefileTemplate = '''
|
||||
# Plugins to include in the build.
|
||||
GENERATED_PLUGINS=\\
|
||||
{{#plugins}}
|
||||
\t{{name}} \\
|
||||
{{/plugins}}
|
||||
|
||||
GENERATED_PLUGINS_DIR={{pluginsDir}}
|
||||
# A plugin library name plugin name with _plugin appended.
|
||||
GENERATED_PLUGIN_LIB_NAMES=\$(foreach plugin,\$(GENERATED_PLUGINS),\$(plugin)_plugin)
|
||||
|
||||
# Variables for use in the enclosing Makefile. Changes to these names are
|
||||
# breaking changes.
|
||||
PLUGIN_TARGETS=\$(GENERATED_PLUGINS)
|
||||
PLUGIN_LIBRARIES=\$(foreach plugin,\$(GENERATED_PLUGIN_LIB_NAMES),\\
|
||||
\t\$(OUT_DIR)/lib\$(plugin).so)
|
||||
PLUGIN_LDFLAGS=\$(patsubst %,-l%,\$(GENERATED_PLUGIN_LIB_NAMES))
|
||||
PLUGIN_CPPFLAGS=\$(foreach plugin,\$(GENERATED_PLUGINS),\\
|
||||
\t-I\$(GENERATED_PLUGINS_DIR)/\$(plugin)/linux)
|
||||
|
||||
# Targets
|
||||
|
||||
# Implicit rules don't match phony targets, so list plugin builds explicitly.
|
||||
{{#plugins}}
|
||||
\$(OUT_DIR)/lib{{name}}_plugin.so: | {{name}}
|
||||
{{/plugins}}
|
||||
|
||||
.PHONY: \$(GENERATED_PLUGINS)
|
||||
\$(GENERATED_PLUGINS):
|
||||
make -C \$(GENERATED_PLUGINS_DIR)/\$@/linux \\
|
||||
OUT_DIR=\$(OUT_DIR) \\
|
||||
FLUTTER_EPHEMERAL_DIR="\$(abspath {{ephemeralDir}})"
|
||||
''';
|
||||
|
||||
Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> iosPlugins = _extractPlatformMaps(plugins, IOSPlugin.kConfigKey);
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
@@ -841,12 +875,34 @@ Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plug
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _writeLinuxPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
Future<void> _writeLinuxPluginFiles(FlutterProject project, List<Plugin> plugins) async {
|
||||
final List<Map<String, dynamic>> linuxPlugins = _extractPlatformMaps(plugins, LinuxPlugin.kConfigKey);
|
||||
// The generated makefile is checked in, so can't use absolute paths. It is
|
||||
// included by the main makefile, so relative paths must be relative to that
|
||||
// file's directory.
|
||||
final String makefileDirPath = project.linux.makeFile.parent.absolute.path;
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': linuxPlugins,
|
||||
'ephemeralDir': globals.fs.path.relative(
|
||||
project.linux.ephemeralDirectory.absolute.path,
|
||||
from: makefileDirPath,
|
||||
),
|
||||
'pluginsDir': globals.fs.path.relative(
|
||||
project.linux.pluginSymlinkDirectory.absolute.path,
|
||||
from: makefileDirPath,
|
||||
),
|
||||
};
|
||||
await _writeCppPluginRegistrant(project.linux.managedDirectory, context);
|
||||
await _writeLinuxPluginMakefile(project.linux.managedDirectory, context);
|
||||
}
|
||||
|
||||
Future<void> _writeLinuxPluginMakefile(Directory destination, Map<String, dynamic> templateContext) async {
|
||||
final String registryDirectory = destination.path;
|
||||
_renderTemplateToFile(
|
||||
_linuxPluginMakefileTemplate,
|
||||
templateContext,
|
||||
globals.fs.path.join(registryDirectory, 'generated_plugins.mk'),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _writeMacOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
|
||||
@@ -1034,7 +1090,7 @@ Future<void> injectPlugins(FlutterProject project, {bool checkProjects = false})
|
||||
// desktop in existing projects are in place. For now, ignore checkProjects
|
||||
// on desktop and always treat it as true.
|
||||
if (featureFlags.isLinuxEnabled && project.linux.existsSync()) {
|
||||
await _writeLinuxPluginRegistrant(project, plugins);
|
||||
await _writeLinuxPluginFiles(project, plugins);
|
||||
}
|
||||
if (featureFlags.isMacOSEnabled && project.macos.existsSync()) {
|
||||
await _writeMacOSPluginRegistrant(project, plugins);
|
||||
|
||||
@@ -1003,6 +1003,9 @@ class LinuxProject extends FlutterProjectPlatform {
|
||||
/// the build.
|
||||
File get generatedMakeConfigFile => ephemeralDirectory.childFile('generated_config.mk');
|
||||
|
||||
/// Makefile with rules and variables for plugin builds.
|
||||
File get generatedPluginMakeFile => managedDirectory.childFile('generated_plugins.mk');
|
||||
|
||||
/// The directory to write plugin symlinks.
|
||||
Directory get pluginSymlinkDirectory => ephemeralDirectory.childDirectory('.plugin_symlinks');
|
||||
|
||||
|
||||
@@ -83,7 +83,13 @@ void main() {
|
||||
linuxProject = MockLinuxProject();
|
||||
when(flutterProject.linux).thenReturn(linuxProject);
|
||||
when(linuxProject.pluginConfigKey).thenReturn('linux');
|
||||
when(linuxProject.pluginSymlinkDirectory).thenReturn(flutterProject.directory.childDirectory('linux').childDirectory('symlinks'));
|
||||
final Directory linuxManagedDirectory = flutterProject.directory.childDirectory('linux').childDirectory('flutter');
|
||||
final Directory linuxEphemeralDirectory = linuxManagedDirectory.childDirectory('ephemeral');
|
||||
when(linuxProject.managedDirectory).thenReturn(linuxManagedDirectory);
|
||||
when(linuxProject.ephemeralDirectory).thenReturn(linuxEphemeralDirectory);
|
||||
when(linuxProject.pluginSymlinkDirectory).thenReturn(linuxEphemeralDirectory.childDirectory('.plugin_symlinks'));
|
||||
when(linuxProject.makeFile).thenReturn(linuxManagedDirectory.parent.childFile('Makefile'));
|
||||
when(linuxProject.generatedPluginMakeFile).thenReturn(linuxManagedDirectory.childFile('generated_plugins.mk'));
|
||||
when(linuxProject.existsSync()).thenReturn(false);
|
||||
|
||||
when(mockClock.now()).thenAnswer(
|
||||
@@ -871,6 +877,51 @@ web_plugin_with_nested:${webPluginWithNestedFile.childDirectory('lib').uri.toStr
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Injecting creates generated Linux registrant', () async {
|
||||
when(linuxProject.existsSync()).thenReturn(true);
|
||||
when(featureFlags.isLinuxEnabled).thenReturn(true);
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
configureDummyPackageAsPlugin();
|
||||
|
||||
await injectPlugins(flutterProject, checkProjects: true);
|
||||
|
||||
final File registrantHeader = linuxProject.managedDirectory.childFile('generated_plugin_registrant.h');
|
||||
final File registrantImpl = linuxProject.managedDirectory.childFile('generated_plugin_registrant.cc');
|
||||
|
||||
expect(registrantHeader.existsSync(), isTrue);
|
||||
expect(registrantImpl.existsSync(), isTrue);
|
||||
expect(registrantImpl.readAsStringSync(), contains('SomePluginRegisterWithRegistrar'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
testUsingContext('Injecting creates generated Linux plugin makefile', () async {
|
||||
when(linuxProject.existsSync()).thenReturn(true);
|
||||
when(featureFlags.isLinuxEnabled).thenReturn(true);
|
||||
when(flutterProject.isModule).thenReturn(false);
|
||||
configureDummyPackageAsPlugin();
|
||||
|
||||
await injectPlugins(flutterProject, checkProjects: true);
|
||||
|
||||
final File pluginMakefile = linuxProject.generatedPluginMakeFile;
|
||||
|
||||
expect(pluginMakefile.existsSync(), isTrue);
|
||||
final String contents = pluginMakefile.readAsStringSync();
|
||||
expect(contents, contains('libapackage_plugin.so'));
|
||||
// Verify all the variables the app-level Makefile rely on.
|
||||
expect(contents, contains('PLUGIN_TARGETS='));
|
||||
expect(contents, contains('PLUGIN_LIBRARIES='));
|
||||
expect(contents, contains('PLUGIN_LDFLAGS='));
|
||||
expect(contents, contains('PLUGIN_CPPFLAGS='));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
FeatureFlags: () => featureFlags,
|
||||
});
|
||||
|
||||
|
||||
testUsingContext('Injecting creates generated Windows registrant', () async {
|
||||
when(windowsProject.existsSync()).thenReturn(true);
|
||||
when(featureFlags.isWindowsEnabled).thenReturn(true);
|
||||
|
||||
Reference in New Issue
Block a user