From 74a2d905306874094552ecdc34b862e7a8083123 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 30 Nov 2017 19:47:20 -0500 Subject: [PATCH] Changes to assets/ build/ flow/ runtime/ and shell/ to allow for compilation on Windows (#4407) Made changes to assets/ build/ flow/ runtime/ and shell/ to allow for compilation on Windows. --- assets/directory_asset_bundle.cc | 4 + assets/zip_asset_store.cc | 4 + build/dart/tools/dart_pkg.py | 6 +- flow/matrix_decomposition_unittests.cc | 7 ++ runtime/dart_controller.cc | 41 ++++++- runtime/dart_init.cc | 7 ++ shell/common/engine.cc | 94 +++++++++++++++- shell/common/switches.cc | 3 +- shell/platform/BUILD.gn | 4 +- shell/platform/win/BUILD.gn | 30 ++++++ shell/platform/win/main_win.cc | 136 ++++++++++++++++++++++++ travis/licenses_golden/licenses_flutter | 1 + 12 files changed, 329 insertions(+), 8 deletions(-) create mode 100644 shell/platform/win/BUILD.gn create mode 100644 shell/platform/win/main_win.cc diff --git a/assets/directory_asset_bundle.cc b/assets/directory_asset_bundle.cc index 213a977bf..9d4f2935f 100644 --- a/assets/directory_asset_bundle.cc +++ b/assets/directory_asset_bundle.cc @@ -3,9 +3,13 @@ // found in the LICENSE file. #include "flutter/assets/directory_asset_bundle.h" +#include "lib/fxl/build_config.h" #include + +#if !defined(OS_WIN) #include +#endif #include diff --git a/assets/zip_asset_store.cc b/assets/zip_asset_store.cc index 8b8d93e3c..c8534fa10 100644 --- a/assets/zip_asset_store.cc +++ b/assets/zip_asset_store.cc @@ -3,9 +3,13 @@ // found in the LICENSE file. #include "flutter/assets/zip_asset_store.h" +#include "lib/fxl/build_config.h" #include + +#if !defined(OS_WIN) #include +#endif #include #include diff --git a/build/dart/tools/dart_pkg.py b/build/dart/tools/dart_pkg.py index dd0724691..34396b827 100755 --- a/build/dart/tools/dart_pkg.py +++ b/build/dart/tools/dart_pkg.py @@ -119,6 +119,8 @@ def list_files(from_root, filter_func=None): def remove_broken_symlink(path): + if not USE_LINKS: + return try: link_path = os.readlink(path) except OSError as e: @@ -131,6 +133,8 @@ def remove_broken_symlink(path): def remove_broken_symlinks(root_dir): + if not USE_LINKS: + return for current_dir, _, child_files in os.walk(root_dir): for filename in child_files: path = os.path.join(current_dir, filename) @@ -268,7 +272,7 @@ def main(): # Symlink packages/ package_path = os.path.join(args.package_root, args.package_name) - link(lib_path, package_path) + copy_or_link(lib_path, package_path) # Link dart-pkg/$package/packages to dart-pkg/packages link_if_possible(args.package_root, target_packages_dir) diff --git a/flow/matrix_decomposition_unittests.cc b/flow/matrix_decomposition_unittests.cc index 9d24168d7..87ed5df08 100644 --- a/flow/matrix_decomposition_unittests.cc +++ b/flow/matrix_decomposition_unittests.cc @@ -2,6 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "lib/fxl/build_config.h" + +#if defined(OS_WIN) +#define _USE_MATH_DEFINES +#endif +#include + #include "flutter/flow/matrix_decomposition.h" #include "third_party/gtest/include/gtest/gtest.h" diff --git a/runtime/dart_controller.cc b/runtime/dart_controller.cc index 636b20f78..4145eb5e7 100644 --- a/runtime/dart_controller.cc +++ b/runtime/dart_controller.cc @@ -3,6 +3,12 @@ // found in the LICENSE file. #include "flutter/runtime/dart_controller.h" +#include "lib/fxl/build_config.h" + +#if defined(OS_WIN) +#include +#undef GetCurrentDirectory +#endif #include @@ -33,6 +39,37 @@ using tonic::ToDart; namespace blink { namespace { +#if defined(OS_WIN) + +std::string FindAndReplace(const std::string& str, + const std::string& findStr, + const std::string& replaceStr) { + std::string rStr = str; + size_t pos = 0; + while ((pos = rStr.find(findStr, pos)) != std::string::npos) { + rStr.replace(pos, findStr.length(), replaceStr); + pos += replaceStr.length(); + } + return rStr; +} + +std::string SanitizePath(const std::string& path) { + return FindAndReplace(path, "\\\\", "/"); +} + +std::string ResolvePath(std::string path) { + std::string sanitized = SanitizePath(path); + if ((sanitized.length() > 2) && (sanitized[1] == ':')) { + return sanitized; + } + return files::SimplifyPath(files::GetCurrentDirectory() + "/" + sanitized); +} + +#else // defined(OS_WIN) + +std::string SanitizePath(const std::string& path) { + return path; +} // TODO(abarth): Consider adding this to //garnet/public/lib/fxl. std::string ResolvePath(std::string path) { @@ -41,6 +78,8 @@ std::string ResolvePath(std::string path) { return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path); } +#endif + } // namespace DartController::DartController() : ui_dart_state_(nullptr) {} @@ -169,7 +208,7 @@ tonic::DartErrorHandleType DartController::RunFromSource( tonic::FileLoader& loader = dart_state()->file_loader(); if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages))) FXL_LOG(WARNING) << "Failed to load package map: " << packages; - Dart_Handle result = loader.LoadScript(main); + Dart_Handle result = loader.LoadScript(SanitizePath(main)); LogIfError(result); error = tonic::GetErrorHandleType(result); } diff --git a/runtime/dart_init.cc b/runtime/dart_init.cc index db4b09314..28781864b 100644 --- a/runtime/dart_init.cc +++ b/runtime/dart_init.cc @@ -3,11 +3,18 @@ // found in the LICENSE file. #include "flutter/runtime/dart_init.h" +#include "flutter/sky/engine/wtf/OperatingSystem.h" #include #include #include + +#if defined(OS_WIN) +#include +#undef ERROR +#else #include +#endif #include #include diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 9372f7baa..de62e4816 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -4,11 +4,28 @@ #include "flutter/shell/common/engine.h" +#if OS(WIN) +#include +#include +#define access _access +#define R_OK 0x4 + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#endif + +#else #include -#include #include -#include #include +#endif // OS(WIN) + +#include +#include #include #include @@ -46,6 +63,30 @@ constexpr char kNavigationChannel[] = "flutter/navigation"; constexpr char kLocalizationChannel[] = "flutter/localization"; constexpr char kSettingsChannel[] = "flutter/settings"; +void FindAndReplaceInPlace(std::string& str, + const std::string& findStr, + const std::string& replaceStr) { + size_t pos = 0; + while ((pos = str.find(findStr, pos)) != std::string::npos) { + str.replace(pos, findStr.length(), replaceStr); + pos += replaceStr.length(); + } +} + +std::string SanitizePath(const std::string& path) { +#if OS(WIN) + std::string sanitized = path; + FindAndReplaceInPlace(sanitized, "\\\\", "/"); + if ((sanitized.length() > 2) && (sanitized[1] == ':')) { + // Path begins with a drive letter. + sanitized = '/' + sanitized; + } + return sanitized; +#else + return path; +#endif +} + bool PathExists(const std::string& path) { return access(path.c_str(), R_OK) == 0; } @@ -63,7 +104,7 @@ std::string FindPackagesPath(const std::string& main_dart) { } std::string GetScriptUriFromPath(const std::string& path) { - return "file://" + path; + return "file://" + SanitizePath(path); } } // namespace @@ -93,6 +134,7 @@ fml::WeakPtr Engine::GetWeakPtr() { #if !FLUTTER_AOT #elif OS(IOS) #elif OS(ANDROID) +// TODO(bkonyi): do we even get here for Windows? static const uint8_t* MemMapSnapshot(const std::string& aot_snapshot_path, const std::string& default_file_name, const std::string& settings_file_name, @@ -104,6 +146,49 @@ static const uint8_t* MemMapSnapshot(const std::string& aot_snapshot_path, asset_path = aot_snapshot_path + "/" + settings_file_name; } +#if OS(WIN) + HANDLE file_handle_ = + CreateFileA(reinterpret_cast(path.c_str()), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); + + if (file_handle_ == INVALID_HANDLE_VALUE) { + return; + } + + size_ = GetFileSize(file_handle_, nullptr); + if (size_ == INVALID_FILE_SIZE) { + size_ = 0; + return; + } + + int mapping_flags = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; + mapping_handle_ = CreateFileMapping(file_handle_, nullptr, mapping_flags, 0, + size_, nullptr); + + CloseHandle(file_handle_); + + if (mapping_handle_ == INVALID_HANDLE_VALUE) { + return; + } + + int access_flags = FILE_MAP_READ; + if (executable) { + access_flags |= FILE_MAP_EXECUTE; + } + auto mapping = MapViewOfFile(mapping_handle_, access_flags, 0, 0, size_); + + if (mapping == INVALID_HANDLE_VALUE) { + CloseHandle(mapping_handle_); + mapping_handle_ = INVALID_HANDLE_VALUE; + return; + } + + void* symbol = static_cast(mapping); + if (symbol == NULL) { + return nullptr; + } +#else struct stat info; if (stat(asset_path.c_str(), &info) < 0) { return nullptr; @@ -123,6 +208,7 @@ static const uint8_t* MemMapSnapshot(const std::string& aot_snapshot_path, if (symbol == MAP_FAILED) { return nullptr; } +#endif return reinterpret_cast(symbol); } #endif @@ -161,7 +247,7 @@ void Engine::Init(const std::string& bundle_path) { dlsym(library_handle, "kDartIsolateSnapshotData")); default_isolate_snapshot_instr = reinterpret_cast( dlsym(library_handle, "kDartIsolateSnapshotInstructions")); -#elif OS(ANDROID) +#elif OS(ANDROID) || OS(WIN) const blink::Settings& settings = blink::Settings::Get(); const std::string& aot_shared_library_path = settings.aot_shared_library_path; const std::string& aot_snapshot_path = settings.aot_snapshot_path; diff --git a/shell/common/switches.cc b/shell/common/switches.cc index 68a4f7b0a..c1c82ff16 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include #include #include @@ -27,7 +28,7 @@ struct SwitchDesc { // clang-format off #define DEF_SWITCHES_START static const struct SwitchDesc gSwitchDescs[] = { #define DEF_SWITCH(p_swtch, p_flag, p_help) \ - { .sw = shell::Switch:: p_swtch, .flag = p_flag, .help = p_help }, + { shell::Switch:: p_swtch, p_flag, p_help }, #define DEF_SWITCHES_END }; // clang-format on diff --git a/shell/platform/BUILD.gn b/shell/platform/BUILD.gn index 915cff4c3..4b1e1a9e0 100644 --- a/shell/platform/BUILD.gn +++ b/shell/platform/BUILD.gn @@ -17,7 +17,9 @@ group("platform") { "embedder", ] } else if (is_win) { - print("Shell currently not supported on Windows.") + deps = [ + "win" + ] } else { assert(false, "Unknown/Unsupported platform.") } diff --git a/shell/platform/win/BUILD.gn b/shell/platform/win/BUILD.gn new file mode 100644 index 000000000..b4a2fe503 --- /dev/null +++ b/shell/platform/win/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +executable("win") { + output_name = "flutter_tester" + + sources = [ + "main_win.cc", + ] + + deps = [ + "//flutter/common", + "//flutter/flow", + "//flutter/fml", + "//flutter/shell/common", + "//flutter/shell/testing", + "//flutter/sky/engine/wtf", + "//garnet/public/lib/fxl", + "//third_party/dart/runtime/bin:embedded_dart_io", + "//third_party/dart/runtime:libdart_jit", + "//third_party/skia", + "//topaz/lib/tonic", + ] + + libs = [ + "iphlpapi.lib", + "Rpcrt4.lib" + ] +} diff --git a/shell/platform/win/main_win.cc b/shell/platform/win/main_win.cc new file mode 100644 index 000000000..d555ecde9 --- /dev/null +++ b/shell/platform/win/main_win.cc @@ -0,0 +1,136 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "flutter/common/threads.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/testing/test_runner.h" +#include "flutter/shell/testing/testing.h" +#include "lib/fxl/command_line.h" +#include "lib/tonic/dart_microtask_queue.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +namespace { + +// Exit codes used by the Dart command line tool. +const int kApiErrorExitCode = 253; +const int kCompilationErrorExitCode = 254; +const int kErrorExitCode = 255; + +// Checks whether the engine's main Dart isolate has no pending work. If so, +// then exit the given message loop. +class ScriptCompletionTaskObserver : public fml::TaskObserver { + public: + ScriptCompletionTaskObserver(fxl::RefPtr task_runner) + : main_task_runner_(std::move(task_runner)), + prev_live_(false), + last_error_(tonic::kNoError) {} + + void DidProcessTask() override { + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + shell::Engine& engine = test_runner.platform_view().engine(); + + if (engine.GetLoadScriptError() != tonic::kNoError) { + last_error_ = engine.GetLoadScriptError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + return; + } + + bool live = engine.UIIsolateHasLivePorts(); + if (prev_live_ && !live) { + last_error_ = engine.GetUIIsolateLastError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + } + prev_live_ = live; + } + + tonic::DartErrorHandleType last_error() { return last_error_; } + + private: + fxl::RefPtr main_task_runner_; + bool prev_live_; + tonic::DartErrorHandleType last_error_; +}; + +int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { + switch (error) { + case tonic::kCompilationErrorType: + return kCompilationErrorExitCode; + case tonic::kApiErrorType: + return kApiErrorExitCode; + case tonic::kUnknownErrorType: + return kErrorExitCode; + default: + return 0; + } +} + +void RunNonInteractive(fxl::CommandLine initial_command_line, + bool run_forever) { + // This is a platform thread (i.e not one created by fml::Thread), so perform + // one time initialization. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + shell::Shell::InitStandalone(initial_command_line); + + // Note that this task observer must be added after the observer that drains + // the microtask queue. + ScriptCompletionTaskObserver task_observer( + fml::MessageLoop::GetCurrent().GetTaskRunner()); + if (!run_forever) { + blink::Threads::UI()->PostTask([&task_observer] { + fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); + }); + } + + if (!shell::InitForTesting(initial_command_line)) { + shell::PrintUsage("flutter_tester"); + ::ExitProcess(EXIT_FAILURE); + return; + } + + fml::MessageLoop::GetCurrent().Run(); + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + tonic::DartErrorHandleType error = + test_runner.platform_view().engine().GetLoadScriptError(); + if (error == tonic::kNoError) + error = task_observer.last_error(); + if (error == tonic::kNoError) { + fxl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&error, &latch] { + error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); + latch.Signal(); + }); + latch.Wait(); + } + + // The script has completed and the engine may not be in a clean state, + // so just stop the process. + ::ExitProcess(ConvertErrorTypeToExitCode(error)); +} + +} // namespace + +int main(int argc, char* argv[]) { + dart::bin::SetExecutableName(argv[0]); + dart::bin::SetExecutableArguments(argc - 1, argv); + + auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); + + if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { + shell::PrintUsage("flutter_tester"); + return EXIT_SUCCESS; + } + + bool run_forever = + command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)); + RunNonInteractive(std::move(command_line), run_forever); + return EXIT_SUCCESS; +} diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index eff987a8a..91afac52e 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -9600,6 +9600,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDele FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm FILE: ../../../flutter/shell/platform/linux/main_linux.cc +FILE: ../../../flutter/shell/platform/win/main_win.cc FILE: ../../../flutter/sky/engine/wtf/Allocator.h FILE: ../../../flutter/sky/engine/wtf/MakeUnique.h ---------------------------------------------------------------------------------------------------- -- GitLab