Browse Source

support for linux desktop

master
Herbert Poul 5 years ago
parent
commit
190ea970e1
  1. 1
      example/linux/.gitignore
  2. 90
      example/linux/CMakeLists.txt
  3. 1
      example/linux/flutter/.template_version
  4. 108
      example/linux/flutter/CMakeLists.txt
  5. 12
      example/linux/flutter/generated_plugin_registrant.cc
  6. 13
      example/linux/flutter/generated_plugin_registrant.h
  7. 8
      example/linux/flutter/generated_plugins.cmake
  8. 64
      example/linux/main.cc
  9. 5
      example/linux/window_configuration.cc
  10. 15
      example/linux/window_configuration.h
  11. 2
      ios/Classes/argon2_ffi.c
  12. 39
      lib/argon2_ffi.dart
  13. 4
      linux/CMakeLists.txt

1
example/linux/.gitignore vendored

@ -0,0 +1 @@
flutter/ephemeral

90
example/linux/CMakeLists.txt

@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
set(BINARY_NAME "argon2_ffi_example")
cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "\$ORIGIN")
# Configure build options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules.
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build
add_executable(${BINARY_NAME}
"main.cc"
"window_configuration.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
apply_standard_settings(${BINARY_NAME})
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
add_dependencies(${BINARY_NAME} flutter_assemble)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# BundleUtilities doesn't re-copy changed files, so start with a clean build
# bundle directory every time.
INSTALL(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
file(GLOB FLUTTER_PLUGIN_DIRS "${PROJECT_BINARY_DIR}/plugins/*")
INSTALL(CODE "
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${BINARY_NAME}\" \"\"
\"${FLUTTER_PLUGIN_DIRS};${FLUTTER_LIBRARY_DIR}\")
" COMPONENT Runtime)
INSTALL(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
INSTALL(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
INSTALL(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the lib directory on non-Debug builds only.
if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
INSTALL(DIRECTORY "${PROJECT_BUILD_DIR}/lib"
DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime)
endif()

1
example/linux/flutter/.template_version

@ -0,0 +1 @@
3

108
example/linux/flutter/CMakeLists.txt

@ -0,0 +1,108 @@
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper_glfw")
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_glfw.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY_DIR "${EPHEMERAL_DIR}" PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"flutter_glfw.h"
"flutter_messenger.h"
"flutter_plugin_registrar.h"
)
list_prepend(FLUTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"engine_method_result.cc"
"standard_codec.cc"
)
list_prepend(CPP_WRAPPER_SOURCES_CORE "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list_prepend(CPP_WRAPPER_SOURCES_PLUGIN "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_window_controller.cc"
)
list_prepend(CPP_WRAPPER_SOURCES_APP "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
)
apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP}
)
apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_app flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE}
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)

12
example/linux/flutter/generated_plugin_registrant.cc

@ -0,0 +1,12 @@
//
// Generated file. Do not edit.
//
#include "generated_plugin_registrant.h"
#include <argon2_ffi_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
Argon2FfiPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Argon2FfiPlugin"));
}

13
example/linux/flutter/generated_plugin_registrant.h

@ -0,0 +1,13 @@
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

8
example/linux/flutter/generated_plugins.cmake

@ -0,0 +1,8 @@
list(APPEND FLUTTER_PLUGIN_LIST
argon2_ffi
)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
endforeach(plugin)

64
example/linux/main.cc

@ -0,0 +1,64 @@
#include <flutter/flutter_engine.h>
#include <flutter/flutter_window_controller.h>
#include <linux/limits.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <vector>
#include "flutter/generated_plugin_registrant.h"
#include "window_configuration.h"
namespace {
// Runs the application in headless mode, without a window.
void RunHeadless(const std::string& icu_data_path,
const std::string& assets_path,
const std::vector<std::string>& arguments,
const std::string& aot_library_path) {
flutter::FlutterEngine engine;
engine.Start(icu_data_path, assets_path, arguments, aot_library_path);
RegisterPlugins(&engine);
while (true) {
engine.RunEventLoopWithTimeout();
}
}
} // namespace
int main(int argc, char **argv) {
std::string data_directory = "data";
std::string assets_path = data_directory + "/flutter_assets";
std::string icu_data_path = data_directory + "/icudtl.dat";
std::string lib_directory = "lib";
std::string aot_library_path = lib_directory + "/libapp.so";
// Arguments for the Flutter Engine.
std::vector<std::string> arguments;
flutter::FlutterWindowController flutter_controller(icu_data_path);
flutter::WindowProperties window_properties = {};
window_properties.title = kFlutterWindowTitle;
window_properties.width = kFlutterWindowWidth;
window_properties.height = kFlutterWindowHeight;
// Start the engine.
if (!flutter_controller.CreateWindow(window_properties, assets_path,
arguments, aot_library_path)) {
if (getenv("DISPLAY") == nullptr) {
std::cout << "No DISPLAY; falling back to headless mode." << std::endl;
RunHeadless(icu_data_path, assets_path, arguments, aot_library_path);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
RegisterPlugins(&flutter_controller);
// Run until the window is closed.
while (flutter_controller.RunEventLoopWithTimeout()) {
}
return EXIT_SUCCESS;
}

5
example/linux/window_configuration.cc

@ -0,0 +1,5 @@
#include "window_configuration.h"
const char *kFlutterWindowTitle = "argon2_ffi_example";
const unsigned int kFlutterWindowWidth = 1280;
const unsigned int kFlutterWindowHeight = 720;

15
example/linux/window_configuration.h

@ -0,0 +1,15 @@
#ifndef WINDOW_CONFIGURATION_
#define WINDOW_CONFIGURATION_
// This is a temporary approach to isolate common customizations from main.cpp,
// where the APIs are still in flux. This should simplify re-creating the
// runner while preserving local changes.
//
// Longer term there should be simpler configuration options for common
// customizations like this, without requiring native code changes.
extern const char *kFlutterWindowTitle;
extern const unsigned int kFlutterWindowWidth;
extern const unsigned int kFlutterWindowHeight;
#endif // WINDOW_CONFIGURATION_

2
ios/Classes/argon2_ffi.c

@ -107,7 +107,7 @@ char *hp_argon2_hash(uint8_t *key, uint32_t keylen, uint8_t *salt, uint32_t salt
uint8_t type, int32_t version) { uint8_t type, int32_t version) {
uint8_t hash1[hashlen]; uint8_t hash1[hashlen];
PRINT_DEBUG("keylen: %ld, saltlen: %ld, m_cost: %ld, t_cost: %ld, parallelism: %ld, hashlen: %ld, type: %d, version: %02x\n", PRINT_DEBUG("keylen: %ld, saltlen: %ld, m_cost: %ld, t_cost: %ld, parallelism: %ld, hashlen: %ld, type: %d, version: %02x\n",
keylen, saltlen, m_cost, t_cost, parallelism, hashlen, type, version); (long)keylen, (long)saltlen, (long)m_cost, (long)t_cost, (long)parallelism, (long)hashlen, type, version);
PRINT_DEBUG("key: "); PRINT_DEBUG("key: ");
debugBytes(key, keylen); debugBytes(key, keylen);

39
lib/argon2_ffi.dart

@ -5,23 +5,48 @@ import 'dart:io';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
typedef HashStuff = Pointer<Utf8> Function(Pointer<Utf8> str); typedef Argon2HashNative = Pointer<Utf8> Function(
Pointer<Uint8> key,
Uint32 keyLen,
Pointer<Uint8> salt,
Uint32 saltlen,
Uint32 m_cost, // memory cost
Uint32 t_cost, // time cost (number iterations)
Uint32 parallelism,
IntPtr hashlen,
Uint8 type,
Uint32 version,
);
class Argon2Ffi { typedef Argon2Hash = Pointer<Utf8> Function(
static const MethodChannel _channel = const MethodChannel('argon2_ffi'); Pointer<Uint8> key,
int keyLen,
Pointer<Uint8> salt,
int saltlen,
int m_cost, // memory cost
int t_cost, // time cost (number iterations)
int parallelism,
int hashlen,
int type,
int version,
);
class Argon2Ffi {
int Function(int x, int y) _nativeAdd; int Function(int x, int y) _nativeAdd;
HashStuff _hashStuff; Argon2Hash argon2hash;
Argon2Ffi() { Argon2Ffi() {
final argon2lib = Platform.isAndroid final argon2lib = Platform.isAndroid
? DynamicLibrary.open('libargon2_ffi.so') ? DynamicLibrary.open('libargon2_ffi.so')
: DynamicLibrary.executable(); : Platform.isLinux
? DynamicLibrary.open('libargon2_ffi_plugin.so')
: DynamicLibrary.executable();
_nativeAdd = argon2lib _nativeAdd = argon2lib
.lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add') .lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add')
.asFunction(); .asFunction();
_hashStuff = argon2hash = argon2lib
argon2lib.lookup<NativeFunction<HashStuff>>('hashStuff').asFunction(); .lookup<NativeFunction<Argon2HashNative>>('hp_argon2_hash')
.asFunction();
} }
int addIt(int x, int y) => _nativeAdd(x, y); int addIt(int x, int y) => _nativeAdd(x, y);

4
linux/CMakeLists.txt

@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME "argon2_ffi") set(PROJECT_NAME "argon2_ffi")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES C CXX)
set(PLUGIN_NAME "${PROJECT_NAME}_plugin") set(PLUGIN_NAME "${PROJECT_NAME}_plugin")
add_library(${PLUGIN_NAME} SHARED add_library(${PLUGIN_NAME} SHARED
"${PLUGIN_NAME}.cc" ${PLUGIN_NAME}.cc
../ios/Classes/argon2_ffi.c ../ios/Classes/argon2_ffi.c

Loading…
Cancel
Save