first commit

This commit is contained in:
Hidenori Matsubayashi
2021-07-16 13:03:30 +09:00
commit d10fcb6127
42 changed files with 4287 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
name: Dart
on:
push:
pull_request:
jobs:
analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Fetch Flutter SDK
run: |
git clone --depth=1 https://github.com/flutter/flutter.git
cd flutter
git fetch --depth=1 https://github.com/flutter/flutter.git `cat ../bin/internal/flutter.version`
git checkout FETCH_HEAD
- name: Install pub dependencies
run: flutter/bin/flutter pub get
- name: Verify formatting
run: flutter/bin/dart format --output=none --set-exit-if-changed lib
- name: Analyze project source
run: flutter/bin/dart analyze --fatal-infos lib
+114
View File
@@ -0,0 +1,114 @@
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.classpath
.project
.settings/
.vscode/
# Flutter repo-specific
/bin/cache/
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/docs/doc/
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
# packages file containing multi-root paths
.packages.generated
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
build/
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# macOS
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/Flutter-Debug.xcconfig
**/macos/Flutter/Flutter-Release.xcconfig
**/macos/Flutter/Flutter-Profile.xcconfig
# Coverage
coverage/
# Symbols
app.*.symbols
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
+7
View File
@@ -0,0 +1,7 @@
# Below is a list of people and organizations that have contributed
# to sony/flutter-elinux from after forking flutter-tizen. Names should
# be added to the list like so:
#
# Name/Organization <email address>
Sony Group Corporation
+2
View File
@@ -0,0 +1,2 @@
# Contributing to flutter-elinux
Welcome to this project. We welcome all your contribution and feedback. If you've never submitted code before, you must add your (or your organization's) name and contact info to the [AUTHORS](./AUTHORS) file.
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2021 Sony Group Corporation. All rights reserved.
Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
Copyright (c) 2014 The Flutter Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the names of the copyright holders nor the names of the
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+21
View File
@@ -0,0 +1,21 @@
# Flutter for Embedded Linux (eLinux)
This software is a **non-official** extension to the [Flutter SDK](https://github.com/flutter/flutter) to build Flutter apps for Embedded Linux devices.
## Documentation
See https://github.com/sony/flutter-elinux/wiki
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md).
## Related projects/repos
### Flutter plugins for eLinux
- [flutter-elinux-plugins](https://github.com/sony/flutter-elinux-plugins)
### Flutter embedder (engine) for eLinux
- [flutter-embedded-linux](https://github.com/sony/flutter-embedded-linux)
### Yocto recipes for Flutter embedder for eLinux
- [meta-flutter](https://github.com/sony/meta-flutter)
## Base software
This software was created based on the [flutter-tizen](https://github.com/flutter-tizen/flutter-tizen) (branched from [this version](https://github.com/flutter-tizen/flutter-tizen/commit/ed128233c0bce33c77dd0df69afa59f0888d2d00)). Special thanks to the flutter-tizen team.
+20
View File
@@ -0,0 +1,20 @@
include: flutter/packages/flutter_tools/analysis_options.yaml
analyzer:
exclude:
- "flutter/bin/cache/**"
- "flutter/dev/**"
- "flutter/examples/**"
- "flutter/packages/flutter/**"
- "flutter/packages/flutter_driver/**"
- "flutter/packages/flutter_goldens/**"
- "flutter/packages/flutter_goldens_client/**"
- "flutter/packages/flutter_localizations/**"
- "flutter/packages/flutter_test/**"
- "flutter/packages/flutter_web_plugins/**"
- "flutter/packages/fuchsia_remote_debug_protocol/**"
- "flutter/packages/integration_test/**"
linter:
rules:
implementation_imports: false
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Copyright 2021 Sony Group Corporation. All rights reserved.
# Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
# Copyright 2014 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -e
# Needed because if it is set, cd may print the path it changed to.
unset CDPATH
# On Mac OS, readlink -f doesn't work, so follow_links traverses the path one
# link at a time, and then cds into the link destination and find out where it
# ends up.
#
# The returned filesystem path must be a format usable by Dart's URI parser,
# since the Dart command line tool treats its argument as a file URI, not a
# filename. For instance, multiple consecutive slashes should be reduced to a
# single slash, since double-slashes indicate a URI "authority", and these are
# supposed to be filenames. There is an edge case where this will return
# multiple slashes: when the input resolves to the root directory. However, if
# that were the case, we wouldn't be running this shell, so we don't do anything
# about it.
#
# The function is enclosed in a subshell to avoid changing the working directory
# of the caller.
function follow_links() (
cd -P "$(dirname -- "$1")"
file="$PWD/$(basename -- "$1")"
while [[ -h "$file" ]]; do
cd -P "$(dirname -- "$file")"
file="$(readlink -- "$file")"
cd -P "$(dirname -- "$file")"
file="$PWD/$(basename -- "$file")"
done
echo "$file"
)
PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
OS="$(uname -s)"
# Allow only 64-bit host platform.
if [ "$(getconf LONG_BIT)" != "64" ]; then
echo "$(basename $PROG_NAME) only supports 64 bit platforms."
exit 1
fi
# If we're on Windows, invoke the batch script instead to get proper locking.
if [[ $OS =~ MINGW.* || $OS =~ CYGWIN.* ]]; then
echo "Window platforms are not supported."
exit 1
fi
source "$BIN_DIR/internal/shared.sh"
# Clone or update the flutter repo.
update_flutter
# Upgrade flutter-elinux if needed.
update_flutter_elinux
# Run the snapshot.
exec_snapshot "$@"
+12
View File
@@ -0,0 +1,12 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_elinux/executable.dart' as executable;
void main(List<String> args) {
executable.main(args);
}
+1
View File
@@ -0,0 +1 @@
9d517f475ba1282b619477bde8e708d6a34287cf
+1
View File
@@ -0,0 +1 @@
615957513eb43b128a16048ab5aa2daaba1656cd
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# Copyright 2021 Sony Group Corporation. All rights reserved.
# Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# ---------------------------------- NOTE ---------------------------------- #
#
# Please keep the logic in this file consistent with the logic in the
# `shared.bat` script in the same directory to ensure that Flutter continue
# to work across all platforms!
#
# -------------------------------------------------------------------------- #
set -e
# Needed because if it is set, cd may print the path it changed to.
unset CDPATH
FLUTTER_REPO="https://github.com/flutter/flutter.git"
if [[ -z "$BIN_DIR" ]]; then
echo "BIN_DIR is not set."
exit 1
fi
ROOT_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
FLUTTER_DIR="$ROOT_DIR/flutter"
SNAPSHOT_PATH="$ROOT_DIR/bin/cache/flutter-elinux.snapshot"
FLUTTER_EXE="$FLUTTER_DIR/bin/flutter"
DART_EXE="$FLUTTER_DIR/bin/cache/dart-sdk/bin/dart"
function update_flutter() {
if [[ -e "$FLUTTER_DIR" && ! -d "$FLUTTER_DIR/.git" ]]; then
echo "$FLUTTER_DIR is not a git directory. Remove it and try again."
exit 1
fi
# Clone flutter repo if not installed.
if [[ ! -d "$FLUTTER_DIR" ]]; then
git clone --depth=1 "$FLUTTER_REPO" "$FLUTTER_DIR"
fi
# GIT_DIR and GIT_WORK_TREE are used in the git command.
export GIT_DIR="$FLUTTER_DIR/.git"
export GIT_WORK_TREE="$FLUTTER_DIR"
# Update flutter repo if needed.
local version="$(cat "$ROOT_DIR/bin/internal/flutter.version")"
if [[ "$version" != "$(git rev-parse HEAD)" ]]; then
git reset --hard
git clean -xdf
git fetch --depth=1 "$FLUTTER_REPO" "$version"
git checkout FETCH_HEAD
# Invalidate the cache.
rm -fr "$ROOT_DIR/bin/cache"
fi
if [[ "$version" != "$(git rev-parse HEAD)" ]]; then
echo "Something went wrong when upgrading the Flutter SDK." \
"Remove directory $FLUTTER_DIR and try again."
exit 1
fi
unset GIT_DIR
unset GIT_WORK_TREE
# Invalidate the flutter cache.
local stamp_path="$FLUTTER_DIR/bin/cache/flutter_tools.stamp"
if [[ ! -f "$stamp_path" || "$version" != "$(cat "$stamp_path")" ]]; then
"$FLUTTER_EXE" --version
fi
}
function update_flutter_elinux() {
mkdir -p "$ROOT_DIR/bin/cache"
local revision="$(git --git-dir="$ROOT_DIR/.git" rev-parse HEAD)"
local stamp_path="$ROOT_DIR/bin/cache/flutter-elinux.stamp"
if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$stamp_path" || "$revision" != "$(cat "$stamp_path")"
|| "$ROOT_DIR/pubspec.yaml" -nt "$ROOT_DIR/pubspec.lock" ]]; then
echo "Running pub upgrade..."
(cd "$ROOT_DIR" && "$FLUTTER_EXE" pub upgrade) || {
>&2 echo "Error: Unable to 'pub upgrade' flutter-elinux."
exit 1
}
echo "Compiling flutter-elinux..."
"$DART_EXE" --disable-dart-dev --no-enable-mirrors \
--snapshot="$SNAPSHOT_PATH" --packages="$ROOT_DIR/.packages" \
"$ROOT_DIR/bin/flutter_elinux.dart"
echo "$revision" > "$stamp_path"
fi
}
function exec_snapshot() {
"$DART_EXE" --disable-dart-dev --packages="$ROOT_DIR/.packages" "$SNAPSHOT_PATH" "$@"
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/analyze.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../elinux_plugins.dart';
class ELinuxAnalyzeCommand extends AnalyzeCommand with ELinuxExtension {
ELinuxAnalyzeCommand({bool verboseHelp = false})
: super(
verboseHelp: verboseHelp,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
logger: globals.logger,
terminal: globals.terminal,
artifacts: globals.artifacts,
);
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/attach.dart';
import '../elinux_plugins.dart';
class ELinuxAttachCommand extends AttachCommand with ELinuxExtension {
ELinuxAttachCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp);
}
+99
View File
@@ -0,0 +1,99 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/android/build_validation.dart' as android;
import 'package:flutter_tools/src/base/analyze_size.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_apk.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../elinux_builder.dart';
import '../elinux_cache.dart';
import '../elinux_plugins.dart';
class ELinuxBuildCommand extends BuildCommand {
ELinuxBuildCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
addSubcommand(BuildPackageCommand(verboseHelp: verboseHelp));
}
}
class BuildPackageCommand extends BuildSubCommand with ELinuxExtension {
/// See: [BuildApkCommand] in `build_apk.dart`
BuildPackageCommand({bool verboseHelp = false}) {
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
usesBuildNameOption();
argParser.addOption(
'target-arch',
defaultsTo: _getCurrentHostPlatformArchName(),
allowed: <String>['x64', 'arm64'],
help: 'Target architecture for which the the app is compiled',
);
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
final String name = 'elinux';
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
<DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
ELinuxDevelopmentArtifact.elinux,
};
@override
final String description = 'Build an eLinux package from your app.';
/// See: [android.validateBuild] in `build_validation.dart`
void validateBuild(ELinuxBuildInfo eLinuxBuildInfo) {
if (eLinuxBuildInfo.buildInfo.mode.isPrecompiled &&
eLinuxBuildInfo.targetArch == 'x86') {
throwToolExit('x86 ABI does not support AOT compilation.');
}
}
/// See: [BuildApkCommand.runCommand] in `build_apk.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final BuildInfo buildInfo = await getBuildInfo();
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
buildInfo,
targetArch: stringArg('target-arch'),
targetBackendType: stringArg('target-backend-type'),
);
validateBuild(eLinuxBuildInfo);
displayNullSafetyMode(buildInfo);
await ELinuxBuilder.buildBundle(
project: FlutterProject.current(),
targetFile: targetFile,
eLinuxBuildInfo: eLinuxBuildInfo,
sizeAnalyzer: SizeAnalyzer(
fileSystem: globals.fs,
logger: globals.logger,
flutterUsage: globals.flutterUsage,
),
);
return FlutterCommandResult.success();
}
String _getCurrentHostPlatformArchName() {
final HostPlatform hostPlatform = getCurrentHostPlatform();
return getNameForHostPlatformArch(hostPlatform);
}
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/commands/clean.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:path/path.dart';
import '../elinux_cmake_project.dart';
class ELinuxCleanCommand extends CleanCommand {
ELinuxCleanCommand({bool verbose = false}) : super(verbose: verbose);
/// See: [CleanCommand.runCommand] in `clean.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final FlutterProject flutterProject = FlutterProject.current();
_cleanELinuxProject(ELinuxProject.fromFlutter(flutterProject));
return super.runCommand();
}
void _cleanELinuxProject(ELinuxProject project) {
if (!project.existsSync()) {
return;
}
_deleteFile(project.ephemeralDirectory);
}
/// Source: [CleanCommand.deleteFile] in `clean.dart` (simplified)
void _deleteFile(FileSystemEntity file) {
if (!file.existsSync()) {
return;
}
final String path = relative(file.path);
final Status status = globals.logger.startProgress(
'Deleting $path...',
);
try {
file.deleteSync(recursive: true);
} on FileSystemException catch (error) {
globals.printError('Failed to remove $path: $error');
} finally {
status?.stop();
}
}
}
+163
View File
@@ -0,0 +1,163 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/flutter_project_metadata.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/template.dart';
import '../elinux_plugins.dart';
class ELinuxCreateCommand extends CreateCommand {
ELinuxCreateCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
void printUsage() {
super.printUsage();
// TODO(swift-kim): I couldn't find a proper way to override the --platforms
// option without copying the entire class. This message is a workaround.
print(
'You don\'t have to specify "elinux" as a target platform with '
'"--platforms" option. It is automatically added by default.',
);
}
/// See:
/// - [CreateCommand.runCommand] in `create.dart`
/// - [CreateCommand._getProjectType] in `create.dart` (generatePlugin)
Future<FlutterCommandResult> runInternal() async {
final FlutterCommandResult result = await super.runCommand();
if (result != FlutterCommandResult.success() || argResults.rest.isEmpty) {
return result;
}
final bool generatePlugin = argResults['template'] != null
? stringArg('template') ==
flutterProjectTypeToString(FlutterProjectType.plugin)
: determineTemplateType() == FlutterProjectType.plugin;
if (generatePlugin) {
// Assume that pubspec.yaml uses the multi-platforms plugin format if the
// file already exists.
// TODO(swift-kim): Skip this message if elinux already exists in pubspec.
globals.printStatus(
'The `pubspec.yaml` under the project directory must be updated to support ELinux.\n'
'Add below lines to under the `platforms:` key.',
emphasis: true,
color: TerminalColor.yellow,
);
final Map<String, dynamic> templateContext = createTemplateContext(
organization: '',
projectName: projectName,
flutterRoot: '',
);
globals.printStatus(
'\nelinux:\n'
' pluginClass: ${templateContext['pluginClass'] as String}\n'
' fileName: ${projectName}_plugin.h',
emphasis: true,
color: TerminalColor.blue,
);
globals.printStatus('');
}
if (boolArg('pub')) {
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
await ensureReadyForELinuxTooling(project);
if (project.hasExampleApp) {
await ensureReadyForELinuxTooling(project.example);
}
}
return result;
}
/// See: [Template.render] in `template.dart`
@override
Future<FlutterCommandResult> runCommand() async {
// The template directory that the flutter tools search for available
// templates cannot be overriden because the implementation is private.
// So we have to copy eLinux templates into the directory manually.
final Directory eLinuxTemplates = globals.fs
.directory(Cache.flutterRoot)
.parent
.childDirectory('templates');
if (!eLinuxTemplates.existsSync()) {
throwToolExit('Could not locate eLinux templates.');
}
final File eLinuxTemplateManifest =
eLinuxTemplates.childFile('template_manifest.json');
final Directory templates = globals.fs
.directory(Cache.flutterRoot)
.childDirectory('packages')
.childDirectory('flutter_tools')
.childDirectory('templates');
final File templateManifest = templates.childFile('template_manifest.json');
// This is required due to: https://github.com/flutter/flutter/pull/59706
// TODO(swift-kim): Find any better workaround. One option is to override
// renderTemplate() but it may result in additional complexity.
eLinuxTemplateManifest.copySync(templateManifest.path);
final String backend = stringArg('target-backend-type');
final List<Directory> created = <Directory>[];
try {
for (final Directory projectType
in eLinuxTemplates.listSync().whereType<Directory>()) {
final Directory sourceRunnerCommon =
projectType.childDirectory('runner');
if (!sourceRunnerCommon.existsSync()) {
continue;
}
final Directory sourceFlutter = projectType.childDirectory('flutter');
if (!sourceFlutter.existsSync()) {
continue;
}
final Directory dest = templates
.childDirectory(projectType.basename)
.childDirectory('elinux.tmpl');
if (dest.existsSync()) {
dest.deleteSync(recursive: true);
}
copyDirectory(projectType, dest);
copyDirectory(sourceFlutter, dest.childDirectory('flutter'));
copyDirectory(sourceRunnerCommon, dest.childDirectory('runner'));
if (projectType.basename == 'app') {
final Directory sourceVariation =
projectType.childDirectory('runner_$backend');
if (!sourceVariation.existsSync()) {
continue;
}
copyDirectory(sourceVariation, dest.childDirectory('runner'));
}
created.add(dest);
}
return await runInternal();
} finally {
for (final Directory template in created) {
template.deleteSync(recursive: true);
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/drive.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../elinux_plugins.dart';
class ELinuxDriveCommand extends DriveCommand with ELinuxExtension {
ELinuxDriveCommand({bool verboseHelp = false})
: super(
verboseHelp: verboseHelp,
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
);
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/commands/packages.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../elinux_plugins.dart';
/// This class was copied from [PackagesCommand] to substitute its
/// [PackagesGetCommand] and [PackagesInteractiveGetCommand] subcommands with
/// their ELinux equivalents. We may find a better workaround in the future.
///
/// Source: [PackagesCommand] in `packages.dart`
class ELinuxPackagesCommand extends FlutterCommand {
ELinuxPackagesCommand() {
addSubcommand(ELinuxPackagesGetCommand('get', false));
addSubcommand(ELinuxPackagesInteractiveGetCommand('upgrade',
'Upgrade the current package\'s dependencies to latest versions.'));
addSubcommand(ELinuxPackagesInteractiveGetCommand(
'add', 'Add a dependency to pubspec.yaml.'));
addSubcommand(ELinuxPackagesInteractiveGetCommand(
'remove', 'Removes a dependency from the current package.'));
addSubcommand(PackagesTestCommand());
addSubcommand(PackagesForwardCommand(
'publish', 'Publish the current package to pub.dartlang.org',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand(
'downgrade', 'Downgrade packages in a Flutter project',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies',
requiresPubspec: true));
addSubcommand(PackagesForwardCommand(
'run', 'Run an executable from a package',
requiresPubspec: true));
addSubcommand(
PackagesForwardCommand('cache', 'Work with the Pub system cache'));
addSubcommand(PackagesForwardCommand('version', 'Print Pub version'));
addSubcommand(PackagesForwardCommand(
'uploader', 'Manage uploaders for a package on pub.dev'));
addSubcommand(PackagesForwardCommand('login', 'Log into pub.dev.'));
addSubcommand(PackagesForwardCommand('logout', 'Log out of pub.dev.'));
addSubcommand(
PackagesForwardCommand('global', 'Work with Pub global packages'));
addSubcommand(PackagesForwardCommand(
'outdated', 'Analyze dependencies to find which ones can be upgraded',
requiresPubspec: true));
addSubcommand(PackagesPassthroughCommand());
}
@override
final String name = 'pub';
@override
List<String> get aliases => const <String>['packages'];
@override
final String description = 'Commands for managing Flutter packages.';
@override
Future<FlutterCommandResult> runCommand() async => null;
}
class ELinuxPackagesGetCommand extends PackagesGetCommand
with _PostRunPluginInjection {
ELinuxPackagesGetCommand(String name, bool upgrade) : super(name, upgrade);
}
class ELinuxPackagesInteractiveGetCommand extends PackagesInteractiveGetCommand
with _PostRunPluginInjection {
ELinuxPackagesInteractiveGetCommand(String commandName, String description)
: super(commandName, description);
}
mixin _PostRunPluginInjection on FlutterCommand {
/// See: [PackagesGetCommand.runCommand] in `packages.dart`
@override
Future<FlutterCommandResult> runCommand() async {
final FlutterCommandResult result = await super.runCommand();
if (result == FlutterCommandResult.success()) {
final String workingDirectory =
argResults.rest.isNotEmpty ? argResults.rest[0] : null;
final String target = findProjectRoot(globals.fs, workingDirectory);
if (target == null) {
return result;
}
final FlutterProject rootProject =
FlutterProject.fromDirectory(globals.fs.directory(target));
await ensureReadyForELinuxTooling(rootProject);
if (rootProject.hasExampleApp &&
rootProject.example.pubspecFile.existsSync()) {
await ensureReadyForELinuxTooling(rootProject.example);
}
}
return result;
}
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/precache.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:meta/meta.dart';
import '../elinux_cache.dart';
class ELinuxPrecacheCommand extends PrecacheCommand {
ELinuxPrecacheCommand({
bool verboseHelp = false,
@required Cache cache,
@required Platform platform,
@required Logger logger,
@required FeatureFlags featureFlags,
}) : _cache = cache,
_platform = platform,
super(
verboseHelp: verboseHelp,
cache: cache,
platform: platform,
logger: logger,
featureFlags: featureFlags,
) {
argParser.addFlag(
'elinux',
negatable: true,
defaultsTo: false,
help: 'Precache artifacts for Embedded Linux development.',
);
}
final Cache _cache;
final Platform _platform;
bool get _includeOtherPlatforms =>
boolArg('android') ||
DevelopmentArtifact.values.any((DevelopmentArtifact artifact) =>
boolArg(artifact.name) && argResults.wasParsed(artifact.name));
@override
Future<FlutterCommandResult> runCommand() async {
final bool includeAllPlatforms = boolArg('all-platforms');
final bool includeELinux = boolArg('elinux');
final bool includeDefaults = !includeELinux && !_includeOtherPlatforms;
const String elinuxStampName = 'elinux-sdk';
// Re-lock the cache.
if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await _cache.lock();
}
if (includeAllPlatforms || includeDefaults || includeELinux) {
if (boolArg('force')) {
_cache.setStampFor(elinuxStampName, '');
}
await _cache.updateAll(<DevelopmentArtifact>{
ELinuxDevelopmentArtifact.elinux,
});
}
if (includeAllPlatforms || includeDefaults || _includeOtherPlatforms) {
// If the '--force' option is used, the super.runCommand() will delete
// the elinux's stamp file. It should be restored.
final String elinuxStamp = _cache.getStampFor(elinuxStampName);
final FlutterCommandResult result = await super.runCommand();
if (elinuxStamp != null) {
_cache.setStampFor(elinuxStampName, elinuxStamp);
}
return result;
}
return FlutterCommandResult.success();
}
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/run.dart';
import '../elinux_cache.dart';
import '../elinux_plugins.dart';
class ELinuxRunCommand extends RunCommand with ELinuxExtension {
ELinuxRunCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp) {
argParser.addOption(
'target-backend-type',
defaultsTo: 'wayland',
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
help: 'Target backend type that the app will run on devices.',
);
}
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
<DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
ELinuxDevelopmentArtifact.elinux,
};
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/commands/test.dart';
import '../elinux_plugins.dart';
class ELinuxTestCommand extends TestCommand with ELinuxExtension {
ELinuxTestCommand({bool verboseHelp = false})
: super(verboseHelp: verboseHelp);
}
+436
View File
@@ -0,0 +1,436 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:file/file.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/depfile.dart';
import 'package:flutter_tools/src/build_system/exceptions.dart';
import 'package:flutter_tools/src/build_system/source.dart';
import 'package:flutter_tools/src/build_system/targets/android.dart';
import 'package:flutter_tools/src/build_system/targets/assets.dart';
import 'package:flutter_tools/src/build_system/targets/common.dart';
import 'package:flutter_tools/src/build_system/targets/icon_tree_shaker.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/cmake.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'elinux_builder.dart';
import 'elinux_cmake_project.dart';
import 'elinux_plugins.dart';
/// Prepares the pre-built flutter bundle.
///
/// Source: [AndroidAssetBundle] in `android.dart`
abstract class ELinuxAssetBundle extends Target {
const ELinuxAssetBundle();
@override
String get name => 'elinux_asset_bundle';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.dill'),
...IconTreeShaker.inputs,
];
@override
List<Source> get outputs => const <Source>[];
@override
List<String> get depfiles => <String>[
'flutter_assets.d',
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
@override
Future<void> build(Environment environment) async {
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, name);
}
final BuildMode buildMode =
getBuildModeForName(environment.defines[kBuildMode]);
final Directory outputDirectory = environment.outputDir
.childDirectory('flutter_assets')
..createSync(recursive: true);
// Only copy the prebuilt runtimes and kernel blob in debug mode.
if (buildMode == BuildMode.debug) {
final String vmSnapshotData = environment.artifacts
.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug);
final String isolateSnapshotData = environment.artifacts
.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug);
environment.buildDir
.childFile('app.dill')
.copySync(outputDirectory.childFile('kernel_blob.bin').path);
environment.fileSystem
.file(vmSnapshotData)
.copySync(outputDirectory.childFile('vm_snapshot_data').path);
environment.fileSystem
.file(isolateSnapshotData)
.copySync(outputDirectory.childFile('isolate_snapshot_data').path);
}
final Depfile assetDepfile = await copyAssets(
environment,
outputDirectory,
targetPlatform: null, // corresponds to flutter-tester
);
final DepfileService depfileService = DepfileService(
fileSystem: environment.fileSystem,
logger: environment.logger,
);
depfileService.writeToFile(
assetDepfile,
environment.buildDir.childFile('flutter_assets.d'),
);
}
}
/// Source: [DebugAndroidApplication] in `android.dart`
class DebugELinuxApplication extends ELinuxAssetBundle {
DebugELinuxApplication(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'debug_elinux_application';
@override
List<Source> get inputs => <Source>[
...super.inputs,
const Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
const Source.artifact(Artifact.isolateSnapshotData,
mode: BuildMode.debug),
];
@override
List<Source> get outputs => <Source>[
...super.outputs,
const Source.pattern('{OUTPUT_DIR}/flutter_assets/vm_snapshot_data'),
const Source.pattern(
'{OUTPUT_DIR}/flutter_assets/isolate_snapshot_data'),
const Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
];
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
ELinuxPlugins(buildInfo),
];
}
/// See: [ReleaseAndroidApplication] in `android.dart`
class ReleaseELinuxApplication extends ELinuxAssetBundle {
ReleaseELinuxApplication(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'release_elinux_application';
@override
List<Target> get dependencies => <Target>[
...super.dependencies,
ELinuxAotElf(),
ELinuxPlugins(buildInfo),
];
}
/// Compiles eLinux native plugins into a single shared object.
class ELinuxPlugins extends Target {
ELinuxPlugins(this.buildInfo);
final ELinuxBuildInfo buildInfo;
@override
String get name => 'elinux_plugins';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/../lib/elinux_build_target.dart'),
Source.pattern('{PROJECT_DIR}/.packages'),
];
@override
List<Source> get outputs => const <Source>[];
@override
List<String> get depfiles => <String>[
'elinux_plugins.d',
];
@override
List<Target> get dependencies => const <Target>[];
@override
Future<void> build(Environment environment) async {
// todo: add plugin build support.
}
}
/// Generates an AOT snapshot (app.so) of the Dart code.
///
/// Source: [AotElfRelease] in `common.dart`
class ELinuxAotElf extends AotElfBase {
ELinuxAotElf();
@override
String get name => 'elinux_aot_elf';
@override
List<Source> get inputs => <Source>[
const Source.pattern('{BUILD_DIR}/app.dill'),
const Source.hostArtifact(HostArtifact.engineDartBinary),
const Source.artifact(Artifact.skyEnginePath),
// Any type of gen_snapshot is applicable here because engine artifacts
// are assumed to be updated at once, not one by one for each platform
// or build mode.
const Source.artifact(Artifact.genSnapshot, mode: BuildMode.release),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.so'),
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
}
class NativeBundle {
NativeBundle(this.buildInfo, this.targetFile);
final ELinuxBuildInfo buildInfo;
final String targetFile;
final ProcessUtils _processUtils = ProcessUtils(
logger: globals.logger, processManager: globals.processManager);
Future<void> build(Environment environment) async {
final FlutterProject project =
FlutterProject.fromDirectory(environment.projectDir);
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
// Clean up the intermediate and output directories.
final Directory eLinuxDir = eLinuxProject.editableDirectory;
final BuildMode buildMode = buildInfo.buildInfo.mode;
final String buildConfig = buildMode.isPrecompiled ? 'release' : 'debug';
final Directory outputDir = environment.outputDir
.childDirectory(buildInfo.targetArch)
.childDirectory(buildConfig);
if (outputDir.existsSync()) {
outputDir.deleteSync(recursive: true);
}
outputDir.createSync(recursive: true);
final Directory outputBundleDir = outputDir.childDirectory('bundle');
if (outputBundleDir.existsSync()) {
outputBundleDir.deleteSync(recursive: true);
}
outputBundleDir.createSync(recursive: true);
final Directory outputBundleLibDir = outputBundleDir.childDirectory('lib');
if (outputBundleLibDir.existsSync()) {
outputBundleLibDir.deleteSync(recursive: true);
}
outputBundleLibDir.createSync(recursive: true);
final Directory outputBundleDataDir =
outputBundleDir.childDirectory('data');
if (outputBundleDataDir.existsSync()) {
outputBundleDataDir.deleteSync(recursive: true);
}
outputBundleDataDir.createSync(recursive: true);
// Copy necessary files
final Directory engineDir =
_getEngineArtifactsDirectory(buildInfo.targetArch, buildMode);
final Directory commonDir =
engineDir.parent.childDirectory('elinux-common');
final File engineBinary = engineDir.childFile('libflutter_engine.so');
final File embedder =
engineDir.childFile(buildInfo.targetBackendType == 'gbm'
? 'libflutter_elinux_gbm.so'
: buildInfo.targetBackendType == 'eglstream'
? 'libflutter_elinux_eglstream.so'
: buildInfo.targetBackendType == 'x11'
? 'libflutter_elinux_x11.so'
: 'libflutter_elinux_wayland.so');
final Directory clientWrapperDir =
commonDir.childDirectory('cpp_client_wrapper');
final Directory pluginsDir =
environment.buildDir.childDirectory('elinux_plugins');
final File pluginsLib = pluginsDir.childFile('libflutter_plugins.so');
if (pluginsLib.existsSync()) {
pluginsLib
.copySync(outputBundleLibDir.childFile(pluginsLib.basename).path);
}
final Directory pluginsUserLibDir = pluginsDir.childDirectory('lib');
if (pluginsUserLibDir.existsSync()) {
pluginsUserLibDir.listSync().whereType<File>().forEach((File lib) =>
lib.copySync(outputBundleLibDir.childFile(lib.basename).path));
}
final Directory flutterDir = eLinuxDir.childDirectory('flutter');
final Directory flutterEphemeralDir =
flutterDir.childDirectory('ephemeral');
// Copy necessary files.
{
if (flutterEphemeralDir.existsSync()) {
flutterEphemeralDir.deleteSync(recursive: true);
}
flutterEphemeralDir.createSync(recursive: true);
flutterEphemeralDir
.childDirectory('cpp_client_wrapper')
.createSync(recursive: true);
copyDirectory(
clientWrapperDir,
flutterEphemeralDir.childDirectory('cpp_client_wrapper'),
);
commonDir.listSync().whereType<File>().forEach((File lib) =>
lib.copySync(flutterEphemeralDir.childFile(lib.basename).path));
engineBinary
.copySync(flutterEphemeralDir.childFile(engineBinary.basename).path);
embedder.copySync(flutterEphemeralDir.childFile(embedder.basename).path);
final File icuData =
commonDir.childDirectory('icu').childFile('icudtl.dat');
icuData.copySync(flutterEphemeralDir.childFile(icuData.basename).path);
if (buildMode.isPrecompiled) {
final File aotSharedLib = environment.buildDir.childFile('app.so');
aotSharedLib.copySync(flutterEphemeralDir.childFile('libapp.so').path);
}
}
// Build the environment that needs to be set for the re-entrant flutter build
// step.
{
final Map<String, String> environment = <String, String>{
if (targetFile != null) 'FLUTTER_TARGET': targetFile,
...buildInfo.buildInfo.toEnvironmentConfig(),
};
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts =
globals.artifacts as LocalEngineArtifacts;
final String engineOutPath = localEngineArtifacts.engineOutPath;
environment['FLUTTER_ENGINE'] =
globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath));
environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath);
}
writeGeneratedCmakeConfig(Cache.flutterRoot, eLinuxProject, environment);
//createPluginSymlinks(eLinuxProject.parent);
}
// Run the native build.
final String cmakeBuildType = buildMode.isPrecompiled ? 'Release' : 'Debug';
RunResult result = await _processUtils.run(
<String>[
'cmake',
'-DCMAKE_BUILD_TYPE=$cmakeBuildType',
'-DFLUTTER_TARGET_BACKEND_TYPE=${buildInfo.targetBackendType}',
eLinuxDir.path,
],
workingDirectory: outputDir.path,
environment: <String, String>{'CC': 'clang', 'CXX': 'clang++'},
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake:\n$result');
}
result = await _processUtils.run(
<String>['cmake', '--build', '.'],
workingDirectory: outputDir.path,
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake build:\n$result');
}
// Create flutter app's bunle.
result = await _processUtils.run(
<String>['cmake', '--install', '.'],
workingDirectory: outputDir.path,
);
if (result.exitCode != 0) {
throwToolExit('Failed to cmake install:\n$result');
}
{
final Directory flutterAssetsDir =
outputBundleDataDir.childDirectory('flutter_assets');
copyDirectory(
environment.outputDir.childDirectory('flutter_assets'),
flutterAssetsDir,
);
}
}
}
/// Converts [targetArch] to an arch name that corresponds to the `BUILD_ARCH`
/// value used by the eLinux native builder.
String getELinuxBuildArch(String targetArch) {
switch (targetArch) {
case 'arm':
return 'armel';
case 'arm64':
return 'aarch64';
case 'x86':
return 'i586';
default:
return targetArch;
}
}
/// On non-Windows, returns [path] unchanged.
///
/// On Windows, converts Windows-style [path] (e.g. 'C:\x\y') into Unix path
/// ('/c/x/y') and returns.
String getUnixPath(String path) {
if (Platform.isWindows) {
path = path.replaceAll(r'\', '/');
if (path.startsWith(':', 1)) {
path = '/${path[0].toLowerCase()}${path.substring(2)}';
}
}
return path;
}
/// On non-Windows, returns the PATH environment variable.
///
/// On Windows, appends the msys2 executables directory to PATH and returns.
String getDefaultPathVariable() {
final Map<String, String> variables = globals.platform.environment;
return variables.containsKey('PATH') ? variables['PATH'] : '';
}
/// See: [CachedArtifacts._getEngineArtifactsPath]
Directory _getEngineArtifactsDirectory(String arch, BuildMode mode) {
assert(mode != null, 'Need to specify a build mode.');
return globals.cache
.getArtifactDirectory('engine')
.childDirectory('elinux-$arch-${mode.name}');
}
+150
View File
@@ -0,0 +1,150 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/base/analyze_size.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/assemble.dart';
import 'package:flutter_tools/src/commands/build_ios_framework.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/linux/build_linux.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'elinux_build_target.dart';
import 'elinux_cmake_project.dart';
/// The define to control what eLinux device is built for.
const String kTargetBackendType = 'TargetBackendType';
/// See: [AndroidBuildInfo] in `build_info.dart`
class ELinuxBuildInfo {
const ELinuxBuildInfo(
this.buildInfo, {
@required this.targetArch,
@required this.targetBackendType,
}) : assert(targetArch != null),
assert(targetBackendType != null);
final BuildInfo buildInfo;
final String targetArch;
final String targetBackendType;
}
/// See:
/// - [AndroidBuilder] in `android_builder.dart`
/// - [AndroidGradleBuilder.buildGradleApp] in `gradle.dart`
/// - [BuildIOSFrameworkCommand._produceAppFramework] in `build_ios_framework.dart` (build target)
/// - [AssembleCommand.runCommand] in `assemble.dart` (performance measurement)
/// - [buildLinux] in `build_linux.dart` (code size)
class ELinuxBuilder {
static Future<void> buildBundle({
@required FlutterProject project,
@required ELinuxBuildInfo eLinuxBuildInfo,
@required String targetFile,
SizeAnalyzer sizeAnalyzer,
}) async {
final ELinuxProject elinuxProject = ELinuxProject.fromFlutter(project);
if (!elinuxProject.existsSync()) {
throwToolExit(
'This project is not configured for eLinux.\n'
'To fix this problem, create a new project by running `flutter-elinux create <app-dir>`.',
);
}
final Directory outputDir =
project.directory.childDirectory('build').childDirectory('elinux');
final BuildInfo buildInfo = eLinuxBuildInfo.buildInfo;
final String buildModeName = getNameForBuildMode(buildInfo.mode);
// Used by AotElfBase to generate an AOT snapshot.
final String targetPlatform = getNameForTargetPlatform(
_getTargetPlatformForArch(eLinuxBuildInfo.targetArch));
final Environment environment = Environment(
projectDir: project.directory,
outputDir: outputDir,
buildDir: project.dartTool.childDirectory('flutter_build'),
cacheDir: globals.cache.getRoot(),
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
engineVersion: globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
defines: <String, String>{
kTargetFile: targetFile,
kBuildMode: buildModeName,
kTargetPlatform: targetPlatform,
kDartObfuscation: buildInfo.dartObfuscation.toString(),
kSplitDebugInfo: buildInfo.splitDebugInfoPath,
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
kTrackWidgetCreation: buildInfo.trackWidgetCreation.toString(),
kCodeSizeDirectory: buildInfo.codeSizeDirectory,
if (buildInfo.dartDefines?.isNotEmpty ?? false)
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
if (buildInfo.extraGenSnapshotOptions?.isNotEmpty ?? false)
kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','),
if (buildInfo.extraFrontEndOptions?.isNotEmpty ?? false)
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
kTargetBackendType: eLinuxBuildInfo.targetBackendType,
},
inputs: <String, String>{
kBundleSkSLPath: buildInfo.bundleSkSLPath,
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
);
final Target target = buildInfo.isDebug
? DebugELinuxApplication(eLinuxBuildInfo)
: ReleaseELinuxApplication(eLinuxBuildInfo);
final Status status = globals.logger.startProgress(
'Building an eLinux application with ${eLinuxBuildInfo.targetBackendType} backend in $buildModeName mode for ${eLinuxBuildInfo.targetArch} target...');
try {
final BuildResult result =
await globals.buildSystem.build(target, environment);
if (!result.success) {
for (final ExceptionMeasurement measurement
in result.exceptions.values) {
globals.printError(measurement.exception.toString());
}
throwToolExit('The build failed.');
}
// These pseudo targets cannot be skipped and should be invoked whenever
// the build is run.
await NativeBundle(eLinuxBuildInfo, targetFile).build(environment);
if (buildInfo.performanceMeasurementFile != null) {
final File outFile =
globals.fs.file(buildInfo.performanceMeasurementFile);
// ignore: invalid_use_of_visible_for_testing_member
writePerformanceData(result.performance.values, outFile);
}
} finally {
status.stop();
}
}
}
/// See: [getTargetPlatformForName] in `build_info.dart`
TargetPlatform _getTargetPlatformForArch(String arch) {
switch (arch) {
case 'arm64':
return TargetPlatform.android_arm64;
default:
return TargetPlatform.android_x64;
}
}
+133
View File
@@ -0,0 +1,133 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart' show OperatingSystemUtils;
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/flutter_cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:meta/meta.dart';
/// See: [DevelopmentArtifact] in `cache.dart`
class ELinuxDevelopmentArtifact implements DevelopmentArtifact {
const ELinuxDevelopmentArtifact._(this.name, this.feature);
@override
final String name;
@override
final Feature feature;
static const DevelopmentArtifact elinux =
ELinuxDevelopmentArtifact._('elinux', null);
}
/// Extends [FlutterCache] to register [ELinuxEngineArtifacts].
///
/// See: [FlutterCache] in `flutter_cache.dart`
class ELinuxFlutterCache extends FlutterCache {
ELinuxFlutterCache({
@required Logger logger,
@required FileSystem fileSystem,
@required Platform platform,
@required OperatingSystemUtils osUtils,
}) : super(
logger: logger,
fileSystem: fileSystem,
platform: platform,
osUtils: osUtils) {
registerArtifact(ELinuxEngineArtifacts(this, platform: platform));
}
}
class ELinuxEngineArtifacts extends EngineCachedArtifact {
ELinuxEngineArtifacts(
Cache cache, {
@required Platform platform,
}) : _platform = platform,
super(
'elinux-sdk',
cache,
ELinuxDevelopmentArtifact.elinux,
);
final Platform _platform;
@override
String get version {
final File versionFile = globals.fs
.directory(Cache.flutterRoot)
.parent
.childDirectory('bin')
.childDirectory('internal')
.childFile('engine.version');
return versionFile.existsSync()
? versionFile.readAsStringSync().trim()
: null;
}
String get shortVersion {
if (version != null && version.length >= 10) {
return version.substring(0, 10);
}
return version;
}
/// See: [Cache.storageBaseUrl] in `cache.dart`
String get engineBaseUrl {
final String overrideUrl = _platform.environment['ELINUX_ENGINE_BASE_URL'];
if (overrideUrl == null) {
return 'https://github.com/sony/flutter-embedded-linux/releases';
}
try {
Uri.parse(overrideUrl);
} on FormatException catch (err) {
throwToolExit('"ELINUX_ENGINE_BASE_URL" contains an invalid URI:\n$err');
}
return overrideUrl;
}
@override
List<List<String>> getBinaryDirs() => <List<String>>[
<String>['elinux-common', 'elinux-common.zip'],
<String>['elinux-arm64-debug', 'elinux-arm64-debug.zip'],
<String>['elinux-arm64-profile', 'elinux-arm64-profile.zip'],
<String>['elinux-arm64-release', 'elinux-arm64-release.zip'],
<String>['elinux-x64-debug', 'elinux-x64-debug.zip'],
<String>['elinux-x64-profile', 'elinux-x64-profile.zip'],
<String>['elinux-x64-release', 'elinux-x64-release.zip'],
];
@override
List<String> getLicenseDirs() => const <String>[];
@override
List<String> getPackageDirs() => const <String>[];
@override
Future<void> updateInner(
ArtifactUpdater artifactUpdater,
FileSystem fileSystem,
OperatingSystemUtils operatingSystemUtils,
) async {
final String downloadUrl = '$engineBaseUrl/download/$shortVersion';
for (final List<String> toolsDir in getBinaryDirs()) {
final String cacheDir = toolsDir[0];
final String urlPath = toolsDir[1];
await artifactUpdater.downloadZipArchive(
'Downloading $cacheDir tools...',
Uri.parse('$downloadUrl/$urlPath'),
location.childDirectory(cacheDir),
);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/project.dart';
import 'elinux_plugins.dart';
/// The eLinux sub project.
class ELinuxProject extends FlutterProjectPlatform
implements CmakeBasedProject {
ELinuxProject.fromFlutter(this.parent);
@override
final FlutterProject parent;
@override
String get pluginConfigKey => ELinuxPlugin.kConfigKey;
String get _childDirectory => 'elinux';
@override
bool existsSync() => editableDirectory.existsSync() && cmakeFile.existsSync();
@override
File get cmakeFile => editableDirectory.childFile('CMakeLists.txt');
@override
File get managedCmakeFile => managedDirectory.childFile('CMakeLists.txt');
@override
File get generatedCmakeConfigFile =>
ephemeralDirectory.childFile('generated_config.cmake');
@override
File get generatedPluginCmakeFile =>
managedDirectory.childFile('generated_plugins.cmake');
@override
Directory get pluginSymlinkDirectory =>
ephemeralDirectory.childDirectory('.plugin_symlinks');
Directory get editableDirectory =>
parent.directory.childDirectory(_childDirectory);
Directory get managedDirectory => editableDirectory.childDirectory('flutter');
Directory get ephemeralDirectory =>
managedDirectory.childDirectory('ephemeral');
Future<void> ensureReadyForPlatformSpecificTooling() async {}
}
+356
View File
@@ -0,0 +1,356 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/device_port_forwarder.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/protocol_discovery.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'elinux_builder.dart';
import 'elinux_package.dart';
/// eLinux device implementation.
///
/// See: [DesktopDevice] in `desktop_device.dart`
class ELinuxDevice extends Device {
ELinuxDevice(
String id, {
@required bool desktop,
@required String backendType,
@required String targetArch,
@required Logger logger,
@required ProcessManager processManager,
@required OperatingSystemUtils operatingSystemUtils,
}) : _desktop = desktop,
_backendType = backendType,
_targetArch = targetArch,
_logger = logger,
_processManager = processManager,
_operatingSystemUtils = operatingSystemUtils,
super(id,
category: Category.desktop,
platformType: PlatformType.custom,
ephemeral: true);
final bool _desktop;
final String _backendType;
final String _targetArch;
final Logger _logger;
final ProcessManager _processManager;
final OperatingSystemUtils _operatingSystemUtils;
final Set<Process> _runningProcesses = <Process>{};
final ELinuxLogReader _logReader = ELinuxLogReader();
@override
Future<bool> get isLocalEmulator async => false;
@override
Future<String> get emulatorId async => null;
@override
Future<TargetPlatform> get targetPlatform async {
// Use tester as a platform identifer for eLinux.
// There's currently no other choice because getNameForTargetPlatform()
// throws an error for unknown platform types.
return TargetPlatform.tester;
}
@override
bool supportsRuntimeMode(BuildMode buildMode) =>
buildMode != BuildMode.jitRelease;
@override
Future<String> get sdkNameAndVersion async => _operatingSystemUtils.name;
@override
String get name => 'eLinux';
@override
Future<bool> isAppInstalled(ELinuxApp app, {String userIdentifier}) async {
return true;
}
@override
Future<bool> isLatestBuildInstalled(ELinuxApp app) async {
return true;
}
@override
Future<bool> installApp(ELinuxApp app, {String userIdentifier}) async {
return true;
}
@override
Future<bool> uninstallApp(ELinuxApp app, {String userIdentifier}) async {
return true;
}
/// Source: [AndroidDevice.startApp] in `android_device.dart`
@override
Future<LaunchResult> startApp(
ELinuxApp package, {
String mainPath,
String route,
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
bool ipv6 = false,
String userIdentifier,
}) async {
if (!prebuiltApplication) {
_logger.printTrace('Building app');
await buildForDevice(
package,
buildInfo: debuggingOptions.buildInfo,
mainPath: mainPath,
);
}
// Ensure that the executable is locatable.
final BuildMode buildMode = debuggingOptions?.buildInfo?.mode;
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
final String executable = executablePathForDevice(package, buildMode);
const String executableOptions = '--bundle=./';
if (executable == null) {
_logger.printError('Unable to find executable to run');
return LaunchResult.failed();
}
final Process process = await _processManager.start(
<String>[
executable,
executableOptions,
if (_desktop && _backendType == 'wayland') '-d',
...?debuggingOptions?.dartEntrypointArgs,
],
environment: _computeEnvironment(debuggingOptions, traceStartup, route),
);
_runningProcesses.add(process);
unawaited(process.exitCode.then((_) => _runningProcesses.remove(process)));
_logReader.initializeProcess(process);
if (debuggingOptions?.buildInfo?.isRelease == true) {
return LaunchResult.succeeded();
}
final ProtocolDiscovery observatoryDiscovery =
ProtocolDiscovery.observatory(
_logReader,
devicePort: debuggingOptions?.deviceVmServicePort,
hostPort: debuggingOptions?.hostVmServicePort,
ipv6: ipv6,
logger: _logger,
);
try {
final Uri observatoryUri = await observatoryDiscovery.uri;
if (observatoryUri != null) {
onAttached(package, buildMode, process);
return LaunchResult.succeeded(observatoryUri: observatoryUri);
}
_logger.printError(
'Error waiting for a debug connection: '
'The log reader stopped unexpectedly.',
);
} on Exception catch (error) {
_logger.printError('Error waiting for a debug connection: $error');
} finally {
await observatoryDiscovery.cancel();
}
return LaunchResult.failed();
}
@override
Future<bool> stopApp(ELinuxApp app, {String userIdentifier}) async {
bool succeeded = true;
// Walk a copy of _runningProcesses, since the exit handler removes from the
// set.
for (final Process process in Set<Process>.of(_runningProcesses)) {
succeeded &= _processManager.killPid(process.pid);
}
return succeeded;
}
@override
void clearLogs() {}
@override
FutureOr<DeviceLogReader> getLogReader({
ELinuxApp app,
bool includePastLogs = false,
}) =>
_logReader;
@override
DevicePortForwarder get portForwarder => null;
@override
bool isSupported() => true;
@override
bool get supportsScreenshot => false;
@override
bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.isModule &&
flutterProject.directory.childDirectory('elinux').existsSync();
}
@override
Future<void> dispose() async {}
Future<void> buildForDevice(
ELinuxApp package, {
String mainPath,
BuildInfo buildInfo,
}) async {
final FlutterProject project = FlutterProject.current();
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
buildInfo,
targetArch: _targetArch,
targetBackendType: _backendType,
);
await ELinuxBuilder.buildBundle(
project: project,
targetFile: mainPath,
eLinuxBuildInfo: eLinuxBuildInfo,
);
package = ELinuxApp.fromELinuxProject(project);
}
String executablePathForDevice(ELinuxApp package, BuildMode buildMode) {
return package.executable(buildMode, _targetArch);
}
void onAttached(ELinuxApp package, BuildMode buildMode, Process process) {}
/// Computes a set of environment variables used to pass debugging information
/// to the engine without interfering with application level command line
/// arguments.
///
/// The format of the environment variables is:
/// * FLUTTER_ENGINE_SWITCHES to the number of switches.
/// * FLUTTER_ENGINE_SWITCH_<N> (indexing from 1) to the individual switches.
Map<String, String> _computeEnvironment(
DebuggingOptions debuggingOptions, bool traceStartup, String route) {
int flags = 0;
final Map<String, String> environment = <String, String>{};
void addFlag(String value) {
flags += 1;
environment['FLUTTER_ENGINE_SWITCH_$flags'] = value;
}
void finish() {
environment['FLUTTER_ENGINE_SWITCHES'] = flags.toString();
}
addFlag('enable-dart-profiling=true');
addFlag('enable-background-compilation=true');
if (traceStartup) {
addFlag('trace-startup=true');
}
if (route != null) {
addFlag('route=$route');
}
if (debuggingOptions.enableSoftwareRendering) {
addFlag('enable-software-rendering=true');
}
if (debuggingOptions.skiaDeterministicRendering) {
addFlag('skia-deterministic-rendering=true');
}
if (debuggingOptions.traceSkia) {
addFlag('trace-skia=true');
}
if (debuggingOptions.traceAllowlist != null) {
addFlag('trace-allowlist=${debuggingOptions.traceAllowlist}');
}
if (debuggingOptions.traceSkiaAllowlist != null) {
addFlag('trace-skia-allowlist=${debuggingOptions.traceSkiaAllowlist}');
}
if (debuggingOptions.traceSystrace) {
addFlag('trace-systrace=true');
}
if (debuggingOptions.endlessTraceBuffer) {
addFlag('endless-trace-buffer=true');
}
if (debuggingOptions.dumpSkpOnShaderCompilation) {
addFlag('dump-skp-on-shader-compilation=true');
}
if (debuggingOptions.cacheSkSL) {
addFlag('cache-sksl=true');
}
if (debuggingOptions.purgePersistentCache) {
addFlag('purge-persistent-cache=true');
}
// Options only supported when there is a VM Service connection between the
// tool and the device, usually in debug or profile mode.
if (debuggingOptions.debuggingEnabled) {
if (debuggingOptions.deviceVmServicePort != null) {
addFlag('observatory-port=${debuggingOptions.deviceVmServicePort}');
}
if (debuggingOptions.buildInfo.isDebug) {
addFlag('enable-checked-mode=true');
addFlag('verify-entry-points=true');
}
if (debuggingOptions.startPaused) {
addFlag('start-paused=true');
}
if (debuggingOptions.disableServiceAuthCodes) {
addFlag('disable-service-auth-codes=true');
}
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
if (dartVmFlags.isNotEmpty) {
addFlag('dart-flags=$dartVmFlags');
}
if (debuggingOptions.useTestFonts) {
addFlag('use-test-fonts=true');
}
if (debuggingOptions.verboseSystemLogs) {
addFlag('verbose-logging=true');
}
}
finish();
return environment;
}
}
class ELinuxLogReader extends DeviceLogReader {
final StreamController<List<int>> _inputController =
StreamController<List<int>>.broadcast();
void initializeProcess(Process process) {
process.stdout.listen(_inputController.add);
process.stderr.listen(_inputController.add);
process.exitCode.whenComplete(_inputController.close);
}
@override
Stream<String> get logLines {
return _inputController.stream
.transform(utf8.decoder)
.transform(const LineSplitter());
}
@override
String get name => 'eLinux';
@override
void dispose() {}
}
+132
View File
@@ -0,0 +1,132 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/android/android_device_discovery.dart';
import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/custom_devices/custom_devices_config.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/flutter_device_manager.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/macos/macos_workflow.dart';
import 'package:flutter_tools/src/windows/uwptool.dart';
import 'package:flutter_tools/src/windows/windows_workflow.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'elinux_device.dart';
import 'elinux_doctor.dart';
/// An extended [FlutterDeviceManager] for managing eLinux devices.
class ELinuxDeviceManager extends FlutterDeviceManager {
/// Source: [runInContext] in `context_runner.dart`
ELinuxDeviceManager()
: super(
logger: globals.logger,
processManager: globals.processManager,
platform: globals.platform,
androidSdk: globals.androidSdk,
iosSimulatorUtils: globals.iosSimulatorUtils,
featureFlags: featureFlags,
fileSystem: globals.fs,
iosWorkflow: globals.iosWorkflow,
artifacts: globals.artifacts,
flutterVersion: globals.flutterVersion,
androidWorkflow: androidWorkflow,
config: globals.config,
fuchsiaWorkflow: fuchsiaWorkflow,
xcDevice: globals.xcdevice,
userMessages: globals.userMessages,
windowsWorkflow: windowsWorkflow,
macOSWorkflow: context.get<MacOSWorkflow>(),
operatingSystemUtils: globals.os,
terminal: globals.terminal,
customDevicesConfig: CustomDevicesConfig(
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
),
uwptool: UwpTool(
artifacts: globals.artifacts,
logger: globals.logger,
processManager: globals.processManager,
),
);
final ELinuxDeviceDiscovery _eLinuxDeviceDiscovery = ELinuxDeviceDiscovery(
eLinuxWorkflow: eLinuxWorkflow,
logger: globals.logger,
processManager: globals.processManager,
);
@override
List<DeviceDiscovery> get deviceDiscoverers => <DeviceDiscovery>[
...super.deviceDiscoverers,
_eLinuxDeviceDiscovery,
];
}
/// Device discovery for eLinux devices.
///
/// Source: [AndroidDevices] in `android_device_discovery.dart`
class ELinuxDeviceDiscovery extends PollingDeviceDiscovery {
ELinuxDeviceDiscovery({
@required ELinuxWorkflow eLinuxWorkflow,
@required ProcessManager processManager,
@required Logger logger,
}) : _eLinuxWorkflow = eLinuxWorkflow,
_logger = logger,
_processManager = processManager,
super('eLinux devices');
final ELinuxWorkflow _eLinuxWorkflow;
final Logger _logger;
final ProcessManager _processManager;
@override
bool get supportsPlatform => _eLinuxWorkflow.appliesToHostPlatform;
@override
bool get canListAnything => _eLinuxWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices({Duration timeout}) async {
if (!canListAnything) {
return const <Device>[];
}
return <Device>[
ELinuxDevice('eLinux',
desktop: true,
targetArch: _getCurrentHostPlatformArchName(),
backendType: 'wayland',
logger: _logger ?? globals.logger,
processManager: _processManager ?? globals.processManager,
operatingSystemUtils: OperatingSystemUtils(
fileSystem: globals.fs,
logger: _logger ?? globals.logger,
platform: globals.platform,
processManager: const LocalProcessManager(),
)),
];
}
@override
Future<List<String>> getDiagnostics() async => const <String>[];
String _getCurrentHostPlatformArchName() {
final HostPlatform hostPlatform = getCurrentHostPlatform();
return getNameForHostPlatformArch(hostPlatform);
}
}
+126
View File
@@ -0,0 +1,126 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/doctor_validator.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/version.dart';
import 'package:meta/meta.dart';
import 'executable.dart';
ELinuxWorkflow get eLinuxWorkflow => context.get<ELinuxWorkflow>();
ELinuxValidator get eLinuxValidator => context.get<ELinuxValidator>();
/// See: [_DefaultDoctorValidatorsProvider] in `doctor.dart`
class ELinuxDoctorValidatorsProvider extends DoctorValidatorsProvider {
@override
List<DoctorValidator> get validators {
final List<DoctorValidator> validators =
DoctorValidatorsProvider.defaultInstance.validators;
return <DoctorValidator>[
validators.first,
eLinuxValidator,
...validators.sublist(1)
];
}
@override
List<Workflow> get workflows => <Workflow>[
...DoctorValidatorsProvider.defaultInstance.workflows,
eLinuxWorkflow,
];
}
/// A validator that checks for eLinux SDK installation.
class ELinuxValidator extends DoctorValidator {
ELinuxValidator() : super('eLinux toolchain - develop for eLinux devices');
bool _validatePackages(List<ValidationMessage> messages) {
return true;
}
/// See: [AndroidValidator.validate] in `android_workflow.dart`
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
final FlutterVersion version = _FlutterELinuxVersion();
messages.add(ValidationMessage(globals.userMessages.flutterRevision(
version.frameworkRevisionShort,
version.frameworkAge,
version.frameworkCommitDate,
)));
messages.add(ValidationMessage(
globals.userMessages.engineRevision(version.engineRevisionShort)));
if (!_validatePackages(messages)) {
return ValidationResult(ValidationType.partial, messages);
}
return ValidationResult(ValidationType.installed, messages);
}
}
/// The eLinux-specific implementation of a [Workflow].
///
/// See: [AndroidWorkflow] in `android_workflow.dart`
class ELinuxWorkflow extends Workflow {
ELinuxWorkflow({
@required OperatingSystemUtils operatingSystemUtils,
}) : _operatingSystemUtils = operatingSystemUtils;
final OperatingSystemUtils _operatingSystemUtils;
@override
bool get appliesToHostPlatform =>
_operatingSystemUtils.hostPlatform != HostPlatform.linux_arm64;
@override
bool get canLaunchDevices => true;
@override
bool get canListDevices => true;
@override
bool get canListEmulators => false;
}
class _FlutterELinuxVersion extends FlutterVersion {
_FlutterELinuxVersion() : super(workingDirectory: rootPath);
/// See: [Cache.getVersionFor] in `cache.dart`
String _getVersionFor(String artifactName) {
final File versionFile = globals.fs
.directory(rootPath)
.childDirectory('bin')
.childDirectory('internal')
.childFile('$artifactName.version');
return versionFile.existsSync()
? versionFile.readAsStringSync().trim()
: null;
}
@override
String get engineRevision => _getVersionFor('engine');
/// See: [_runGit] in `version.dart`
String _runGit(String command) => globals.processUtils
.runSync(command.split(' '), workingDirectory: rootPath)
.stdout
.trim();
/// This should be overriden because [FlutterVersion._latestGitCommitDate]
/// runs the git log command in the `Cache.flutterRoot` directory.
@override
String get frameworkCommitDate => _runGit(
'git -c log.showSignature=false log -n 1 --pretty=format:%ad --date=iso');
}
+103
View File
@@ -0,0 +1,103 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cmake.dart';
import 'package:flutter_tools/src/flutter_application_package.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'elinux_cmake_project.dart';
class ELinuxApplicationPackageFactory extends FlutterApplicationPackageFactory {
ELinuxApplicationPackageFactory()
: super(
androidSdk: globals.androidSdk,
processManager: globals.processManager,
logger: globals.logger,
userMessages: globals.userMessages,
fileSystem: globals.fs,
);
@override
Future<ApplicationPackage> getPackageForPlatform(
TargetPlatform platform, {
BuildInfo buildInfo,
File applicationBinary,
}) async {
if (platform == TargetPlatform.tester) {
return applicationBinary == null
? ELinuxApp.fromELinuxProject(FlutterProject.current())
: ELinuxApp.fromPrebuiltApp(applicationBinary);
}
return super.getPackageForPlatform(platform,
buildInfo: buildInfo, applicationBinary: applicationBinary);
}
}
abstract class ELinuxApp extends ApplicationPackage {
ELinuxApp({@required String projectBundleId}) : super(id: projectBundleId);
factory ELinuxApp.fromELinuxProject(FlutterProject project) {
return BuildableELinuxApp(
project: ELinuxProject.fromFlutter(project),
);
}
factory ELinuxApp.fromPrebuiltApp(FileSystemEntity applicationBinary) {
return PrebuiltELinuxApp(
executable: applicationBinary.path,
);
}
@override
String get displayName => id;
String executable(BuildMode buildMode, String targetArch);
}
class PrebuiltELinuxApp extends ELinuxApp {
PrebuiltELinuxApp({
@required String executable,
}) : _executable = executable,
super(projectBundleId: executable);
final String _executable;
@override
String executable(BuildMode buildMode, String targetArch) => _executable;
@override
String get name => _executable;
}
class BuildableELinuxApp extends ELinuxApp {
BuildableELinuxApp({@required this.project})
: super(projectBundleId: project.parent.manifest.appName);
final ELinuxProject project;
@override
String executable(BuildMode buildMode, String targetArch) {
final String binaryName = getCmakeExecutableName(project);
return globals.fs.path.join(
'build/elinux/',
targetArch,
getNameForBuildMode(buildMode),
'bundle',
binaryName,
);
}
@override
String get name => project.parent.manifest.appName;
}
+462
View File
@@ -0,0 +1,462 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_system/targets/web.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/dart/language_version.dart';
import 'package:flutter_tools/src/dart/package_map.dart';
import 'package:flutter_tools/src/flutter_plugins.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/platform_plugins.dart';
import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:yaml/yaml.dart';
import 'elinux_cmake_project.dart';
/// Contains the parameters to template a elinux plugin.
///
/// The [name] of the plugin is required. Either [dartPluginClass] or
/// [pluginClass] are required. [pluginClass] will be the entry point to the
/// plugin's native code. If [pluginClass] is not empty, the [fileName]
/// containing the plugin's code is required.
///
/// Source: [LinuxPlugin] in `platform_plugins.dart`
class ELinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
ELinuxPlugin({
@required this.name,
@required this.directory,
this.pluginClass,
this.dartPluginClass,
this.fileName,
}) : assert(pluginClass != null || dartPluginClass != null);
factory ELinuxPlugin.fromYaml(
String name, Directory directory, YamlMap yaml) {
assert(validate(yaml));
return ELinuxPlugin(
name: name,
directory: directory,
pluginClass: yaml[kPluginClass] as String,
dartPluginClass: yaml[kDartPluginClass] as String,
fileName: yaml['fileName'] as String,
);
}
static bool validate(YamlMap yaml) {
if (yaml == null) {
return false;
}
return yaml[kPluginClass] is String || yaml[kDartPluginClass] is String;
}
static const String kConfigKey = 'elinux';
final String name;
final Directory directory;
final String pluginClass;
final String dartPluginClass;
final String fileName;
@override
bool isNative() => pluginClass != null;
@override
Map<String, dynamic> toMap() {
return <String, dynamic>{
'name': name,
if (pluginClass != null) 'class': pluginClass,
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass,
'file': fileName,
};
}
File get projectFile => directory.childFile('project_def.prop');
final RegExp _propertyFormat = RegExp(r'(\S+)\s*\+?=(.*)');
Map<String, String> _properties;
String getProperty(String key) {
if (_properties == null) {
if (!projectFile.existsSync()) {
return null;
}
_properties = <String, String>{};
for (final String line in projectFile.readAsLinesSync()) {
final Match match = _propertyFormat.firstMatch(line);
if (match == null) {
continue;
}
final String key = match.group(1);
final String value = match.group(2).trim();
_properties[key] = value;
}
}
return _properties.containsKey(key) ? _properties[key] : null;
}
List<String> getPropertyAsAbsolutePaths(String key) {
final String property = getProperty(key);
if (property == null) {
return <String>[];
}
final List<String> paths = <String>[];
for (final String element in property.split(' ')) {
if (globals.fs.path.isAbsolute(element)) {
paths.add(element);
} else {
paths.add(globals.fs.path
.normalize(globals.fs.path.join(directory.path, element)));
}
}
return paths;
}
}
/// Any [FlutterCommand] that invokes [usesPubOption] or [targetFile] should
/// depend on this mixin to ensure plugins are correctly configured for eLinux.
///
/// See: [FlutterCommand.verifyThenRunCommand] in `flutter_command.dart`
mixin ELinuxExtension on FlutterCommand {
String _entrypoint;
bool get _usesTargetOption => argParser.options.containsKey('target');
@override
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
if (super.shouldRunPub) {
// TODO(swift-kim): Should run pub get first before injecting plugins.
await ensureReadyForELinuxTooling(FlutterProject.current());
}
if (_usesTargetOption) {
_entrypoint =
await _createEntrypoint(FlutterProject.current(), super.targetFile);
}
return super.verifyThenRunCommand(commandPath);
}
@override
String get targetFile => _entrypoint ?? super.targetFile;
}
/// Creates an entrypoint wrapper of [targetFile] and returns its path.
/// This effectively adds support for Dart plugins.
///
/// Source: [WebEntrypointTarget.build] in `web.dart`
Future<String> _createEntrypoint(
FlutterProject project, String targetFile) async {
final List<ELinuxPlugin> dartPlugins =
await findELinuxPlugins(project, dartOnly: true);
if (dartPlugins.isEmpty) {
return targetFile;
}
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
if (!eLinuxProject.existsSync()) {
return targetFile;
}
final File entrypoint = eLinuxProject.managedDirectory.childFile('main.dart')
..createSync(recursive: true);
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
project.directory.childFile('.packages'),
logger: globals.logger,
);
final FlutterProject flutterProject = FlutterProject.current();
final LanguageVersion languageVersion = determineLanguageVersion(
globals.fs.file(targetFile),
packageConfig[flutterProject.manifest.appName],
Cache.flutterRoot,
);
final Uri mainUri = globals.fs.file(targetFile).absolute.uri;
final String mainImport =
packageConfig.toPackageUri(mainUri)?.toString() ?? mainUri.toString();
entrypoint.writeAsStringSync('''
//
// Generated file. Do not edit.
//
// @dart=${languageVersion.major}.${languageVersion.minor}
import '$mainImport' as entrypoint;
import 'generated_plugin_registrant.dart';
Future<void> main() async {
registerPlugins();
entrypoint.main();
}
''');
return entrypoint.path;
}
const List<String> _knownPlugins = <String>[
'audioplayers',
'battery',
'battery_plus',
'camera',
'connectivity',
'device_info',
'flutter_tts',
'image_picker',
'integration_test',
'package_info',
'package_info_plus',
'path_provider',
'permission_handler',
'sensors',
'sensors_plus',
'share',
'shared_preferences',
'url_launcher',
'video_player',
'webview_flutter',
'wifi_info_flutter',
];
/// This function must be called whenever [FlutterProject.regeneratePlatformSpecificTooling]
/// or [FlutterProject.ensureReadyForPlatformSpecificTooling] is called.
///
/// See: [FlutterProject.ensureReadyForPlatformSpecificTooling] in `project.dart`
Future<void> ensureReadyForELinuxTooling(FlutterProject project) async {
if (!project.directory.existsSync() ||
project.hasExampleApp ||
project.isPlugin) {
return;
}
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
await eLinuxProject.ensureReadyForPlatformSpecificTooling();
await injectELinuxPlugins(project);
}
/// See: [injectPlugins] in `plugins.dart`
Future<void> injectELinuxPlugins(FlutterProject project) async {
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
if (eLinuxProject.existsSync()) {
final List<ELinuxPlugin> dartPlugins =
await findELinuxPlugins(project, dartOnly: true);
final List<ELinuxPlugin> nativePlugins =
await findELinuxPlugins(project, nativeOnly: true);
_writeDartPluginRegistrant(eLinuxProject.managedDirectory, dartPlugins);
_writePluginCmakefileTemplate(
eLinuxProject.managedDirectory, nativePlugins);
}
final List<String> plugins =
(await findPlugins(project)).map((Plugin p) => p.name).toList();
for (final String plugin in plugins) {
final String eLinuxPlugin = '${plugin}_elinux';
if (_knownPlugins.contains(plugin) && !plugins.contains(eLinuxPlugin)) {
globals.printStatus(
'$eLinuxPlugin is available on pub.dev. Did you forget to add to pubspec.yaml?',
color: TerminalColor.yellow,
);
}
}
}
/// Source: [findPlugins] in `plugins.dart`
Future<List<ELinuxPlugin>> findELinuxPlugins(
FlutterProject project, {
bool dartOnly = false,
bool nativeOnly = false,
bool throwOnError = true,
}) async {
final List<ELinuxPlugin> plugins = <ELinuxPlugin>[];
final File packagesFile = project.directory.childFile('.packages');
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
packagesFile,
logger: globals.logger,
throwOnError: throwOnError,
);
for (final Package package in packageConfig.packages) {
final Uri packageRoot = package.packageUriRoot.resolve('..');
final ELinuxPlugin plugin = _pluginFromPackage(package.name, packageRoot);
if (plugin == null) {
continue;
} else if (nativeOnly && plugin.pluginClass == null) {
continue;
} else if (dartOnly && plugin.dartPluginClass == null) {
continue;
}
plugins.add(plugin);
}
return plugins;
}
/// Source: [_pluginFromPackage] in `plugins.dart`
ELinuxPlugin _pluginFromPackage(String name, Uri packageRoot) {
final String pubspecPath =
globals.fs.path.fromUri(packageRoot.resolve('pubspec.yaml'));
if (!globals.fs.isFileSync(pubspecPath)) {
return null;
}
dynamic pubspec;
try {
pubspec = loadYaml(globals.fs.file(pubspecPath).readAsStringSync());
} on YamlException catch (err) {
globals.printTrace('Failed to parse plugin manifest for $name: $err');
}
if (pubspec == null) {
return null;
}
final dynamic flutterConfig = pubspec['flutter'];
if (flutterConfig == null || !(flutterConfig.containsKey('plugin') as bool)) {
return null;
}
final Directory packageDir = globals.fs.directory(packageRoot);
globals.printTrace('Found plugin $name at ${packageDir.path}');
final YamlMap pluginYaml = flutterConfig['plugin'] as YamlMap;
if (pluginYaml == null || pluginYaml['platforms'] == null) {
return null;
}
final YamlMap platformsYaml = pluginYaml['platforms'] as YamlMap;
if (platformsYaml == null || platformsYaml[ELinuxPlugin.kConfigKey] == null) {
return null;
}
return ELinuxPlugin.fromYaml(
name,
packageDir.childDirectory('elinux'),
platformsYaml[ELinuxPlugin.kConfigKey] as YamlMap,
);
}
/// See: [_writeWebPluginRegistrant] in `plugins.dart`
void _writeDartPluginRegistrant(
Directory registryDirectory,
List<ELinuxPlugin> plugins,
) {
final List<Map<String, dynamic>> pluginConfigs =
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
final Map<String, dynamic> context = <String, dynamic>{
'plugins': pluginConfigs,
};
_renderTemplateToFile(
'''
//
// Generated file. Do not edit.
//
// ignore_for_file: lines_longer_than_80_chars
{{#plugins}}
import 'package:{{name}}/{{name}}.dart';
{{/plugins}}
// ignore: public_member_api_docs
void registerPlugins() {
{{#plugins}}
{{dartPluginClass}}.register();
{{/plugins}}
}
''',
context,
registryDirectory.childFile('generated_plugin_registrant.dart').path,
);
}
/// See: [_writeWindowsPluginFiles] in `plugins.dart`
void _writePluginCmakefileTemplate(
Directory registryDirectory,
List<ELinuxPlugin> plugins,
) {
final List<Map<String, dynamic>> pluginConfigs =
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
final Map<String, dynamic> context = <String, dynamic>{
'plugins': pluginConfigs,
};
_renderTemplateToFile(
'''
//
// 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_
''',
context,
registryDirectory.childFile('generated_plugin_registrant.h').path,
);
_renderTemplateToFile(
'''
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}
''',
context,
registryDirectory.childFile('generated_plugin_registrant.cc').path,
);
_renderTemplateToFile(
r'''
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
{{#plugins}}
{{name}}
{{/plugins}}
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(
${USER_PROJECT_PATH}/flutter/plugins/${plugin}/elinux plugins/${plugin})
target_link_libraries(${TARGET}
PRIVATE
${plugin}_plugin
)
list(APPEND PLUGIN_BUNDLED_LIBRARIES
${PROJECT_BINARY_DIR}/plugins/${plugin}/lib${plugin}_plugin.so
)
endforeach(plugin)
''',
context,
registryDirectory.childFile('generated_plugins.cmake').path,
);
}
/// Source: [_renderTemplateToFile] in `plugins.dart` (exact copy)
void _renderTemplateToFile(String template, dynamic context, String filePath) {
final String renderedTemplate = globals.templateRenderer
.renderString(template, context, htmlEscapeValues: false);
final File file = globals.fs.file(filePath);
file.createSync(recursive: true);
file.writeAsStringSync(renderedTemplate);
}
+144
View File
@@ -0,0 +1,144 @@
// Copyright 2021 Sony Group Corporation. All rights reserved.
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:io';
import 'package:flutter_tools/executable.dart' as flutter;
import 'package:flutter_tools/runner.dart' as runner;
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/template.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/config.dart';
import 'package:flutter_tools/src/commands/devices.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/commands/emulators.dart';
import 'package:flutter_tools/src/commands/format.dart';
import 'package:flutter_tools/src/commands/generate_localizations.dart';
import 'package:flutter_tools/src/commands/install.dart';
import 'package:flutter_tools/src/commands/logs.dart';
import 'package:flutter_tools/src/commands/screenshot.dart';
import 'package:flutter_tools/src/commands/symbolize.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/isolated/mustache_template.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:path/path.dart';
import 'commands/analyze.dart';
import 'commands/attach.dart';
import 'commands/build.dart';
import 'commands/clean.dart';
import 'commands/create.dart';
import 'commands/drive.dart';
import 'commands/packages.dart';
import 'commands/precache.dart';
import 'commands/run.dart';
import 'commands/test.dart';
import 'elinux_cache.dart';
import 'elinux_device_discovery.dart';
import 'elinux_doctor.dart';
import 'elinux_package.dart';
/// Main entry point for commands.
///
/// Source: [flutter.main] in `executable.dart` (some commands and options were omitted)
Future<void> main(List<String> args) async {
final bool veryVerbose = args.contains('-vv');
final bool verbose =
args.contains('-v') || args.contains('--verbose') || veryVerbose;
final bool doctor = (args.isNotEmpty && args.first == 'doctor') ||
(args.length == 2 && verbose && args.last == 'doctor');
final bool help = args.contains('-h') ||
args.contains('--help') ||
(args.isNotEmpty && args.first == 'help') ||
(args.length == 1 && verbose);
final bool muteCommandLogging = (help || doctor) && !veryVerbose;
final bool verboseHelp = help && verbose;
final bool hasSpecifiedDeviceId =
args.contains('-d') || args.contains('--device-id');
args = <String>[
'--suppress-analytics', // Suppress flutter analytics by default.
'--no-version-check',
if (!hasSpecifiedDeviceId) ...<String>['--device-id', 'elinux'],
...args,
];
Cache.flutterRoot = join(rootPath, 'flutter');
await runner.run(
args,
() => <FlutterCommand>[
// Commands directly from flutter_tools.
ConfigCommand(verboseHelp: verboseHelp),
DevicesCommand(verboseHelp: verboseHelp),
DoctorCommand(verbose: verbose),
EmulatorsCommand(),
FormatCommand(),
GenerateLocalizationsCommand(
fileSystem: globals.fs,
logger: globals.logger,
),
InstallCommand(),
LogsCommand(),
ScreenshotCommand(),
SymbolizeCommand(stdio: globals.stdio, fileSystem: globals.fs),
// Commands extended for ELinux.
ELinuxAnalyzeCommand(verboseHelp: verboseHelp),
ELinuxAttachCommand(verboseHelp: verboseHelp),
ELinuxBuildCommand(verboseHelp: verboseHelp),
ELinuxCleanCommand(verbose: verbose),
ELinuxCreateCommand(verboseHelp: verboseHelp),
ELinuxDriveCommand(verboseHelp: verboseHelp),
ELinuxPackagesCommand(),
ELinuxPrecacheCommand(
verboseHelp: verboseHelp,
cache: globals.cache,
logger: globals.logger,
platform: globals.platform,
featureFlags: featureFlags,
),
ELinuxRunCommand(verboseHelp: verboseHelp),
ELinuxTestCommand(verboseHelp: verboseHelp),
],
verbose: verbose,
verboseHelp: verboseHelp,
muteCommandLogging: muteCommandLogging,
reportCrashes: false,
overrides: <Type, Generator>{
Cache: () => ELinuxFlutterCache(
fileSystem: globals.fs,
logger: globals.logger,
platform: globals.platform,
osUtils: globals.os,
),
TemplateRenderer: () => const MustacheTemplateRenderer(),
ApplicationPackageFactory: () => ELinuxApplicationPackageFactory(),
DeviceManager: () => ELinuxDeviceManager(),
DoctorValidatorsProvider: () => ELinuxDoctorValidatorsProvider(),
ELinuxWorkflow: () => ELinuxWorkflow(
operatingSystemUtils: globals.os,
),
ELinuxValidator: () => ELinuxValidator(),
},
);
}
/// See: [Cache.defaultFlutterRoot] in `cache.dart`
String get rootPath {
final String scriptPath = Platform.script.toFilePath();
return normalize(join(
scriptPath,
scriptPath.endsWith('.snapshot') ? '../../..' : '../..',
));
}
+26
View File
@@ -0,0 +1,26 @@
name: flutter_elinux
description: Flutter application build tools for Embedded Linux devices
homepage: https://github.com/sony/flutter-embedded-linux
version: 2.2.1
publish_to: none
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter_tools:
path: flutter/packages/flutter_tools
file: # inherit from flutter_tools
meta:
package_config:
path:
process:
xml:
yaml:
dev_dependencies:
flutter_test:
sdk: flutter
mockito:
pedantic:
test:
+104
View File
@@ -0,0 +1,104 @@
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
set(BINARY_NAME "{{projectName}}")
cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# 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()
# Configure build option to target backend.
if (NOT FLUTTER_TARGET_BACKEND_TYPE)
set(FLUTTER_TARGET_BACKEND_TYPE "wayland" CACHE
STRING "Flutter target backend type" FORCE)
set_property(CACHE FLUTTER_TARGET_BACKEND_TYPE PROPERTY STRINGS
"wayland" "gbm" "eglstream" "x11")
endif()
# Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
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_subdirectory("runner")
# 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()
# 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)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_EMBEDDER_LIBRARY}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# 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 AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
+108
View File
@@ -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)
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# 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 ===
# System-level dependencies.
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_engine.so")
if(FLUTTER_TARGET_BACKEND_TYPE MATCHES "gbm")
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_gbm.so")
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "eglstream")
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_eglstream.so")
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "x11")
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_x11.so")
else()
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_wayland.so")
endif()
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_EMBEDDER_LIBRARY ${FLUTTER_EMBEDDER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/elinux/" PARENT_SCOPE)
set(AOT_LIBRARY "${EPHEMERAL_DIR}/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"flutter_plugin_registrar.h"
"flutter_messenger.h"
"flutter_texture_registrar.h"
"flutter_elinux.h"
"flutter_platform_views.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE "${FLUTTER_EMBEDDER_LIBRARY}")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc"
"standard_codec.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_view_controller.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${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)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
"${FLUTTER_EMBEDDER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)
+23
View File
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
if(FLUTTER_TARGET_BACKEND_TYPE MATCHES "gbm")
add_definitions(-DFLUTTER_TARGET_BACKEND_GBM)
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "eglstream")
add_definitions(-DFLUTTER_TARGET_BACKEND_EGLSTREAM)
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "x11")
add_definitions(-DFLUTTER_TARGET_BACKEND_X11)
else()
add_definitions(-DFLUTTER_TARGET_BACKEND_WAYLAND)
endif()
add_executable(${BINARY_NAME}
"flutter_window.cc"
"main.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
apply_standard_settings(${BINARY_NAME})
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
add_dependencies(${BINARY_NAME} flutter_assemble)
+367
View File
@@ -0,0 +1,367 @@
// Copyright 2021 Sony Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMMAND_OPTIONS_
#define COMMAND_OPTIONS_
#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
// todo: Supports other types besides int, string.
namespace commandline {
namespace {
constexpr char kOptionStyleNormal[] = "--";
constexpr char kOptionStyleShort[] = "-";
constexpr char kOptionValueForHelpMessage[] = "=<value>";
} // namespace
class Exception : public std::exception {
public:
Exception(const std::string& msg) : msg_(msg) {}
~Exception() throw() {}
const char* what() const throw() { return msg_.c_str(); }
private:
std::string msg_;
};
class CommandOptions {
public:
CommandOptions() = default;
~CommandOptions() = default;
void AddWithoutValue(const std::string& name, const std::string& short_name,
const std::string& description, bool required) {
Add<std::string, ReaderString>(name, short_name, description, "",
ReaderString(), required, false);
}
void AddInt(const std::string& name, const std::string& short_name,
const std::string& description, const int& default_value,
bool required) {
Add<int, ReaderInt>(name, short_name, description, default_value,
ReaderInt(), required, true);
}
void AddString(const std::string& name, const std::string& short_name,
const std::string& description,
const std::string& default_value, bool required) {
Add<std::string, ReaderString>(name, short_name, description, default_value,
ReaderString(), required, true);
}
template <typename T, typename F>
void Add(const std::string& name, const std::string& short_name,
const std::string& description, const T default_value,
F reader = F(), bool required = true, bool required_value = true) {
if (options_.find(name) != options_.end()) {
std::cerr << "Already registered option: " << name << std::endl;
return;
}
if (lut_short_options_.find(short_name) != lut_short_options_.end()) {
std::cerr << short_name << "is already registered" << std::endl;
return;
}
lut_short_options_[short_name] = name;
options_[name] = std::make_unique<OptionValueReader<T, F>>(
name, short_name, description, default_value, reader, required,
required_value);
// register to show help message.
registration_order_options_.push_back(options_[name].get());
}
bool Exist(const std::string& name) {
auto itr = options_.find(name);
return itr != options_.end() && itr->second->HasValue();
}
template <typename T>
const T& GetValue(const std::string& name) {
auto itr = options_.find(name);
if (itr == options_.end()) {
throw Exception("Not found: " + name);
}
auto* option_value = dynamic_cast<const OptionValue<T>*>(itr->second.get());
if (!option_value) {
throw Exception("Type mismatch: " + name);
}
return option_value->GetValue();
}
bool Parse(int argc, const char* const* argv) {
if (argc < 1) {
errors_.push_back("No options");
return false;
}
command_name_ = argv[0];
for (auto i = 1; i < argc; i++) {
const std::string arg(argv[i]);
// normal options: e.g. --bundle=/data/sample/bundle --fullscreen
if (arg.length() > 2 &&
arg.substr(0, 2).compare(kOptionStyleNormal) == 0) {
const size_t option_value_len = arg.find("=") != std::string::npos
? (arg.length() - arg.find("="))
: 0;
const bool has_value = option_value_len != 0;
std::string option_name =
arg.substr(2, arg.length() - 2 - option_value_len);
if (options_.find(option_name) == options_.end()) {
errors_.push_back("Not found option: " + option_name);
continue;
}
if (!has_value && options_[option_name]->IsRequiredValue()) {
errors_.push_back(option_name + " requres an option value");
continue;
}
if (has_value && !options_[option_name]->IsRequiredValue()) {
errors_.push_back(option_name + " doesn't requres an option value");
continue;
}
if (has_value) {
SetOptionValue(option_name, arg.substr(arg.find("=") + 1));
} else {
SetOption(option_name);
}
}
// short options: e.g. -f /foo/file.txt -h 640 -abc
else if (arg.length() > 1 &&
arg.substr(0, 1).compare(kOptionStyleShort) == 0) {
for (size_t j = 1; j < arg.length(); j++) {
const std::string option_name{argv[i][j]};
if (lut_short_options_.find(option_name) ==
lut_short_options_.end()) {
errors_.push_back("Not found short option: " + option_name);
break;
}
if (j == arg.length() - 1 &&
options_[lut_short_options_[option_name]]->IsRequiredValue()) {
if (i == argc - 1) {
errors_.push_back("Invalid format option: " + option_name);
break;
}
SetOptionValue(lut_short_options_[option_name], argv[++i]);
} else {
SetOption(lut_short_options_[option_name]);
}
}
} else {
errors_.push_back("Invalid format option: " + arg);
}
}
for (size_t i = 0; i < registration_order_options_.size(); i++) {
if (registration_order_options_[i]->IsRequired() &&
!registration_order_options_[i]->HasValue()) {
errors_.push_back(
std::string(registration_order_options_[i]->GetName()) +
" option is mandatory.");
}
}
return errors_.size() == 0;
}
std::string GetError() { return errors_.size() > 0 ? errors_[0] : ""; }
std::vector<std::string>& GetErrors() { return errors_; }
std::string ShowHelp() {
std::ostringstream ostream;
ostream << "Usage: " << command_name_ << " ";
for (size_t i = 0; i < registration_order_options_.size(); i++) {
if (registration_order_options_[i]->IsRequired()) {
ostream << registration_order_options_[i]->GetHelpShortMessage() << " ";
}
}
ostream << std::endl;
ostream << "Global options:" << std::endl;
size_t max_name_len = 0;
for (size_t i = 0; i < registration_order_options_.size(); i++) {
max_name_len = std::max(
max_name_len, registration_order_options_[i]->GetName().length());
}
for (size_t i = 0; i < registration_order_options_.size(); i++) {
if (!registration_order_options_[i]->GetShortName().empty()) {
ostream << kOptionStyleShort
<< registration_order_options_[i]->GetShortName() << ", ";
} else {
ostream << std::string(4, ' ');
}
size_t index_adjust = 0;
constexpr int kSpacerNum = 5;
auto need_value = registration_order_options_[i]->IsRequiredValue();
ostream << kOptionStyleNormal
<< registration_order_options_[i]->GetName();
if (need_value) {
ostream << kOptionValueForHelpMessage;
index_adjust += std::string(kOptionValueForHelpMessage).length();
}
ostream << std::string(
max_name_len + kSpacerNum - index_adjust -
registration_order_options_[i]->GetName().length(),
' ');
ostream << registration_order_options_[i]->GetDescription() << std::endl;
}
return ostream.str();
}
private:
struct ReaderInt {
int operator()(const std::string& value) { return std::stoi(value); }
};
struct ReaderString {
std::string operator()(const std::string& value) { return value; }
};
class Option {
public:
Option(const std::string& name, const std::string& short_name,
const std::string& description, bool required, bool required_value)
: name_(name),
short_name_(short_name),
description_(description),
is_required_(required),
is_required_value_(required_value),
value_set_(false){};
virtual ~Option() = default;
const std::string& GetName() const { return name_; };
const std::string& GetShortName() const { return short_name_; };
const std::string& GetDescription() const { return description_; };
const std::string GetHelpShortMessage() const {
std::string message = kOptionStyleNormal + name_;
if (is_required_value_) {
message += kOptionValueForHelpMessage;
}
return message;
}
bool IsRequired() const { return is_required_; };
bool IsRequiredValue() const { return is_required_value_; };
void Set() { value_set_ = true; };
virtual bool SetValue(const std::string& value) = 0;
virtual bool HasValue() const = 0;
protected:
std::string name_;
std::string short_name_;
std::string description_;
bool is_required_;
bool is_required_value_;
bool value_set_;
};
template <typename T>
class OptionValue : public Option {
public:
OptionValue(const std::string& name, const std::string& short_name,
const std::string& description, const T& default_value,
bool required, bool required_value)
: Option(name, short_name, description, required, required_value),
default_value_(default_value),
value_(default_value){};
virtual ~OptionValue() = default;
bool SetValue(const std::string& value) {
value_ = Read(value);
value_set_ = true;
return true;
}
bool HasValue() const { return value_set_; }
const T& GetValue() const { return value_; }
protected:
virtual T Read(const std::string& s) = 0;
T default_value_;
T value_;
};
template <typename T, typename F>
class OptionValueReader : public OptionValue<T> {
public:
OptionValueReader(const std::string& name, const std::string& short_name,
const std::string& description, const T default_value,
F reader, bool required, bool required_value)
: OptionValue<T>(name, short_name, description, default_value, required,
required_value),
reader_(reader) {}
~OptionValueReader() = default;
private:
T Read(const std::string& value) { return reader_(value); }
F reader_;
};
bool SetOption(const std::string& name) {
auto itr = options_.find(name);
if (itr == options_.end()) {
errors_.push_back("Unknown option: " + name);
return false;
}
itr->second->Set();
return true;
}
bool SetOptionValue(const std::string& name, const std::string& value) {
auto itr = options_.find(name);
if (itr == options_.end()) {
errors_.push_back("Unknown option: " + name);
return false;
}
if (!itr->second->SetValue(value)) {
errors_.push_back("Invalid option value: " + name + " = " + value);
return false;
}
return true;
}
std::string command_name_;
std::unordered_map<std::string, std::unique_ptr<Option>> options_;
std::unordered_map<std::string, std::string> lut_short_options_;
std::vector<Option*> registration_order_options_;
std::vector<std::string> errors_;
};
} // namespace commandline
#endif // COMMAND_OPTIONS_
@@ -0,0 +1,103 @@
// Copyright 2021 Sony Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_EMBEDDER_OPTIONS_
#define FLUTTER_EMBEDDER_OPTIONS_
#include <flutter/flutter_view_controller.h>
#include <string>
#include "command_options.h"
class FlutterEmbedderOptions {
public:
FlutterEmbedderOptions() {
options_.AddString("bundle", "b", "Path to Flutter app bundle", "./bundle",
true);
options_.AddWithoutValue("no-cursor", "n", "No mouse cursor/pointer",
false);
#if defined(FLUTTER_TARGET_BACKEND_GBM) || \
defined(FLUTTER_TARGET_BACKEND_EGLSTREAM)
// no more options.
#elif defined(FLUTTER_TARGET_BACKEND_X11)
options_.AddWithoutValue("fullscreen", "f", "Always full-screen display",
false);
options_.AddInt("width", "w", "Flutter app window width", 1280, false);
options_.AddInt("height", "h", "Flutter app window height", 720, false);
#else // FLUTTER_TARGET_BACKEND_WAYLAND
options_.AddWithoutValue("onscreen-keyboard", "k",
"Enable on-screen keyboard", false);
options_.AddWithoutValue("window-decoration", "d",
"Enable window decorations", false);
options_.AddWithoutValue("fullscreen", "f", "Always full-screen display",
false);
options_.AddInt("width", "w", "Flutter app window width", 1280, false);
options_.AddInt("height", "h", "Flutter app window height", 720, false);
#endif
}
~FlutterEmbedderOptions() = default;
bool Parse(int argc, char** argv) {
if (!options_.Parse(argc, argv)) {
std::cerr << options_.GetError() << std::endl;
std::cout << options_.ShowHelp();
return false;
}
bundle_path_ = options_.GetValue<std::string>("bundle");
use_mouse_cursor_ = !options_.Exist("no-cursor");
#if defined(FLUTTER_TARGET_BACKEND_GBM) || \
defined(FLUTTER_TARGET_BACKEND_EGLSTREAM)
use_onscreen_keyboard_ = false;
use_window_decoration_ = false;
window_view_mode_ = flutter::FlutterViewController::ViewMode::kFullscreen;
#elif defined(FLUTTER_TARGET_BACKEND_X11)
use_onscreen_keyboard_ = false;
use_window_decoration_ = false;
window_view_mode_ =
options_.Exist("fullscreen")
? flutter::FlutterViewController::ViewMode::kFullscreen
: flutter::FlutterViewController::ViewMode::kNormal;
window_width_ = options_.GetValue<int>("width");
window_height_ = options_.GetValue<int>("height");
#else // FLUTTER_TARGET_BACKEND_WAYLAND
use_onscreen_keyboard_ = options_.Exist("onscreen-keyboard");
use_window_decoration_ = options_.Exist("window-decoration");
window_view_mode_ =
options_.Exist("fullscreen")
? flutter::FlutterViewController::ViewMode::kFullscreen
: flutter::FlutterViewController::ViewMode::kNormal;
window_width_ = options_.GetValue<int>("width");
window_height_ = options_.GetValue<int>("height");
#endif
return true;
}
std::string BundlePath() const { return bundle_path_; }
bool IsUseMouseCursor() const { return use_mouse_cursor_; }
bool IsUseOnscreenKeyboard() const { return use_onscreen_keyboard_; }
bool IsUseWindowDecoraation() const { return use_window_decoration_; }
flutter::FlutterViewController::ViewMode WindowViewMode() const {
return window_view_mode_;
}
int WindowWidth() const { return window_width_; }
int WindowHeight() const { return window_height_; }
private:
commandline::CommandOptions options_;
std::string bundle_path_;
bool use_mouse_cursor_ = true;
bool use_onscreen_keyboard_ = false;
bool use_window_decoration_ = false;
flutter::FlutterViewController::ViewMode window_view_mode_ =
flutter::FlutterViewController::ViewMode::kNormal;
int window_width_ = 1280;
int window_height_ = 720;
};
#endif // FLUTTER_EMBEDDER_OPTIONS_
+79
View File
@@ -0,0 +1,79 @@
// Copyright 2021 Sony Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter_window.h"
#include <chrono>
#include <cmath>
#include <iostream>
#include <thread>
#include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(
const flutter::FlutterViewController::ViewProperties view_properties,
const flutter::DartProject project)
: view_properties_(view_properties), project_(project) {}
bool FlutterWindow::OnCreate() {
flutter_view_controller_ = std::make_unique<flutter::FlutterViewController>(
view_properties_, project_);
// Ensure that basic setup of the controller was successful.
if (!flutter_view_controller_->engine() ||
!flutter_view_controller_->view()) {
return false;
}
// Register Flutter plugins.
RegisterPlugins(flutter_view_controller_->engine());
return true;
}
void FlutterWindow::OnDestroy() {
if (flutter_view_controller_) {
flutter_view_controller_ = nullptr;
}
}
void FlutterWindow::Run() {
// Main loop.
auto next_flutter_event_time =
std::chrono::steady_clock::time_point::clock::now();
while (flutter_view_controller_->view()->DispatchEvent()) {
// Wait until the next event.
{
auto wait_duration =
std::max(std::chrono::nanoseconds(0),
next_flutter_event_time -
std::chrono::steady_clock::time_point::clock::now());
std::this_thread::sleep_for(
std::chrono::duration_cast<std::chrono::milliseconds>(wait_duration));
}
// Processes any pending events in the Flutter engine, and returns the
// number of nanoseconds until the next scheduled event (or max, if none).
auto wait_duration = flutter_view_controller_->engine()->ProcessMessages();
{
auto next_event_time = std::chrono::steady_clock::time_point::max();
if (wait_duration != std::chrono::nanoseconds::max()) {
next_event_time =
std::min(next_event_time,
std::chrono::steady_clock::time_point::clock::now() +
wait_duration);
} else {
// Wait for the next frame if no events.
auto frame_rate = flutter_view_controller_->view()->GetFrameRate();
next_event_time = std::min(
next_event_time,
std::chrono::steady_clock::time_point::clock::now() +
std::chrono::milliseconds(
static_cast<int>(std::trunc(1000000.0 / frame_rate))));
}
next_flutter_event_time =
std::max(next_flutter_event_time, next_event_time);
}
}
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2021 Sony Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_WINDOW_
#define FLUTTER_WINDOW_
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <memory>
class FlutterWindow {
public:
explicit FlutterWindow(
const flutter::FlutterViewController::ViewProperties view_properties,
const flutter::DartProject project);
~FlutterWindow() = default;
// Prevent copying.
FlutterWindow(FlutterWindow const&) = delete;
FlutterWindow& operator=(FlutterWindow const&) = delete;
bool OnCreate();
void OnDestroy();
void Run();
private:
flutter::FlutterViewController::ViewProperties view_properties_;
flutter::DartProject project_;
std::unique_ptr<flutter::FlutterViewController> flutter_view_controller_;
};
#endif // FLUTTER_WINDOW_
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2021 Sony Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <iostream>
#include <memory>
#include <string>
#include "flutter_embedder_options.h"
#include "flutter_window.h"
int main(int argc, char** argv) {
FlutterEmbedderOptions options;
if (!options.Parse(argc, argv)) {
return 0;
}
// Creates the Flutter project.
const auto bundle_path = options.BundlePath();
const std::wstring fl_path(bundle_path.begin(), bundle_path.end());
flutter::DartProject project(fl_path);
auto command_line_arguments = std::vector<std::string>();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
flutter::FlutterViewController::ViewProperties view_properties = {};
view_properties.width = options.WindowWidth();
view_properties.height = options.WindowHeight();
view_properties.view_mode = options.WindowViewMode();
view_properties.use_mouse_cursor = options.IsUseMouseCursor();
view_properties.use_onscreen_keyboard = options.IsUseOnscreenKeyboard();
view_properties.use_window_decoration = options.IsUseWindowDecoraation();
// The Flutter instance hosted by this window.
FlutterWindow window(view_properties, project);
if (!window.OnCreate()) {
std::cerr << "Failed to create a Flutter window." << std::endl;
return 0;
}
window.Run();
window.OnDestroy();
return 0;
}
+293
View File
@@ -0,0 +1,293 @@
{
"version": 1.0,
"_comment": "A listing of all possible template output files.",
"files": [
"templates/app/elinux.tmpl/.gitignore",
"templates/app/elinux.tmpl/CMakeLists.txt.tmpl",
"templates/app/elinux.tmpl/flutter/CMakeLists.txt",
"templates/app/elinux.tmpl/runner/CMakeLists.txt",
"templates/app/elinux.tmpl/runner/command_options.h",
"templates/app/elinux.tmpl/runner/flutter_embedder_options.h",
"templates/app/elinux.tmpl/runner/flutter_window.cc",
"templates/app/elinux.tmpl/runner/flutter_window.h",
"templates/app/elinux.tmpl/runner/main.cc",
"templates/app/.gitignore.tmpl",
"templates/app/.idea/libraries/Dart_SDK.xml.tmpl",
"templates/app/.idea/libraries/KotlinJavaRuntime.xml.tmpl",
"templates/app/.idea/modules.xml.tmpl",
"templates/app/.idea/runConfigurations/main_dart.xml.tmpl",
"templates/app/.idea/workspace.xml.tmpl",
"templates/app/.metadata.tmpl",
"templates/app/android-java.tmpl/app/build.gradle.tmpl",
"templates/app/android-java.tmpl/app/src/main/java/androidIdentifier/MainActivity.java.tmpl",
"templates/app/android-java.tmpl/build.gradle",
"templates/app/android-java.tmpl/projectName_android.iml.tmpl",
"templates/app/android-kotlin.tmpl/app/build.gradle.tmpl",
"templates/app/android-kotlin.tmpl/app/src/main/kotlin/androidIdentifier/MainActivity.kt.tmpl",
"templates/app/android-kotlin.tmpl/build.gradle",
"templates/app/android-kotlin.tmpl/projectName_android.iml.tmpl",
"templates/app/android.tmpl/.gitignore",
"templates/app/android.tmpl/app/src/debug/AndroidManifest.xml.tmpl",
"templates/app/android.tmpl/app/src/main/AndroidManifest.xml.tmpl",
"templates/app/android.tmpl/app/src/main/res/drawable/launch_background.xml",
"templates/app/android.tmpl/app/src/main/res/drawable-v21/launch_background.xml",
"templates/app/android.tmpl/app/src/main/res/mipmap-hdpi/ic_launcher.png",
"templates/app/android.tmpl/app/src/main/res/mipmap-mdpi/ic_launcher.png",
"templates/app/android.tmpl/app/src/main/res/mipmap-xhdpi/ic_launcher.png",
"templates/app/android.tmpl/app/src/main/res/mipmap-xxhdpi/ic_launcher.png",
"templates/app/android.tmpl/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png",
"templates/app/android.tmpl/app/src/main/res/values/styles.xml",
"templates/app/android.tmpl/app/src/main/res/values-night/styles.xml",
"templates/app/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl",
"templates/app/android.tmpl/gradle/wrapper/gradle-wrapper.properties",
"templates/app/android.tmpl/gradle.properties.tmpl",
"templates/app/android.tmpl/settings.gradle",
"templates/app/ios-objc.tmpl/Runner/AppDelegate.h",
"templates/app/ios-objc.tmpl/Runner/AppDelegate.m",
"templates/app/ios-objc.tmpl/Runner/main.m",
"templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
"templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"templates/app/ios-swift.tmpl/Runner/AppDelegate.swift",
"templates/app/ios-swift.tmpl/Runner/Runner-Bridging-Header.h",
"templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
"templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"templates/app/ios.tmpl/.gitignore",
"templates/app/ios.tmpl/Flutter/AppFrameworkInfo.plist",
"templates/app/ios.tmpl/Flutter/Debug.xcconfig",
"templates/app/ios.tmpl/Flutter/Release.xcconfig",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png",
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"templates/app/ios.tmpl/Runner/Base.lproj/LaunchScreen.storyboard",
"templates/app/ios.tmpl/Runner/Base.lproj/Main.storyboard",
"templates/app/ios.tmpl/Runner/Info.plist.tmpl",
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"templates/app/ios.tmpl/Runner.xcworkspace/contents.xcworkspacedata",
"templates/app/ios.tmpl/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"templates/app/ios.tmpl/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"templates/app/lib/main.dart.tmpl",
"templates/app/linux.tmpl/my_application.cc.tmpl",
"templates/app/linux.tmpl/.gitignore",
"templates/app/linux.tmpl/CMakeLists.txt.tmpl",
"templates/app/linux.tmpl/flutter/CMakeLists.txt",
"templates/app/linux.tmpl/main.cc",
"templates/app/linux.tmpl/my_application.cc",
"templates/app/linux.tmpl/my_application.h",
"templates/app/macos.tmpl/.gitignore",
"templates/app/macos.tmpl/Flutter/Flutter-Debug.xcconfig",
"templates/app/macos.tmpl/Flutter/Flutter-Release.xcconfig",
"templates/app/macos.tmpl/Runner/AppDelegate.swift",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png",
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"templates/app/macos.tmpl/Runner/Base.lproj/MainMenu.xib",
"templates/app/macos.tmpl/Runner/Configs/AppInfo.xcconfig.tmpl",
"templates/app/macos.tmpl/Runner/Configs/Debug.xcconfig",
"templates/app/macos.tmpl/Runner/Configs/Release.xcconfig",
"templates/app/macos.tmpl/Runner/Configs/Warnings.xcconfig",
"templates/app/macos.tmpl/Runner/DebugProfile.entitlements",
"templates/app/macos.tmpl/Runner/Info.plist",
"templates/app/macos.tmpl/Runner/MainFlutterWindow.swift",
"templates/app/macos.tmpl/Runner/Release.entitlements",
"templates/app/macos.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
"templates/app/macos.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"templates/app/macos.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl",
"templates/app/macos.tmpl/Runner.xcworkspace/contents.xcworkspacedata",
"templates/app/macos.tmpl/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"templates/app/projectName.iml.tmpl",
"templates/app/pubspec.yaml.tmpl",
"templates/app/README.md.tmpl",
"templates/app/test/widget_test.dart.tmpl",
"templates/app/web/favicon.png.copy.tmpl",
"templates/app/web/icons/Icon-192.png.copy.tmpl",
"templates/app/web/icons/Icon-512.png.copy.tmpl",
"templates/app/web/index.html.tmpl",
"templates/app/web/manifest.json.tmpl",
"templates/app/windows.tmpl/.gitignore",
"templates/app/windows.tmpl/CMakeLists.txt.tmpl",
"templates/app/windows.tmpl/flutter/CMakeLists.txt",
"templates/app/windows.tmpl/runner/CMakeLists.txt",
"templates/app/windows.tmpl/runner/flutter_window.cpp",
"templates/app/windows.tmpl/runner/flutter_window.h",
"templates/app/windows.tmpl/runner/main.cpp.tmpl",
"templates/app/windows.tmpl/runner/resource.h",
"templates/app/windows.tmpl/runner/resources/app_icon.ico.img.tmpl",
"templates/app/windows.tmpl/runner/runner.exe.manifest",
"templates/app/windows.tmpl/runner/Runner.rc.tmpl",
"templates/app/windows.tmpl/runner/run_loop.cpp",
"templates/app/windows.tmpl/runner/run_loop.h",
"templates/app/windows.tmpl/runner/utils.cpp",
"templates/app/windows.tmpl/runner/utils.h",
"templates/app/windows.tmpl/runner/win32_window.cpp",
"templates/app/windows.tmpl/runner/win32_window.h",
"templates/app/winuwp.tmpl/project_version",
"templates/cocoapods/Podfile-ios-objc",
"templates/cocoapods/Podfile-ios-swift",
"templates/cocoapods/Podfile-macos",
"templates/module/android/deferred_component/build.gradle.tmpl",
"templates/module/android/deferred_component/src/main/AndroidManifest.xml.tmpl",
"templates/module/android/gradle/build.gradle.copy.tmpl",
"templates/module/android/gradle/gradle.properties.tmpl",
"templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl",
"templates/module/android/host_app_common/app.tmpl/src/main/AndroidManifest.xml.tmpl",
"templates/module/android/host_app_common/app.tmpl/src/main/java/androidIdentifier/host/MainActivity.java.tmpl",
"templates/module/android/host_app_common/app.tmpl/src/main/res/drawable/launch_background.xml",
"templates/module/android/host_app_common/app.tmpl/src/main/res/mipmap-hdpi/ic_launcher.png",
"templates/module/android/host_app_common/app.tmpl/src/main/res/values/styles.xml",
"templates/module/android/host_app_editable/settings.gradle.copy.tmpl",
"templates/module/android/host_app_ephemeral/settings.gradle.copy.tmpl",
"templates/module/android/library/Flutter.tmpl/build.gradle.tmpl",
"templates/module/android/library/Flutter.tmpl/flutter.iml.copy.tmpl",
"templates/module/android/library/Flutter.tmpl/src/main/AndroidManifest.xml.tmpl",
"templates/module/android/library/Flutter.tmpl/src/main/java/io/flutter/facade/Flutter.java.tmpl",
"templates/module/android/library/Flutter.tmpl/src/main/java/io/flutter/facade/FlutterFragment.java.tmpl",
"templates/module/android/library/include_flutter.groovy.copy.tmpl",
"templates/module/android/library/settings.gradle.copy.tmpl",
"templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl",
"templates/module/android/library_new_embedding/Flutter.tmpl/flutter.iml.copy.tmpl",
"templates/module/android/library_new_embedding/Flutter.tmpl/src/main/AndroidManifest.xml.tmpl",
"templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl",
"templates/module/android/library_new_embedding/settings.gradle.copy.tmpl",
"templates/module/common/.gitignore.tmpl",
"templates/module/common/.idea/libraries/Dart_SDK.xml.tmpl",
"templates/module/common/.idea/modules.xml.tmpl",
"templates/module/common/.idea/workspace.xml.tmpl",
"templates/module/common/.metadata.tmpl",
"templates/module/common/lib/main.dart.tmpl",
"templates/module/common/projectName.iml.tmpl",
"templates/module/common/projectName_android.iml.tmpl",
"templates/module/common/pubspec.yaml.tmpl",
"templates/module/common/README.md.tmpl",
"templates/module/common/test/widget_test.dart.tmpl",
"templates/module/ios/host_app_ephemeral/Config.tmpl/Debug.xcconfig",
"templates/module/ios/host_app_ephemeral/Config.tmpl/Flutter.xcconfig",
"templates/module/ios/host_app_ephemeral/Config.tmpl/Release.xcconfig",
"templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/AppDelegate.h",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/AppDelegate.m",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Contents.json",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/Contents.json",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/README.md",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Base.lproj/LaunchScreen.storyboard",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Base.lproj/Main.storyboard",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl",
"templates/module/ios/host_app_ephemeral/Runner.tmpl/main.m",
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl",
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata",
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme",
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/contents.xcworkspacedata",
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist",
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings",
"templates/module/ios/host_app_ephemeral_cocoapods/Config.tmpl/Debug.xcconfig",
"templates/module/ios/host_app_ephemeral_cocoapods/Config.tmpl/Release.xcconfig",
"templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl",
"templates/module/ios/host_app_ephemeral_cocoapods/Runner.tmpl/AppDelegate.m",
"templates/module/ios/library/Flutter.tmpl/AppFrameworkInfo.plist",
"templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl",
"templates/module/ios/library/Flutter.tmpl/projectName.podspec.tmpl",
"templates/module/ios/library/Flutter.tmpl/README.md",
"templates/module/README.md",
"templates/package/.gitignore.tmpl",
"templates/package/.idea/libraries/Dart_SDK.xml.tmpl",
"templates/package/.idea/modules.xml.tmpl",
"templates/package/.idea/workspace.xml.tmpl",
"templates/package/.metadata.tmpl",
"templates/package/CHANGELOG.md.tmpl",
"templates/package/lib/projectName.dart.tmpl",
"templates/package/LICENSE.tmpl",
"templates/package/projectName.iml.tmpl",
"templates/package/pubspec.yaml.tmpl",
"templates/package/README.md.tmpl",
"templates/package/test/projectName_test.dart.tmpl",
"templates/plugin/.gitignore.tmpl",
"templates/plugin/.idea/libraries/Dart_SDK.xml.tmpl",
"templates/plugin/.idea/modules.xml.tmpl",
"templates/plugin/.idea/runConfigurations/example_lib_main_dart.xml.tmpl",
"templates/plugin/.idea/workspace.xml.tmpl",
"templates/plugin/.metadata.tmpl",
"templates/plugin/android-java.tmpl/build.gradle.tmpl",
"templates/plugin/android-java.tmpl/projectName_android.iml.tmpl",
"templates/plugin/android-java.tmpl/src/main/java/androidIdentifier/pluginClass.java.tmpl",
"templates/plugin/android-kotlin.tmpl/build.gradle.tmpl",
"templates/plugin/android-kotlin.tmpl/projectName_android.iml.tmpl",
"templates/plugin/android-kotlin.tmpl/src/main/kotlin/androidIdentifier/pluginClass.kt.tmpl",
"templates/plugin/android.tmpl/.gitignore",
"templates/plugin/android.tmpl/gradle/wrapper/gradle-wrapper.properties",
"templates/plugin/android.tmpl/gradle.properties.tmpl",
"templates/plugin/android.tmpl/settings.gradle.tmpl",
"templates/plugin/android.tmpl/src/main/AndroidManifest.xml.tmpl",
"templates/plugin/CHANGELOG.md.tmpl",
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.h.tmpl",
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.m.tmpl",
"templates/plugin/ios-objc.tmpl/projectName.podspec.tmpl",
"templates/plugin/ios-swift.tmpl/Classes/pluginClass.h.tmpl",
"templates/plugin/ios-swift.tmpl/Classes/pluginClass.m.tmpl",
"templates/plugin/ios-swift.tmpl/Classes/SwiftpluginClass.swift.tmpl",
"templates/plugin/ios-swift.tmpl/projectName.podspec.tmpl",
"templates/plugin/ios.tmpl/.gitignore",
"templates/plugin/ios.tmpl/Assets/.gitkeep",
"templates/plugin/lib/projectName.dart.tmpl",
"templates/plugin/LICENSE.tmpl",
"templates/plugin/linux.tmpl/CMakeLists.txt.tmpl",
"templates/plugin/linux.tmpl/include/projectName.tmpl/pluginClassSnakeCase.h.tmpl",
"templates/plugin/linux.tmpl/pluginClassSnakeCase.cc.tmpl",
"templates/plugin/macos.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin/macos.tmpl/projectName.podspec.tmpl",
"templates/plugin/projectName.iml.tmpl",
"templates/plugin/pubspec.yaml.tmpl",
"templates/plugin/README.md.tmpl",
"templates/plugin/test/projectName_test.dart.tmpl",
"templates/plugin/windows.tmpl/.gitignore",
"templates/plugin/windows.tmpl/CMakeLists.txt.tmpl",
"templates/plugin/windows.tmpl/include/projectName.tmpl/pluginClassSnakeCase.h.tmpl",
"templates/plugin/windows.tmpl/pluginClassSnakeCase.cpp.tmpl",
"templates/plugin/lib/projectName_web.dart.tmpl"
]
}