Skip to content

Commit 2c1f713

Browse files
Add Linux support to Pigeon (flutter#5100)
Add Linux support for Pigeon. This has minimal work porting the generator and some manually written generated code so we can review this before implementing the generator support. flutter#73740
1 parent 648c92d commit 2c1f713

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+33996
-39
lines changed

packages/pigeon/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 21.1.0
2+
3+
* Adds GObject (Linux) support.
4+
15
## 21.0.0
26

37
* **Breaking Change** [cpp] Fixes style of enum names. References to enum values

packages/pigeon/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Currently pigeon supports generating:
1717
* Kotlin and Java code for Android
1818
* Swift and Objective-C code for iOS and macOS
1919
* C++ code for Windows
20+
* GObject code for Linux
2021

2122
### Supported Datatypes
2223

@@ -136,6 +137,13 @@ to the api to allow for multiple instances to be created and operate in parallel
136137
1) Implement the generated protocol for handling the calls on macOS, set it up
137138
as the handler for the messages.
138139

140+
### Flutter calling into Linux steps
141+
142+
1) Add the generated GObject code to your `./linux` directory for compilation, and
143+
to your `linux/CMakeLists.txt` file.
144+
1) Implement the generated protocol for handling the calls on Linux, set it up
145+
as the vtable for the API object.
146+
139147
### Calling into Flutter from the host platform
140148

141149
Pigeon also supports calling in the opposite direction. The steps are similar

packages/pigeon/example/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ needed for your project.
1919
cppOptions: CppOptions(namespace: 'pigeon_example'),
2020
cppHeaderOut: 'windows/runner/messages.g.h',
2121
cppSourceOut: 'windows/runner/messages.g.cpp',
22+
gobjectHeaderOut: 'linux/messages.g.h',
23+
gobjectSourceOut: 'linux/messages.g.cc',
24+
gobjectOptions: GObjectOptions(),
2225
kotlinOut:
2326
'android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt',
2427
kotlinOptions: KotlinOptions(),
@@ -191,6 +194,49 @@ class PigeonApiImplementation : public ExampleHostApi {
191194
};
192195
```
193196
197+
### GObject
198+
<?code-excerpt "linux/my_application.cc (vtable)"?>
199+
```c++
200+
static PigeonExamplePackageExampleHostApiGetHostLanguageResponse*
201+
handle_get_host_language(gpointer user_data) {
202+
return pigeon_example_package_example_host_api_get_host_language_response_new(
203+
"C++");
204+
}
205+
206+
static PigeonExamplePackageExampleHostApiAddResponse* handle_add(
207+
int64_t a, int64_t b, gpointer user_data) {
208+
if (a < 0 || b < 0) {
209+
g_autoptr(FlValue) details = fl_value_new_string("details");
210+
return pigeon_example_package_example_host_api_add_response_new_error(
211+
"code", "message", details);
212+
}
213+
214+
return pigeon_example_package_example_host_api_add_response_new(a + b);
215+
}
216+
217+
static void handle_send_message(
218+
PigeonExamplePackageMessageData* message,
219+
PigeonExamplePackageExampleHostApiResponseHandle* response_handle,
220+
gpointer user_data) {
221+
PigeonExamplePackageCode code =
222+
pigeon_example_package_message_data_get_code(message);
223+
if (code == PIGEON_EXAMPLE_PACKAGE_CODE_ONE) {
224+
g_autoptr(FlValue) details = fl_value_new_string("details");
225+
pigeon_example_package_example_host_api_respond_error_send_message(
226+
response_handle, "code", "message", details);
227+
return;
228+
}
229+
230+
pigeon_example_package_example_host_api_respond_send_message(response_handle,
231+
TRUE);
232+
}
233+
234+
static PigeonExamplePackageExampleHostApiVTable example_host_api_vtable = {
235+
.get_host_language = handle_get_host_language,
236+
.add = handle_add,
237+
.send_message = handle_send_message};
238+
```
239+
194240
## FlutterApi Example
195241

196242
This example gives an overview of how to use Pigeon to call into the Flutter
@@ -274,6 +320,37 @@ void TestPlugin::CallFlutterMethod(
274320
}
275321
```
276322
323+
### GObject
324+
325+
<?code-excerpt "linux/my_application.cc (flutter-method-callback)"?>
326+
```c++
327+
static void flutter_method_cb(GObject* object, GAsyncResult* result,
328+
gpointer user_data) {
329+
g_autoptr(GError) error = nullptr;
330+
g_autoptr(
331+
PigeonExamplePackageMessageFlutterApiFlutterMethodResponse) response =
332+
pigeon_example_package_message_flutter_api_flutter_method_finish(
333+
PIGEON_EXAMPLE_PACKAGE_MESSAGE_FLUTTER_API(object), result, &error);
334+
if (response == nullptr) {
335+
g_warning("Failed to call Flutter method: %s", error->message);
336+
return;
337+
}
338+
339+
g_printerr(
340+
"Got result from Flutter method: %s\n",
341+
pigeon_example_package_message_flutter_api_flutter_method_response_get_return_value(
342+
response));
343+
}
344+
```
345+
346+
<?code-excerpt "linux/my_application.cc (flutter-method)"?>
347+
```c++
348+
self->flutter_api =
349+
pigeon_example_package_message_flutter_api_new(messenger, nullptr);
350+
pigeon_example_package_message_flutter_api_flutter_method(
351+
self->flutter_api, "hello", nullptr, flutter_method_cb, self);
352+
```
353+
277354
## Swift / Kotlin Plugin Example
278355
279356
A downloadable example of using Pigeon to create a Flutter Plugin with Swift and

packages/pigeon/example/app/lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class _ExampleFlutterApi implements MessageFlutterApi {
1919
// #enddocregion main-dart-flutter
2020

2121
void main() {
22+
WidgetsFlutterBinding.ensureInitialized();
2223
// #docregion main-dart-flutter
2324
MessageFlutterApi.setUp(_ExampleFlutterApi());
2425
// #enddocregion main-dart-flutter
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
flutter/ephemeral
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Project-level configuration.
2+
cmake_minimum_required(VERSION 3.10)
3+
project(runner LANGUAGES CXX)
4+
5+
# The name of the executable created for the application. Change this to change
6+
# the on-disk name of your application.
7+
set(BINARY_NAME "pigeon_example_app")
8+
# The unique GTK application identifier for this application. See:
9+
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10+
set(APPLICATION_ID "dev.flutter.pigeon_example_app")
11+
12+
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13+
# versions of CMake.
14+
cmake_policy(SET CMP0063 NEW)
15+
16+
# Load bundled libraries from the lib/ directory relative to the binary.
17+
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18+
19+
# Root filesystem for cross-building.
20+
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21+
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22+
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27+
endif()
28+
29+
# Define build configuration options.
30+
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31+
set(CMAKE_BUILD_TYPE "Debug" CACHE
32+
STRING "Flutter build mode" FORCE)
33+
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34+
"Debug" "Profile" "Release")
35+
endif()
36+
37+
# Compilation settings that should be applied to most targets.
38+
#
39+
# Be cautious about adding new options here, as plugins use this function by
40+
# default. In most cases, you should add new options to specific targets instead
41+
# of modifying this function.
42+
function(APPLY_STANDARD_SETTINGS TARGET)
43+
target_compile_features(${TARGET} PUBLIC cxx_std_14)
44+
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45+
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46+
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47+
endfunction()
48+
49+
# Flutter library and tool build rules.
50+
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51+
add_subdirectory(${FLUTTER_MANAGED_DIR})
52+
53+
# System-level dependencies.
54+
find_package(PkgConfig REQUIRED)
55+
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56+
57+
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
58+
59+
# Define the application target. To change its name, change BINARY_NAME above,
60+
# not the value here, or `flutter run` will no longer work.
61+
#
62+
# Any new source files that you add to the application should be added here.
63+
add_executable(${BINARY_NAME}
64+
"main.cc"
65+
"my_application.cc"
66+
"messages.g.cc"
67+
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
68+
)
69+
70+
# Apply the standard set of build settings. This can be removed for applications
71+
# that need different build settings.
72+
apply_standard_settings(${BINARY_NAME})
73+
74+
# Add dependency libraries. Add any application-specific dependencies here.
75+
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
76+
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
77+
78+
# Run the Flutter tool portions of the build. This must not be removed.
79+
add_dependencies(${BINARY_NAME} flutter_assemble)
80+
81+
# Only the install-generated bundle's copy of the executable will launch
82+
# correctly, since the resources must in the right relative locations. To avoid
83+
# people trying to run the unbundled copy, put it in a subdirectory instead of
84+
# the default top-level location.
85+
set_target_properties(${BINARY_NAME}
86+
PROPERTIES
87+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
88+
)
89+
90+
91+
# Generated plugin build rules, which manage building the plugins and adding
92+
# them to the application.
93+
include(flutter/generated_plugins.cmake)
94+
95+
96+
# === Installation ===
97+
# By default, "installing" just makes a relocatable bundle in the build
98+
# directory.
99+
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
100+
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
101+
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
102+
endif()
103+
104+
# Start with a clean build bundle directory every time.
105+
install(CODE "
106+
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
107+
" COMPONENT Runtime)
108+
109+
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
110+
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
111+
112+
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
113+
COMPONENT Runtime)
114+
115+
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
116+
COMPONENT Runtime)
117+
118+
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
119+
COMPONENT Runtime)
120+
121+
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
122+
install(FILES "${bundled_library}"
123+
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
124+
COMPONENT Runtime)
125+
endforeach(bundled_library)
126+
127+
# Fully re-copy the assets directory on each build to avoid having stale files
128+
# from a previous install.
129+
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
130+
install(CODE "
131+
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
132+
" COMPONENT Runtime)
133+
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
134+
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
135+
136+
# Install the AOT library on non-Debug builds only.
137+
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
138+
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
139+
COMPONENT Runtime)
140+
endif()
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# This file controls Flutter-level build steps. It should not be edited.
2+
cmake_minimum_required(VERSION 3.10)
3+
4+
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5+
6+
# Configuration provided via flutter tool.
7+
include(${EPHEMERAL_DIR}/generated_config.cmake)
8+
9+
# TODO: Move the rest of this into files in ephemeral. See
10+
# https://github.com/flutter/flutter/issues/57146.
11+
12+
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13+
# which isn't available in 3.10.
14+
function(list_prepend LIST_NAME PREFIX)
15+
set(NEW_LIST "")
16+
foreach(element ${${LIST_NAME}})
17+
list(APPEND NEW_LIST "${PREFIX}${element}")
18+
endforeach(element)
19+
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20+
endfunction()
21+
22+
# === Flutter Library ===
23+
# System-level dependencies.
24+
find_package(PkgConfig REQUIRED)
25+
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26+
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27+
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28+
29+
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30+
31+
# Published to parent scope for install step.
32+
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33+
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34+
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35+
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36+
37+
list(APPEND FLUTTER_LIBRARY_HEADERS
38+
"fl_basic_message_channel.h"
39+
"fl_binary_codec.h"
40+
"fl_binary_messenger.h"
41+
"fl_dart_project.h"
42+
"fl_engine.h"
43+
"fl_json_message_codec.h"
44+
"fl_json_method_codec.h"
45+
"fl_message_codec.h"
46+
"fl_method_call.h"
47+
"fl_method_channel.h"
48+
"fl_method_codec.h"
49+
"fl_method_response.h"
50+
"fl_plugin_registrar.h"
51+
"fl_plugin_registry.h"
52+
"fl_standard_message_codec.h"
53+
"fl_standard_method_codec.h"
54+
"fl_string_codec.h"
55+
"fl_value.h"
56+
"fl_view.h"
57+
"flutter_linux.h"
58+
)
59+
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60+
add_library(flutter INTERFACE)
61+
target_include_directories(flutter INTERFACE
62+
"${EPHEMERAL_DIR}"
63+
)
64+
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65+
target_link_libraries(flutter INTERFACE
66+
PkgConfig::GTK
67+
PkgConfig::GLIB
68+
PkgConfig::GIO
69+
)
70+
add_dependencies(flutter flutter_assemble)
71+
72+
# === Flutter tool backend ===
73+
# _phony_ is a non-existent file to force this command to run every time,
74+
# since currently there's no way to get a full input/output list from the
75+
# flutter tool.
76+
add_custom_command(
77+
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78+
${CMAKE_CURRENT_BINARY_DIR}/_phony_
79+
COMMAND ${CMAKE_COMMAND} -E env
80+
${FLUTTER_TOOL_ENVIRONMENT}
81+
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82+
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83+
VERBATIM
84+
)
85+
add_custom_target(flutter_assemble DEPENDS
86+
"${FLUTTER_LIBRARY}"
87+
${FLUTTER_LIBRARY_HEADERS}
88+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#
2+
# Generated file, do not edit.
3+
#
4+
5+
list(APPEND FLUTTER_PLUGIN_LIST
6+
)
7+
8+
list(APPEND FLUTTER_FFI_PLUGIN_LIST
9+
)
10+
11+
set(PLUGIN_BUNDLED_LIBRARIES)
12+
13+
foreach(plugin ${FLUTTER_PLUGIN_LIST})
14+
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
15+
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
16+
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
17+
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
18+
endforeach(plugin)
19+
20+
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21+
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
22+
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23+
endforeach(ffi_plugin)

0 commit comments

Comments
 (0)