Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate a makefile for Linux plugins #51520

Merged
merged 2 commits into from
Feb 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 58 additions & 2 deletions packages/flutter_tools/lib/src/plugins.dart
Expand Up @@ -798,6 +798,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>{
Expand Down Expand Up @@ -838,12 +872,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 {
Expand Down Expand Up @@ -1031,7 +1087,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);
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter_tools/lib/src/project.dart
Expand Up @@ -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');

Expand Down
53 changes: 52 additions & 1 deletion packages/flutter_tools/test/general.shard/plugins_test.dart
Expand Up @@ -82,7 +82,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(
Expand Down Expand Up @@ -832,6 +838,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);
Expand Down