Mounir-Bouaiche

Add linux support to example

  1 +flutter/ephemeral
  1 +cmake_minimum_required(VERSION 3.10)
  2 +project(runner LANGUAGES CXX)
  3 +
  4 +set(BINARY_NAME "example")
  5 +set(APPLICATION_ID "li.zhuoyuan.example")
  6 +
  7 +cmake_policy(SET CMP0063 NEW)
  8 +
  9 +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
  10 +
  11 +# Root filesystem for cross-building.
  12 +if(FLUTTER_TARGET_PLATFORM_SYSROOT)
  13 + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
  14 + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
  15 + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
  16 + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
  17 + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
  18 + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
  19 +endif()
  20 +
  21 +# Configure build options.
  22 +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  23 + set(CMAKE_BUILD_TYPE "Debug" CACHE
  24 + STRING "Flutter build mode" FORCE)
  25 + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
  26 + "Debug" "Profile" "Release")
  27 +endif()
  28 +
  29 +# Compilation settings that should be applied to most targets.
  30 +function(APPLY_STANDARD_SETTINGS TARGET)
  31 + target_compile_features(${TARGET} PUBLIC cxx_std_14)
  32 + target_compile_options(${TARGET} PRIVATE -Wall -Werror)
  33 + target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
  34 + target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
  35 +endfunction()
  36 +
  37 +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
  38 +
  39 +# Flutter library and tool build rules.
  40 +add_subdirectory(${FLUTTER_MANAGED_DIR})
  41 +
  42 +# System-level dependencies.
  43 +find_package(PkgConfig REQUIRED)
  44 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
  45 +
  46 +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
  47 +
  48 +# Application build
  49 +add_executable(${BINARY_NAME}
  50 + "main.cc"
  51 + "my_application.cc"
  52 + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
  53 +)
  54 +apply_standard_settings(${BINARY_NAME})
  55 +target_link_libraries(${BINARY_NAME} PRIVATE flutter)
  56 +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
  57 +add_dependencies(${BINARY_NAME} flutter_assemble)
  58 +# Only the install-generated bundle's copy of the executable will launch
  59 +# correctly, since the resources must in the right relative locations. To avoid
  60 +# people trying to run the unbundled copy, put it in a subdirectory instead of
  61 +# the default top-level location.
  62 +set_target_properties(${BINARY_NAME}
  63 + PROPERTIES
  64 + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
  65 +)
  66 +
  67 +# Generated plugin build rules, which manage building the plugins and adding
  68 +# them to the application.
  69 +include(flutter/generated_plugins.cmake)
  70 +
  71 +
  72 +# === Installation ===
  73 +# By default, "installing" just makes a relocatable bundle in the build
  74 +# directory.
  75 +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
  76 +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  77 + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
  78 +endif()
  79 +
  80 +# Start with a clean build bundle directory every time.
  81 +install(CODE "
  82 + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
  83 + " COMPONENT Runtime)
  84 +
  85 +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
  86 +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
  87 +
  88 +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
  89 + COMPONENT Runtime)
  90 +
  91 +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
  92 + COMPONENT Runtime)
  93 +
  94 +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  95 + COMPONENT Runtime)
  96 +
  97 +if(PLUGIN_BUNDLED_LIBRARIES)
  98 + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
  99 + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  100 + COMPONENT Runtime)
  101 +endif()
  102 +
  103 +# Fully re-copy the assets directory on each build to avoid having stale files
  104 +# from a previous install.
  105 +set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
  106 +install(CODE "
  107 + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
  108 + " COMPONENT Runtime)
  109 +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
  110 + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
  111 +
  112 +# Install the AOT library on non-Debug builds only.
  113 +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
  114 + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  115 + COMPONENT Runtime)
  116 +endif()
  1 +cmake_minimum_required(VERSION 3.10)
  2 +
  3 +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
  4 +
  5 +# Configuration provided via flutter tool.
  6 +include(${EPHEMERAL_DIR}/generated_config.cmake)
  7 +
  8 +# TODO: Move the rest of this into files in ephemeral. See
  9 +# https://github.com/flutter/flutter/issues/57146.
  10 +
  11 +# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
  12 +# which isn't available in 3.10.
  13 +function(list_prepend LIST_NAME PREFIX)
  14 + set(NEW_LIST "")
  15 + foreach(element ${${LIST_NAME}})
  16 + list(APPEND NEW_LIST "${PREFIX}${element}")
  17 + endforeach(element)
  18 + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
  19 +endfunction()
  20 +
  21 +# === Flutter Library ===
  22 +# System-level dependencies.
  23 +find_package(PkgConfig REQUIRED)
  24 +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
  25 +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
  26 +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
  27 +
  28 +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
  29 +
  30 +# Published to parent scope for install step.
  31 +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
  32 +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
  33 +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
  34 +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
  35 +
  36 +list(APPEND FLUTTER_LIBRARY_HEADERS
  37 + "fl_basic_message_channel.h"
  38 + "fl_binary_codec.h"
  39 + "fl_binary_messenger.h"
  40 + "fl_dart_project.h"
  41 + "fl_engine.h"
  42 + "fl_json_message_codec.h"
  43 + "fl_json_method_codec.h"
  44 + "fl_message_codec.h"
  45 + "fl_method_call.h"
  46 + "fl_method_channel.h"
  47 + "fl_method_codec.h"
  48 + "fl_method_response.h"
  49 + "fl_plugin_registrar.h"
  50 + "fl_plugin_registry.h"
  51 + "fl_standard_message_codec.h"
  52 + "fl_standard_method_codec.h"
  53 + "fl_string_codec.h"
  54 + "fl_value.h"
  55 + "fl_view.h"
  56 + "flutter_linux.h"
  57 +)
  58 +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
  59 +add_library(flutter INTERFACE)
  60 +target_include_directories(flutter INTERFACE
  61 + "${EPHEMERAL_DIR}"
  62 +)
  63 +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
  64 +target_link_libraries(flutter INTERFACE
  65 + PkgConfig::GTK
  66 + PkgConfig::GLIB
  67 + PkgConfig::GIO
  68 +)
  69 +add_dependencies(flutter flutter_assemble)
  70 +
  71 +# === Flutter tool backend ===
  72 +# _phony_ is a non-existent file to force this command to run every time,
  73 +# since currently there's no way to get a full input/output list from the
  74 +# flutter tool.
  75 +add_custom_command(
  76 + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
  77 + ${CMAKE_CURRENT_BINARY_DIR}/_phony_
  78 + COMMAND ${CMAKE_COMMAND} -E env
  79 + ${FLUTTER_TOOL_ENVIRONMENT}
  80 + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
  81 + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
  82 + VERBATIM
  83 +)
  84 +add_custom_target(flutter_assemble DEPENDS
  85 + "${FLUTTER_LIBRARY}"
  86 + ${FLUTTER_LIBRARY_HEADERS}
  87 +)
  1 +//
  2 +// Generated file. Do not edit.
  3 +//
  4 +
  5 +// clang-format off
  6 +
  7 +#include "generated_plugin_registrant.h"
  8 +
  9 +
  10 +void fl_register_plugins(FlPluginRegistry* registry) {
  11 +}
  1 +//
  2 +// Generated file. Do not edit.
  3 +//
  4 +
  5 +// clang-format off
  6 +
  7 +#ifndef GENERATED_PLUGIN_REGISTRANT_
  8 +#define GENERATED_PLUGIN_REGISTRANT_
  9 +
  10 +#include <flutter_linux/flutter_linux.h>
  11 +
  12 +// Registers Flutter plugins.
  13 +void fl_register_plugins(FlPluginRegistry* registry);
  14 +
  15 +#endif // GENERATED_PLUGIN_REGISTRANT_
  1 +#
  2 +# Generated file, do not edit.
  3 +#
  4 +
  5 +list(APPEND FLUTTER_PLUGIN_LIST
  6 +)
  7 +
  8 +set(PLUGIN_BUNDLED_LIBRARIES)
  9 +
  10 +foreach(plugin ${FLUTTER_PLUGIN_LIST})
  11 + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
  12 + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
  13 + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
  14 + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
  15 +endforeach(plugin)
  1 +#include "my_application.h"
  2 +
  3 +int main(int argc, char** argv) {
  4 + g_autoptr(MyApplication) app = my_application_new();
  5 + return g_application_run(G_APPLICATION(app), argc, argv);
  6 +}
  1 +#include "my_application.h"
  2 +
  3 +#include <flutter_linux/flutter_linux.h>
  4 +#ifdef GDK_WINDOWING_X11
  5 +#include <gdk/gdkx.h>
  6 +#endif
  7 +
  8 +#include "flutter/generated_plugin_registrant.h"
  9 +
  10 +struct _MyApplication {
  11 + GtkApplication parent_instance;
  12 + char** dart_entrypoint_arguments;
  13 +};
  14 +
  15 +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
  16 +
  17 +// Implements GApplication::activate.
  18 +static void my_application_activate(GApplication* application) {
  19 + MyApplication* self = MY_APPLICATION(application);
  20 + GtkWindow* window =
  21 + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
  22 +
  23 + // Use a header bar when running in GNOME as this is the common style used
  24 + // by applications and is the setup most users will be using (e.g. Ubuntu
  25 + // desktop).
  26 + // If running on X and not using GNOME then just use a traditional title bar
  27 + // in case the window manager does more exotic layout, e.g. tiling.
  28 + // If running on Wayland assume the header bar will work (may need changing
  29 + // if future cases occur).
  30 + gboolean use_header_bar = TRUE;
  31 +#ifdef GDK_WINDOWING_X11
  32 + GdkScreen* screen = gtk_window_get_screen(window);
  33 + if (GDK_IS_X11_SCREEN(screen)) {
  34 + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
  35 + if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
  36 + use_header_bar = FALSE;
  37 + }
  38 + }
  39 +#endif
  40 + if (use_header_bar) {
  41 + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
  42 + gtk_widget_show(GTK_WIDGET(header_bar));
  43 + gtk_header_bar_set_title(header_bar, "example");
  44 + gtk_header_bar_set_show_close_button(header_bar, TRUE);
  45 + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
  46 + } else {
  47 + gtk_window_set_title(window, "example");
  48 + }
  49 +
  50 + gtk_window_set_default_size(window, 1280, 720);
  51 + gtk_widget_show(GTK_WIDGET(window));
  52 +
  53 + g_autoptr(FlDartProject) project = fl_dart_project_new();
  54 + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
  55 +
  56 + FlView* view = fl_view_new(project);
  57 + gtk_widget_show(GTK_WIDGET(view));
  58 + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
  59 +
  60 + fl_register_plugins(FL_PLUGIN_REGISTRY(view));
  61 +
  62 + gtk_widget_grab_focus(GTK_WIDGET(view));
  63 +}
  64 +
  65 +// Implements GApplication::local_command_line.
  66 +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
  67 + MyApplication* self = MY_APPLICATION(application);
  68 + // Strip out the first argument as it is the binary name.
  69 + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
  70 +
  71 + g_autoptr(GError) error = nullptr;
  72 + if (!g_application_register(application, nullptr, &error)) {
  73 + g_warning("Failed to register: %s", error->message);
  74 + *exit_status = 1;
  75 + return TRUE;
  76 + }
  77 +
  78 + g_application_activate(application);
  79 + *exit_status = 0;
  80 +
  81 + return TRUE;
  82 +}
  83 +
  84 +// Implements GObject::dispose.
  85 +static void my_application_dispose(GObject* object) {
  86 + MyApplication* self = MY_APPLICATION(object);
  87 + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
  88 + G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
  89 +}
  90 +
  91 +static void my_application_class_init(MyApplicationClass* klass) {
  92 + G_APPLICATION_CLASS(klass)->activate = my_application_activate;
  93 + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
  94 + G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
  95 +}
  96 +
  97 +static void my_application_init(MyApplication* self) {}
  98 +
  99 +MyApplication* my_application_new() {
  100 + return MY_APPLICATION(g_object_new(my_application_get_type(),
  101 + "application-id", APPLICATION_ID,
  102 + "flags", G_APPLICATION_NON_UNIQUE,
  103 + nullptr));
  104 +}
  1 +#ifndef FLUTTER_MY_APPLICATION_H_
  2 +#define FLUTTER_MY_APPLICATION_H_
  3 +
  4 +#include <gtk/gtk.h>
  5 +
  6 +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
  7 + GtkApplication)
  8 +
  9 +/**
  10 + * my_application_new:
  11 + *
  12 + * Creates a new Flutter-based application.
  13 + *
  14 + * Returns: a new #MyApplication.
  15 + */
  16 +MyApplication* my_application_new();
  17 +
  18 +#endif // FLUTTER_MY_APPLICATION_H_