Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support emscripten build #1145

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ option(ENABLE_XDGAUTOSTART "Enable xdg autostart desktop file installation" On)
option(USE_FLATPAK_ICON "Use flatpak icon name for desktop files" Off)
option(ENABLE_EMOJI "Enable emoji module" On)
option(ENABLE_LIBUUID "Use libuuid for uuid generation" On)
option(BUILD_SPELL_DICT "Build en_dict.fscd for English spell check" On)
set(NO_PREEDIT_APPS "gvim.*,wps.*,wpp.*,et.*" CACHE STRING "Disable preedit for follwing app by default.")

if (ENABLE_EMOJI)
Expand Down Expand Up @@ -69,7 +70,7 @@ if (NOT TARGET Systemd::Systemd)
pkg_get_variable(DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "dbus-1" "system_bus_default_address")
endif()

if (NOT LIBUV_TARGET)
if (NOT LIBUV_TARGET AND NOT EMSCRIPTEN)
if (NOT (TARGET PkgConfig::LibUV))
pkg_check_modules(LibUV REQUIRED IMPORTED_TARGET "libuv")
endif()
Expand Down
2 changes: 1 addition & 1 deletion cmake/Fcitx5CompilerSettings.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-Wall -Wextra ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-Wall -Wextra ${CMAKE_CXX_FLAGS}")

if(NOT APPLE)
if(NOT APPLE AND NOT EMSCRIPTEN)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined -Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined -Wl,--as-needed ${CMAKE_MODULE_LINKER_FLAGS}")
endif()
Expand Down
18 changes: 11 additions & 7 deletions src/lib/fcitx-utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ if (ENABLE_DBUS)
endif()
endif()

if (NOT TARGET Systemd::Systemd)
if (TARGET Systemd::Systemd)
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
event_libuv.cpp)
event_sdevent.cpp)
elseif (EMSCRIPTEN)
list(APPEND FCITX_UTILS_SOURCES event_js.cpp) # implemented in fcitx5-js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having an external file dependency.

I think we could somehow, create a stub for EventLoop and having a global factory class to allow external event loop implementation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea how to achieve that with a factory.
Added the event_js.cpp, since there is nothing specific to fcitx5-js. emscripten_async_call is generic API https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_async_call

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without breaking the API, here's what you can do.

  1. create a stub only EventLoop that takes a EventLoopImpl as parameter.
  2. Create a global factory callback that allow external code to override the creation of EventLoopImpl.
  3. Before initialize Instance, set the factory function

In other words, use Dependency injection to make your js eventloop implementation live outside of the main repo.

else()
set(FCITX_UTILS_SOURCES
${FCITX_UTILS_SOURCES}
event_sdevent.cpp)
event_libuv.cpp)
endif()

set(FCITX_UTILS_SOURCES
Expand Down Expand Up @@ -134,13 +136,15 @@ if(LIBKVM_FOUND)
target_link_libraries(Fcitx5Utils PRIVATE LibKVM::LibKVM)
endif()

if (NOT TARGET Systemd::Systemd)
target_link_libraries(Fcitx5Utils PRIVATE ${LIBUV_TARGET})
if (TARGET Systemd::Systemd)
target_link_libraries(Fcitx5Utils PRIVATE Systemd::Systemd)
else()
if (NOT EMSCRIPTEN)
target_link_libraries(Fcitx5Utils PRIVATE ${LIBUV_TARGET})
endif()
if (ENABLE_DBUS)
target_link_libraries(Fcitx5Utils PRIVATE PkgConfig::DBus)
endif()
else()
target_link_libraries(Fcitx5Utils PRIVATE Systemd::Systemd)
endif()

configure_file(Fcitx5Utils.pc.in ${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Utils.pc @ONLY)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/fcitx-utils/endian_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define _FCITX_UTILS_ENDIAN_P_H_

#include <cstdint>
#if defined(__linux__) || defined(__GLIBC__)
#if defined(__linux__) || defined(__GLIBC__) || defined(__EMSCRIPTEN__)
#include <endian.h>
#elif defined(__APPLE__)

Expand Down
134 changes: 134 additions & 0 deletions src/lib/fcitx-utils/event_js.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include <emscripten.h>
#include "event.h"

namespace fcitx {

template <typename Interface>
struct JSEventSourceBase : public Interface {
public:
~JSEventSourceBase() override {}

bool isEnabled() const override { return enabled_; }

void setEnabled(bool enabled) override { enabled_ = enabled; }

bool isOneShot() const override { return oneShot_; }

void setOneShot() override { oneShot_ = true; }

private:
bool enabled_ = false;
bool oneShot_ = false;
};

struct JSEventSource : public JSEventSourceBase<EventSource> {
JSEventSource(EventCallback _callback)
: callback_(std::make_shared<EventCallback>(std::move(_callback))) {}

std::shared_ptr<EventCallback> callback_;
};

struct JSEventSourceIO : public JSEventSourceBase<EventSourceIO> {
JSEventSourceIO(IOCallback _callback) {}

int fd() const override { return 0; }

void setFd(int fd) override {}

IOEventFlags events() const override { return IOEventFlag::In; }

void setEvents(IOEventFlags flags) override {}

IOEventFlags revents() const override { return IOEventFlag::In; }
};

void TimeEventCallback(void *arg);

struct JSEventSourceTime : public JSEventSourceBase<EventSourceTime> {
JSEventSourceTime(TimeCallback _callback, uint64_t time, clockid_t clockid)
: callback_(std::make_shared<TimeCallback>(std::move(_callback))),
time_(time), clockid_(clockid) {
setOneShot();
}

void setOneShot() override {
int t = std::max<int64_t>(0, time_ - now(CLOCK_MONOTONIC)) / 1000;
emscripten_async_call(TimeEventCallback, this, t);
}

uint64_t time() const override { return time_; }

void setTime(uint64_t time) override { time_ = time; }

uint64_t accuracy() const override { return 0; }

void setAccuracy(uint64_t time) override {}

clockid_t clock() const override { return clockid_; }

std::shared_ptr<TimeCallback> callback_;

private:
uint64_t time_;
clockid_t clockid_;
};

void TimeEventCallback(void *arg) {
auto source = static_cast<JSEventSourceTime *>(arg);
(*source->callback_)(source, source->time());
}

class EventLoopPrivate {
public:
EventLoopPrivate() {}

~EventLoopPrivate() {}
};

EventLoop::EventLoop() : d_ptr(std::make_unique<EventLoopPrivate>()) {}

EventLoop::~EventLoop() = default;

const char *EventLoop::impl() { return "js-event"; }

void *EventLoop::nativeHandle() { return nullptr; }

bool EventLoop::exec() { return true; }

void EventLoop::exit() {}

std::unique_ptr<EventSourceIO> EventLoop::addIOEvent(int fd, IOEventFlags flags,
IOCallback callback) {
auto source = std::make_unique<JSEventSourceIO>(std::move(callback));
return source;
}

std::unique_ptr<EventSourceTime>
EventLoop::addTimeEvent(clockid_t clock, uint64_t usec, uint64_t accuracy,
TimeCallback callback) {
auto source =
std::make_unique<JSEventSourceTime>(std::move(callback), usec, clock);
return source;
}

std::unique_ptr<EventSource> EventLoop::addExitEvent(EventCallback callback) {
auto source = std::make_unique<JSEventSource>(std::move(callback));
return source;
}

std::unique_ptr<EventSource> EventLoop::addDeferEvent(EventCallback callback) {
return addTimeEvent(
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
[callback = std::move(callback)](EventSourceTime *source, uint64_t) {
return callback(source);
});
}

std::unique_ptr<EventSource> EventLoop::addPostEvent(EventCallback callback) {
return addTimeEvent(
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
[callback = std::move(callback)](EventSourceTime *source, uint64_t) {
return callback(source);
});
}
} // namespace fcitx
2 changes: 2 additions & 0 deletions src/modules/spell/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/spell.conf" DESTINATION "${FCITX_INST
COMPONENT config)
fcitx5_export_module(Spell TARGET spell BUILD_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}" HEADERS spell_public.h INSTALL)

if (BUILD_SPELL_DICT)
set(DICT_COMP_SRC
comp_spell_dict.cpp
)
Expand Down Expand Up @@ -46,3 +47,4 @@ add_custom_command(
"${SPELL_EN_DICT_SRC}" "${SPELL_EN_DICT}")
add_custom_target(spell_en_dict ALL DEPENDS "${SPELL_EN_DICT}")
install(FILES "${SPELL_EN_DICT}" DESTINATION "${FCITX_INSTALL_PKGDATADIR}/spell")
endif()
Loading