diff --git a/.gitmodules b/.gitmodules index 70b2abcc..61846331 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "deps/modules/ios-cmake"] path = deps/modules/ios-cmake url = https://github.com/leetal/ios-cmake.git +[submodule "deps/modules/emsdk"] + path = deps/modules/emsdk + url = https://github.com/emscripten-core/emsdk.git diff --git a/.mac-setup.sh b/.mac-setup.sh index 1838f41a..211c9e9c 100755 --- a/.mac-setup.sh +++ b/.mac-setup.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +SCRIPT_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" + # Formatting RED=$(tput setaf 1) YELLOW=$(tput setaf 3) @@ -7,6 +9,12 @@ GREEN=$(tput setaf 2) WHITE=$(tput setaf 15) NC=$(tput sgr0) +# Environment +EMSDK_VERSION=${EMSDK_VERSION:-latest} +UNIFFI_BINDGEN_CPP_VERSION=${UNIFFI_BINDGEN_CPP_VERSION:-"v0.1.0+v0.25.0"} + +die() { printf %s "${@+$@$'\n'}" 1>&2 ; exit 1; } + check_for() { local -r app=$1 @@ -57,12 +65,25 @@ rustup target add aarch64-linux-android \ x86_64-apple-darwin \ aarch64-apple-ios \ x86_64-apple-ios \ - aarch64-apple-ios-sim + aarch64-apple-ios-sim \ + wasm32-unknown-emscripten + +echo +echo "Install cargo dependencies" +cargo install cargo install uniffi-bindgen-cpp \ + --git https://github.com/NordSecurity/uniffi-bindgen-cpp \ + --tag "${UNIFFI_BINDGEN_CPP_VERSION}" echo echo "Setting up project ..." make deps +echo +echo "Setting up emsdk" +cd "${SCRIPT_DIR}/deps/modules/emsdk" || die "Could not find Emscripten SDK under ${RED}deps/modules/emsdk${NC}!" +./emsdk install "${EMSDK_VERSION}" +./emsdk activate "${EMSDK_VERSION}" + echo echo "${WHITE}Setup completed!${NC}" echo " 1. If your ${GREEN}ANDROID_NDK_HOME${NC} was not installed to ${YELLOW}/opt/homebrew/share/android-ndk${NC}, export it's location in your shell profile" diff --git a/Makefile b/Makefile index 679d4ee5..f5f4e177 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,9 @@ define n endef +# Directory containing this Makefile +PROJECT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) + # Formatting RED := $(shell tput setaf 1) YELLOW := $(shell tput setaf 3) @@ -36,6 +39,12 @@ export CXX := clang++ # Build variable(s) BUILD := build +# Directories for external dependencies and their builds +DEPS_DIR := deps +DEPS_MODULES_DIR := $(DEPS_DIR)/modules +DEPS_BUILD_DIR := $(DEPS_DIR)/build +DEPS_ARTIFACTS_DIR := $(DEPS_DIR)/artifacts + # Android ANDROID := android @@ -78,11 +87,19 @@ PLISTBUDDY_EXEC := /usr/libexec/PlistBuddy INSTALL_NAME_TOOL := install_name_tool XCODEBUILD := xcodebuild -# Directories for external dependencies and their builds -DEPS_DIR := deps -DEPS_MODULES_DIR := $(DEPS_DIR)/modules -DEPS_BUILD_DIR := $(DEPS_DIR)/build -DEPS_ARTIFACTS_DIR := $(DEPS_DIR)/artifacts +# Wasm +WASM := wasm +WASM_BUILD := $(BUILD)/$(WASM) + +EMSDK := emsdk +EMSDK_DIR := $(PROJECT_DIR)/$(DEPS_MODULES_DIR)/$(EMSDK) +EMSDK_VERSION := 3.1.51 +EMSDK_ENV := emsdk_env.sh + +UNIFFI_BINDGEN_CPP := uniffi-bindgen-cpp +UNIFFI_BINDGEN_CPP_VERSION := v0.1.0+v0.25.0 + +WASM_MODULE := DotLottiePlayer # External dependencies THORVG := thorvg @@ -91,8 +108,9 @@ LIBPNG := libpng ZLIB := zlib # External dependency artifacts -THORVG_CROSS_FILE := cross.txt -THORVG_NINJA_BUILD_FILE := build.ninja +MESON_CROSS_FILE := cross.txt +MESON_BUILD_FILE := meson.build +NINJA_BUILD_FILE := build.ninja THORVG_LIB := libthorvg.a CMAKE_TOOLCHAIN_FILE := toolchain.cmake @@ -114,10 +132,10 @@ DOTLOTTIE_PLAYER := dotlottie-player # Build artifacts RUNTIME_FFI_UNIFFI_BINDINGS := uniffi-bindings -RUNTIME_FFI_LIB := libdlplayer.so -RUNTIME_FFI_ANDROID_ASSETS := assets +RUNTIME_FFI_STATIC_LIB := libdotlottie_player.a +RUNTIME_FFI_LIB := libdotlottie_player.so +RUNTIME_FFI_DYLIB := libdotlottie_player.dylib -RUNTIME_FFI_DYLIB := libdlplayer.dylib DOTLOTTIE_PLAYER_HEADER := dotlottie_player.h DOTLOTTIE_PLAYER_SWIFT := dotlottie_player.swift DOTLOTTIE_PLAYER_MODULE := DotLottiePlayer @@ -131,9 +149,11 @@ INFO_PLIST := Info.plist KOTLIN := kotlin SWIFT := swift +CPLUSPLUS := cpp +RUNTIME_FFI_ANDROID_ASSETS := assets DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR := $(RELEASE)/$(ANDROID)/$(DOTLOTTIE_PLAYER) -DOTLOTTIE_PLAYER_ANDROID_SRC_DIR := $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR)/src/main/kotlin +DOTLOTTIE_PLAYER_ANDROID_SRC_DIR := $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR)/src/main/$(KOTLIN) DOTLOTTIE_PLAYER_LIB := libuniffi_dotlottie_player.so DOTLOTTIE_PLAYER_GRADLE_PROPERTIES := gradle.properties @@ -203,12 +223,45 @@ cpu = '$(CPU)' endian = 'little' endef -define APPLE_MODULE_MAP_FILE -framework module $(MODULE_NAME) { - umbrella header "$(UMBRELLA_HEADER)" - export * - module * { export * } -} +define WASM_CROSS_FILE +[binaries] +cpp = ['$(EMSDK_DIR)/upstream/emscripten/em++.py', '-std=c++20'] +ar = '$(EMSDK_DIR)/upstream/emscripten/emar.py' +strip = '-strip' + +[properties] +root = '$(EMSDK_DIR)/upstream/emscripten/system' +shared_lib_suffix = 'js' +static_lib_suffix = 'js' +shared_module_suffix = 'js' +exe_suffix = 'js' + +[built-in options] +cpp_args = ['-Wshift-negative-value', '-flto', '-Oz', '-ffunction-sections', '-fdata-sections'] +cpp_link_args = [ + '-Wl,-u,htons', + '-Wl,-u,ntohs', + '-Wl,-u,htonl', + '-Wshift-negative-value', + '-flto', '-Os', '--bind', '-sWASM=1', + '-sALLOW_MEMORY_GROWTH=1', + '-sFORCE_FILESYSTEM=0', + '-sMODULARIZE=1', + '-sEXPORT_NAME=create$(WASM_MODULE)Module', + '-sEXPORT_ES6=1', + '-sUSE_ES6_IMPORT_META=0', + '-sENVIRONMENT=web', + '-sFILESYSTEM=0', + '-sDYNAMIC_EXECUTION=0', + '--no-entry', + '--strip-all', + '--minify=0'] + +[host_machine] +system = '$(SYSTEM)' +cpu_family = '$(CPU_FAMILY)' +cpu = '$(CPU)' +endian = 'little' endef # Helper functions @@ -219,6 +272,29 @@ set(CMAKE_ANDROID_ARCH_ABI $(ANDROID_ABI)) set(CMAKE_ANDROID_NDK $(ANDROID_NDK_HOME)) endef +define APPLE_MODULE_MAP_FILE +framework module $(MODULE_NAME) { + umbrella header "$(UMBRELLA_HEADER)" + export * + module * { export * } +} +endef + +define WASM_MESON_BUILD_FILE +project('$(WASM_MODULE)', 'cpp') + +cc = meson.get_compiler('cpp') +if cc.get_id() == 'emscripten' + executable('$(WASM_MODULE)', + [$(shell find $(FFI_BINDINGS_DIR) -name "*.cpp" -exec printf "'%s'," {} \; 2>/dev/null)], + include_directories: '$(FFI_BINDINGS_DIR)', + link_args: ['-L$(DEPS_LIB_DIR)', '-L$(FFI_BUILD_DIR)', '-lthorvg', '-ldotlottie_player'], + ) +else + message('The compiler is not Emscripten.') +endif +endef + define CREATE_OUTPUT_FILE mkdir -p $$(dirname $@) echo "$$OUTPUT_FILE" > $@ @@ -228,14 +304,22 @@ define SETUP_MESON meson setup \ --prefix=/ \ --backend=ninja \ - -Dlog=true \ -Dloaders="lottie, png, jpg" \ -Ddefault_library=static \ - -Dsavers=all \ -Dbindings=capi \ + -Dlog=$(LOG) \ + -Dstatic=$(STATIC) \ + -Dsavers=$(SAVERS) \ $(CROSS_FILE) "$(THORVG_DEP_SOURCE_DIR)" "$(THORVG_DEP_BUILD_DIR)" endef +define SETUP_WASM_MESON + meson setup \ + --prefix=/ \ + --backend=ninja \ + --cross-file "$(CROSS_FILE)" "$(WASM_SRC_DIR)" "$(WASM_BUILD_DIR)" +endef + define NINJA_BUILD DESTDIR=$(ARTIFACTS_DIR) ninja -C $(DEP_BUILD_DIR) install endef @@ -264,13 +348,32 @@ define CARGO_BUILD endef define UNIFFI_BINDINGS_BUILD + rm -rf $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(BINDINGS_LANGUAGE) cargo +nightly run \ --manifest-path $(RUNTIME_FFI)/Cargo.toml \ --features=uniffi/cli \ --bin uniffi-bindgen \ - generate $(RUNTIME_FFI)/src/dlplayer.udl \ + generate $(RUNTIME_FFI)/src/dotlottie_player.udl \ --language $(BINDINGS_LANGUAGE) \ - --out-dir $(RUNTIME_FFI)/uniffi-bindings/$(BINDINGS_LANGUAGE) + --out-dir $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(BINDINGS_LANGUAGE) +endef + +define UNIFFI_BINDINGS_CPP_BUILD + rm -rf $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS) + $(UNIFFI_BINDGEN_CPP) \ + --config $(RUNTIME_FFI)/uniffi.toml \ + --out-dir $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS) \ + $(RUNTIME_FFI)/src/dotlottie_player.udl + sed -i .bak 's/uint8_t/char/g' $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS)/* + $(RUNTIME_FFI)/uniffi-emscripten-bindings.sh +endef + +define ANDROID_RELEASE + mkdir -p $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR) $(DOTLOTTIE_PLAYER_ANDROID_SRC_DIR) $(DOTLOTTIE_PLAYER_LIB_DIR) + cp -r $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(KOTLIN)/* $(DOTLOTTIE_PLAYER_ANDROID_SRC_DIR) + cp $(RUNTIME_FFI_TARGET_LIB) $(DOTLOTTIE_PLAYER_LIB_DIR)/$(DOTLOTTIE_PLAYER_LIB) + cp $(RUNTIME_FFI)/$(RUNTIME_FFI_ANDROID_ASSETS)/$(ANDROID)/* $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR) + echo "dlplayer-version=$(CRATE_VERSION)-$(COMMIT_HASH)" > $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR)/$(DOTLOTTIE_PLAYER_GRADLE_PROPERTIES) endef define LIPO_CREATE @@ -313,12 +416,12 @@ define APPLE_RELEASE cp $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(SWIFT)/$(DOTLOTTIE_PLAYER_SWIFT) $(RELEASE)/$(APPLE)/. endef -define ANDROID_RELEASE - mkdir -p $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR) $(DOTLOTTIE_PLAYER_ANDROID_SRC_DIR) $(DOTLOTTIE_PLAYER_LIB_DIR) - cp -r $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(KOTLIN)/* $(DOTLOTTIE_PLAYER_ANDROID_SRC_DIR) - cp $(RUNTIME_FFI_TARGET_LIB) $(DOTLOTTIE_PLAYER_LIB_DIR)/$(DOTLOTTIE_PLAYER_LIB) - cp $(RUNTIME_FFI)/$(RUNTIME_FFI_ANDROID_ASSETS)/$(ANDROID)/* $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR) - echo "dlplayer-version=$(CRATE_VERSION)-$(COMMIT_HASH)" > $(DOTLOTTIE_PLAYER_ANDROID_RELEASE_DIR)/$(DOTLOTTIE_PLAYER_GRADLE_PROPERTIES) +define WASM_RELEASE + rm -rf $(RELEASE)/$(WASM) + mkdir -p $(RELEASE)/$(WASM) + cp $(RUNTIME_FFI)/$(WASM_BUILD)/$(BUILD)/$(WASM_MODULE).wasm \ + $(RUNTIME_FFI)/$(WASM_BUILD)/$(BUILD)/$(WASM_MODULE).js \ + $(RELEASE)/$(WASM) endef # $1: rust target triple, e.g. aarch64-linux-android @@ -412,46 +515,58 @@ endef define NEW_ANDROID_CROSS_FILE # Create cross file for thorvg -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): SYSROOT := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(ANDROID_BUILD_PLATFORM)/sysroot/usr/lib/$$($1_ARCH)/$(ANDROID_API_VERSION) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): CPP := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(ANDROID_BUILD_PLATFORM)/bin/$$($1_ARCH)$(ANDROID_API_VERSION)-clang++ -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): CPU_FAMILY := $$($1_CPU_FAMILY) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): CPU := $$($1_CPU) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): DEP_BUILD_DIR := $$($1_THORVG_DEP_BUILD_DIR) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): export OUTPUT_FILE := $$(ANDROID_CROSS_FILE) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): SYSROOT := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(ANDROID_BUILD_PLATFORM)/sysroot/usr/lib/$$($1_ARCH)/$(ANDROID_API_VERSION) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): CPP := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(ANDROID_BUILD_PLATFORM)/bin/$$($1_ARCH)$(ANDROID_API_VERSION)-clang++ +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): CPU_FAMILY := $$($1_CPU_FAMILY) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): CPU := $$($1_CPU) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): export OUTPUT_FILE := $$(ANDROID_CROSS_FILE) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): $$(CREATE_OUTPUT_FILE) endef define NEW_APPLE_CROSS_FILE # Create cross file for thorvg -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): ARCH := $$($1_ABI) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): PLATFORM := $$($1_PLATFORM) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): SDK := $$($1_SDK) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): SUBSYSTEM := $$($1_SUBSYSTEM) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): CPU_FAMILY := $$($1_CPU_FAMILY) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): CPU := $$($1_CPU) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): DEP_BUILD_DIR := $$($1_THORVG_DEP_BUILD_DIR) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): export OUTPUT_FILE := $$(APPLE_CROSS_FILE) -$$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE): +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): ARCH := $$($1_ABI) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): PLATFORM := $$($1_PLATFORM) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): SDK := $$($1_SDK) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): SUBSYSTEM := $$($1_SUBSYSTEM) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): CPU_FAMILY := $$($1_CPU_FAMILY) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): CPU := $$($1_CPU) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): export OUTPUT_FILE := $$(APPLE_CROSS_FILE) +$$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE): + $$(CREATE_OUTPUT_FILE) +endef + +define NEW_WASM_CROSS_FILE +# Create cross file for thorvg +$2/$(MESON_CROSS_FILE): SYSTEM := $3 +$2/$(MESON_CROSS_FILE): CPU_FAMILY := $$($1_CPU_FAMILY) +$2/$(MESON_CROSS_FILE): CPU := $$($1_CPU) +$2/$(MESON_CROSS_FILE): export OUTPUT_FILE := $$(WASM_CROSS_FILE) +$2/$(MESON_CROSS_FILE): $$(CREATE_OUTPUT_FILE) endef define NEW_THORVG_BUILD # Setup meson for thorvg -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): export PKG_CONFIG_PATH := $(PWD)/$$($1_DEPS_LIB_DIR)/pkgconfig:$(PWD)/$$($1_DEPS_LIB64_DIR)/pkgconfig -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): THORVG_DEP_SOURCE_DIR := $(DEPS_MODULES_DIR)/$(THORVG) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): THORVG_DEP_BUILD_DIR := $$($1_THORVG_DEP_BUILD_DIR) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): CROSS_FILE := --cross-file $$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $$($1_THORVG_DEP_BUILD_DIR)/../$(THORVG_CROSS_FILE) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(LIBJPEG_TURBO_LIB) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(LIBPNG_LIB) -$$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(ZLIB_LIB) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): export PKG_CONFIG_PATH := $(PWD)/$$($1_DEPS_LIB_DIR)/pkgconfig:$(PWD)/$$($1_DEPS_LIB64_DIR)/pkgconfig +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): THORVG_DEP_SOURCE_DIR := $(DEPS_MODULES_DIR)/$(THORVG) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): THORVG_DEP_BUILD_DIR := $$($1_THORVG_DEP_BUILD_DIR) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): CROSS_FILE := --cross-file $$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): LOG := $2 +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): STATIC := $3 +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): SAVERS := $4 +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): $$($1_THORVG_DEP_BUILD_DIR)/../$(MESON_CROSS_FILE) +$(if $(filter $3,false), +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(LIBJPEG_TURBO_LIB) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(LIBPNG_LIB) +$$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE): $$($1_DEPS_LIB_DIR)/$(ZLIB_LIB),) $$(SETUP_MESON) # Build thorvg $$($1_DEPS_LIB_DIR)/$(THORVG_LIB): DEP_BUILD_DIR := $$($1_THORVG_DEP_BUILD_DIR) $$($1_DEPS_LIB_DIR)/$(THORVG_LIB): ARTIFACTS_DIR := ../../../artifacts/$$($1)/usr -$$($1_DEPS_LIB_DIR)/$(THORVG_LIB): $$($1_THORVG_DEP_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE) +$$($1_DEPS_LIB_DIR)/$(THORVG_LIB): $$($1_THORVG_DEP_BUILD_DIR)/$(NINJA_BUILD_FILE) $$(NINJA_BUILD) endef @@ -460,7 +575,7 @@ $(eval $(call NEW_ANDROID_CMAKE_BUILD,$1,LIBJPEG_TURBO,$(LIBJPEG_TURBO),$$($1_LI $(eval $(call NEW_ANDROID_CMAKE_BUILD,$1,LIBPNG_LIB,$(LIBPNG),$$($1_LIBPNG_DEP_BUILD_DIR),$(LIBPNG_LIB))) $(eval $(call NEW_ANDROID_CMAKE_BUILD,$1,ZLIB,$(ZLIB),$$($1_ZLIB_DEP_BUILD_DIR),$(ZLIB_LIB))) $(eval $(call NEW_ANDROID_CROSS_FILE,$1)) -$(eval $(call NEW_THORVG_BUILD,$1)) +$(eval $(call NEW_THORVG_BUILD,$1,true,false,all)) endef define NEW_APPLE_DEPS_BUILD @@ -468,7 +583,12 @@ $(eval $(call NEW_APPLE_CMAKE_BUILD,$1,LIBJPEG_TURBO,$(LIBJPEG_TURBO),$$($1_LIBJ $(eval $(call NEW_APPLE_CMAKE_BUILD,$1,LIBPNG_LIB,$(LIBPNG),$$($1_LIBPNG_DEP_BUILD_DIR),$(LIBPNG_LIB))) $(eval $(call NEW_APPLE_CMAKE_BUILD,$1,ZLIB,$(ZLIB),$$($1_ZLIB_DEP_BUILD_DIR),$(ZLIB_LIB))) $(eval $(call NEW_APPLE_CROSS_FILE,$1)) -$(eval $(call NEW_THORVG_BUILD,$1)) +$(eval $(call NEW_THORVG_BUILD,$1,true,false,all)) +endef + +define NEW_WASM_DEPS_BUILD +$(eval $(call NEW_WASM_CROSS_FILE,$1,$$($1_THORVG_DEP_BUILD_DIR)/..,windows)) +$(eval $(call NEW_THORVG_BUILD,$1,false,true,)) endef define NEW_ANDROID_BUILD @@ -546,6 +666,53 @@ $(RUNTIME_FFI)/$(APPLE_BUILD)/$1/$(DOTLOTTIE_PLAYER_FRAMEWORK): $(RUNTIME_FFI)/$ $$(APPLE_RELEASE) endef +define NEW_WASM_BUILD +# Setup final artifact variables +$1_RUNTIME_FFI_DEPS_BUILD_DIR := $(RUNTIME_FFI)/target/$$($1)/release + +# Build dotlottie-ffi +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): export ARTIFACTS_INCLUDE_DIR := ../$$($1_DEPS_INCLUDE_DIR) +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): export ARTIFACTS_LIB_DIR := ../$$($1_DEPS_LIB_DIR) +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): export ARTIFACTS_LIB64_DIR := ../$$($1_DEPS_LIB_DIR)64 +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): export CARGO_TARGET := $$($1) +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): PROJECT_DIR := $(RUNTIME_FFI) +$$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB): $$($1_DEPS_LIB_DIR)/$(THORVG_LIB) + $$(CARGO_BUILD) + +# Setup WASM build cross file +$(call NEW_WASM_CROSS_FILE,$1,$(RUNTIME_FFI)/$(WASM_BUILD),emscripten) + +# Setup WASM meson build +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): DEPS_INCLUDE_DIR := $(PROJECT_DIR)/$$($1_DEPS_INCLUDE_DIR) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): DEPS_LIB_DIR := $(PROJECT_DIR)/$$($1_DEPS_LIB_DIR) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): FFI_BUILD_DIR := $(PROJECT_DIR)/$$($1_RUNTIME_FFI_DEPS_BUILD_DIR) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): FFI_BINDINGS_DIR := $(PROJECT_DIR)/$(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): export OUTPUT_FILE = $$(WASM_MESON_BUILD_FILE) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): $$($1_RUNTIME_FFI_DEPS_BUILD_DIR)/$(RUNTIME_FFI_STATIC_LIB) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE): $(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_CROSS_FILE) + $$(CREATE_OUTPUT_FILE) + +# Setup meson for WASM +$(RUNTIME_FFI)/$(WASM_BUILD)/$(NINJA_BUILD_FILE): WASM_SRC_DIR := $(RUNTIME_FFI)/$(WASM_BUILD) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(NINJA_BUILD_FILE): WASM_BUILD_DIR := $(RUNTIME_FFI)/$(WASM_BUILD)/$(BUILD) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(NINJA_BUILD_FILE): CROSS_FILE := $(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_CROSS_FILE) +$(RUNTIME_FFI)/$(WASM_BUILD)/$(NINJA_BUILD_FILE): $(RUNTIME_FFI)/$(WASM_BUILD)/$(MESON_BUILD_FILE) + $$(SETUP_WASM_MESON) + +# Build release +$(RELEASE)/$(WASM)/$(WASM_MODULE).wasm $(RELEASE)/$(WASM)/$(WASM_MODULE).js: DEP_BUILD_DIR := $(RUNTIME_FFI)/$(WASM_BUILD)/$(BUILD) +$(RELEASE)/$(WASM)/$(WASM_MODULE).wasm $(RELEASE)/$(WASM)/$(WASM_MODULE).js: ARTIFACTS_DIR := $(RELEASE)/$(WASM) +$(RELEASE)/$(WASM)/$(WASM_MODULE).wasm $(RELEASE)/$(WASM)/$(WASM_MODULE).js: $(RUNTIME_FFI)/$(WASM_BUILD)/$(NINJA_BUILD_FILE) + $$(NINJA_BUILD) + $$(WASM_RELEASE) + +.PHONY: $$($1) +$$($1): $(RELEASE)/$(WASM)/$(WASM_MODULE).wasm $(RELEASE)/$(WASM)/$(WASM_MODULE).js + +WASM_BUILD_TARGETS += $$($1) +endef + define TARGET_PREFIX $(shell echo $(1) | tr '[:lower:]-' '[:upper:]_') endef @@ -580,18 +747,21 @@ $(eval $(call NEW_LOCAL_ARCH_CMAKE_BUILD,LIBPNG,$(LIBPNG),$(LIBPNG_LIB))) $(eval $(call NEW_LOCAL_ARCH_CMAKE_BUILD,ZLIB,$(ZLIB),$(ZLIB_LIB))) # Setup meson for thorvg local arch build -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): export PKG_CONFIG_PATH := $(PWD)/$(LOCAL_ARCH_LIB_DIR)/pkgconfig:$(PWD)/$(LOCAL_ARCH_LIB64_DIR) -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): THORVG_DEP_SOURCE_DIR := $(DEPS_MODULES_DIR)/$(THORVG) -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): THORVG_DEP_BUILD_DIR := $(THORVG_LOCAL_ARCH_BUILD_DIR) -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(LIBJPEG_TURBO_LIB) -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(LIBPNG_LIB) -$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(ZLIB_LIB) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): export PKG_CONFIG_PATH := $(PWD)/$(LOCAL_ARCH_LIB_DIR)/pkgconfig:$(PWD)/$(LOCAL_ARCH_LIB64_DIR) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): THORVG_DEP_SOURCE_DIR := $(DEPS_MODULES_DIR)/$(THORVG) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): THORVG_DEP_BUILD_DIR := $(THORVG_LOCAL_ARCH_BUILD_DIR) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): LOG := true +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): STATIC := false +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): SAVERS := all +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(LIBJPEG_TURBO_LIB) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(LIBPNG_LIB) +$(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE): $(LOCAL_ARCH_LIB_DIR)/$(ZLIB_LIB) $(SETUP_MESON) # Build thorvg local arch $(LOCAL_ARCH_LIB_DIR)/$(THORVG_LIB): DEP_BUILD_DIR := $(THORVG_LOCAL_ARCH_BUILD_DIR) $(LOCAL_ARCH_LIB_DIR)/$(THORVG_LIB): ARTIFACTS_DIR := ../../../../artifacts/$(LOCAL_ARCH)/usr -$(LOCAL_ARCH_LIB_DIR)/$(THORVG_LIB): $(THORVG_LOCAL_ARCH_BUILD_DIR)/$(THORVG_NINJA_BUILD_FILE) +$(LOCAL_ARCH_LIB_DIR)/$(THORVG_LIB): $(THORVG_LOCAL_ARCH_BUILD_DIR)/$(NINJA_BUILD_FILE) $(NINJA_BUILD) # Uniffi Bindings - kotlin @@ -612,6 +782,10 @@ $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(SWIFT): $(LOCAL_ARCH_LIB_DIR)/$( $(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(SWIFT): $(RUNTIME_FFI_SRC) $(UNIFFI_BINDINGS_BUILD) +# Uniffi Bindings - cpp (for wasm) +$(RUNTIME_FFI)/$(RUNTIME_FFI_UNIFFI_BINDINGS)/$(CPLUSPLUS): $(RUNTIME_FFI_SRC) + $(UNIFFI_BINDINGS_CPP_BUILD) + # Define all android targets $(eval $(call DEFINE_TARGET,aarch64-linux-android,aarch64-linux-android,arm64-v8a,arm,aarch64)) $(eval $(call DEFINE_TARGET,armv7-linux-androideabi,armv7a-linux-androideabi,armeabi-v7a,arm,armv7)) @@ -653,6 +827,15 @@ $(eval $(call NEW_APPLE_FRAMEWORK,$(APPLE_IOS_FRAMEWORK_TYPE),$(APPLE_IOS_FRAMEW $(eval $(call NEW_APPLE_FRAMEWORK,$(APPLE_IOS_SIMULATOR_FRAMEWORK_TYPE),$(APPLE_IOS_SIMULATOR_FRAMEWORK_TARGETS),$(APPLE_IOS_SIMULATOR_PLATFORM),)) $(eval $(call NEW_APPLE_FRAMEWORK,$(APPLE_MACOSX_FRAMEWORK_TYPE),$(APPLE_MACOSX_FRAMEWORK_TARGETS),$(APPLE_MACOSX_PLATFORM),)) +# Define WASM targets +$(eval $(call DEFINE_TARGET,wasm32-unknown-emscripten,emscripten,emscripten,x86,i686)) + +# Define WASM deps builds +$(eval $(call NEW_WASM_DEPS_BUILD,WASM32_UNKNOWN_EMSCRIPTEN)) + +# Define all WASM builds +$(eval $(call NEW_WASM_BUILD,WASM32_UNKNOWN_EMSCRIPTEN)) + # Build apple module-map file $(RUNTIME_FFI)/$(APPLE_BUILD)/$(MODULE_MAP): MODULE_NAME := $(DOTLOTTIE_PLAYER_MODULE) $(RUNTIME_FFI)/$(APPLE_BUILD)/$(MODULE_MAP): UMBRELLA_HEADER := $(DOTLOTTIE_PLAYER_HEADER) @@ -670,8 +853,11 @@ $(ANDROID): $(ANDROID_BUILD_TARGETS) .PHONY: $(APPLE) $(APPLE): $(APPLE_BUILD_TARGETS) +.PHONY: $(WASM) +$(WASM): $(WASM_BUILD_TARGETS) + .PHONY: all -all: $(APPLE) $(ANDROID) +all: $(APPLE) $(ANDROID) $(WASM) .PHONY: deps deps: @@ -699,6 +885,8 @@ clean: clean-build clean-all: clean clean-deps .PHONY: mac-setup +mac-setup: export EMSDK_VERSION := $(EMSDK_VERSION) +mac-setup: export UNIFFI_BINDGEN_CPP_VERSION:= $(UNIFFI_BINDGEN_CPP_VERSION) mac-setup: @./.$@.sh @@ -706,22 +894,33 @@ mac-setup: help: @echo "Welcome to the $(GREEN)dotlottie-player$(NC) build system!" @echo - @echo "$(GREEN)*************************************************************************************************$(NC)" - @echo "$(GREEN)NOTE$(NC): If you are a $(GREEN)mac$(NC) user, run $(YELLOW)make mac-setup$(NC) the very first time before performing any builds." + @echo "$(YELLOW)*************************************************************************************************$(NC)" + @echo "$(YELLOW)NOTE$(NC): If you are a $(GREEN)mac$(NC) user, run $(YELLOW)make mac-setup$(NC) the very first time before performing any builds." @echo " This will ensure your local machine has all the required tools installed." @echo @echo " After building a target, you should find your artifacts in the $(GREEN)release$(NC) directory." - @echo "$(GREEN)*************************************************************************************************$(NC)" + @echo "$(YELLOW)*************************************************************************************************$(NC)" @echo + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" @echo "The following targets are available for $(GREEN)android$(NC):" @printf " - $(YELLOW)%s$(NC)\n" $(ANDROID_BUILD_TARGETS) @echo @echo "Use the $(YELLOW)android$(NC) target to build all android targets." + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" @echo + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" @echo "The following targets are available for $(GREEN)apple$(NC):" @printf " - $(YELLOW)%s$(NC)\n" $(APPLE_BUILD_TARGETS) @echo @echo "Use the $(YELLOW)apple$(NC) target to build all apple targets." + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" + @echo + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" + @echo "The following targets are available for $(GREEN)wasm$(NC):" + @printf " - $(YELLOW)%s$(NC)\n" $(WASM_BUILD_TARGETS) + @echo + @echo "Use the $(YELLOW)wasm$(NC) target to build all wasm targets." + @echo "$(GREEN)-------------------------------------------------------------------------------------------------$(NC)" @echo @echo "The following are make targets you might also find useful:" @echo " - $(YELLOW)demo-player$(NC) - build the demo player" diff --git a/deps/modules/emsdk b/deps/modules/emsdk new file mode 160000 index 00000000..8822664a --- /dev/null +++ b/deps/modules/emsdk @@ -0,0 +1 @@ +Subproject commit 8822664a145391eee7cb57f9db7ba3705e19f2fe diff --git a/dotlottie-ffi/Cargo.toml b/dotlottie-ffi/Cargo.toml index 8a9d5082..70c8c0f9 100644 --- a/dotlottie-ffi/Cargo.toml +++ b/dotlottie-ffi/Cargo.toml @@ -6,7 +6,7 @@ build = "build.rs" [lib] crate-type = ["staticlib", "cdylib", "rlib"] -name = "dlplayer" +name = "dotlottie_player" [[bin]] name = "uniffi-bindgen" @@ -19,3 +19,4 @@ dotlottie_player = { path = "../dotlottie-rs" } [build-dependencies] uniffi = { version = "0.24.3", features = ["build"] } +lazy_static = "1.4" diff --git a/dotlottie-ffi/build.rs b/dotlottie-ffi/build.rs index a18e4d4e..e3c732c6 100644 --- a/dotlottie-ffi/build.rs +++ b/dotlottie-ffi/build.rs @@ -1,3 +1,44 @@ +use lazy_static::lazy_static; +use std::env; + +// Target triple for WASM +const WASM32_UNKNOWN_EMSCRIPTEN: &str = "wasm32-unknown-emscripten"; + +// Target-specifc build settings +struct BuildSettings { + link_args: Vec, +} + +fn is_wasm_build() -> bool { + match env::var("TARGET") { + Ok(target) => target == WASM32_UNKNOWN_EMSCRIPTEN, + Err(_) => panic!("TARGET environment variable not set"), + } +} + +lazy_static! { + // Native library dependencies + static ref TARGET_BUILD_SETTINGS: BuildSettings = match is_wasm_build() { + true => BuildSettings{ + link_args: vec![String::from("--no-entry"), String::from("-sERROR_ON_UNDEFINED_SYMBOLS=0")], + }, + _ => BuildSettings{ + link_args: vec![], + }, + }; +} + +fn register_link_arg(arg: &String) { + println!("cargo:rustc-link-arg={}", arg); +} + +fn apply_build_settings(build_settings: &BuildSettings) { + build_settings.link_args.iter().for_each(register_link_arg); +} + fn main() { - uniffi::generate_scaffolding("src/dlplayer.udl").unwrap(); + uniffi::generate_scaffolding("src/dotlottie_player.udl").unwrap(); + + // Apply build settings + apply_build_settings(&TARGET_BUILD_SETTINGS); } diff --git a/dotlottie-ffi/src/dlplayer.udl b/dotlottie-ffi/src/dotlottie_player.udl similarity index 100% rename from dotlottie-ffi/src/dlplayer.udl rename to dotlottie-ffi/src/dotlottie_player.udl diff --git a/dotlottie-ffi/src/lib.rs b/dotlottie-ffi/src/lib.rs index ef2700b3..e4f5b4e6 100644 --- a/dotlottie-ffi/src/lib.rs +++ b/dotlottie-ffi/src/lib.rs @@ -1,5 +1,5 @@ -pub use dotlottie_player::DotLottiePlayer; +pub use dotlottie_player_core::DotLottiePlayer; // use dotlottie_player::DotLottiePlayer; -uniffi::include_scaffolding!("dlplayer"); +uniffi::include_scaffolding!("dotlottie_player"); diff --git a/dotlottie-ffi/uniffi-emscripten-bindings.sh b/dotlottie-ffi/uniffi-emscripten-bindings.sh new file mode 100755 index 00000000..81bf9090 --- /dev/null +++ b/dotlottie-ffi/uniffi-emscripten-bindings.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" + +UNIFFI_BINDINGS_CPP_DIR="${UNIFFI_BINDINGS_CPP_DIR:-${SCRIPT_DIR}/uniffi-bindings/cpp}" +UNIFFI_UDL="${UNIFFI_UDL:-${SCRIPT_DIR}/src/dotlottie_player.udl}" +EMSCRIPTEN_BINDINGS_CPP="${EMSCRIPTEN_BINDINGS_CPP:-${UNIFFI_BINDINGS_CPP_DIR}/emscripten_bindings.cpp}" + +GENERATE_EMSCRIPTEN_BINDINGS=$(cat << 'EOF' +BEGIN { + print "#include " + print "using namespace emscripten;" + print +} + +/^namespace / { namespace = $2 } + +function camelCase(str) { + while (match(str, /_./)) { + char = substr(str, RSTART + 1, 1) + str = substr(str, 1, RSTART - 1) toupper(char) substr(str, RSTART + 2) + } + return str +} + +/^interface / { + interface = $2 + printf "EMSCRIPTEN_BINDINGS(%s) {\n", interface + printf " class_<%s::%s>(\"%s\")", namespace, interface, interface +} +/^[[:space:]]+[a-z]+/ { + if (length(interface) > 0) { + if (index($1, "constructor()")) { + printf "\n .constructor(&%s::%s::init)", namespace, interface + } else { + split($2, identifier, "(") + printf "\n .function(\"%s\", &%s::%s::%s)", + camelCase(identifier[1]), namespace, interface, identifier[1] + } + } +} +/^}/ { + if (length(interface) > 0) { + interface = "" + print ";\n}" + } +} +EOF +) + +# Add header includes +find "${UNIFFI_BINDINGS_CPP_DIR}" \ + -name "*.hpp" \ + -and -not -name "*scaffolding*" \ + -exec sh -c 'file="$1"; printf "#include \"%s\"\n" $(basename "${file}")' shell {} \; > "${EMSCRIPTEN_BINDINGS_CPP}" + +# Add emscripten bindings +awk "${GENERATE_EMSCRIPTEN_BINDINGS}" "${UNIFFI_UDL}" >> "${EMSCRIPTEN_BINDINGS_CPP}" diff --git a/dotlottie-rs/Cargo.toml b/dotlottie-rs/Cargo.toml index ddffb060..310214c4 100644 --- a/dotlottie-rs/Cargo.toml +++ b/dotlottie-rs/Cargo.toml @@ -6,7 +6,7 @@ links = "thorvg" [lib] crate-type = ["staticlib", "cdylib", "rlib"] -name = "dotlottie_player" +name = "dotlottie_player_core" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/dotlottie-rs/build.rs b/dotlottie-rs/build.rs index 4d8a0d0b..1885e8e5 100644 --- a/dotlottie-rs/build.rs +++ b/dotlottie-rs/build.rs @@ -5,6 +5,23 @@ use std::path::{Path, PathBuf}; // Path for all default artifacts const DEFAULT_ARTIFACTS_DIR: &str = "../deps/artifacts/local-arch/usr"; +// Target triple for WASM +const WASM32_UNKNOWN_EMSCRIPTEN: &str = "wasm32-unknown-emscripten"; + +// Target-specifc build settings +struct BuildSettings { + static_libs: Vec, + dynamic_libs: Vec, + link_args: Vec, +} + +fn is_wasm_build() -> bool { + match std::env::var("TARGET") { + Ok(target) => target == WASM32_UNKNOWN_EMSCRIPTEN, + Err(_) => panic!("TARGET environment variable not set"), + } +} + lazy_static! { // The project root directory static ref PROJECT_DIR: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -15,8 +32,18 @@ lazy_static! { static ref DEFAULT_LIB64_DIR: PathBuf = PathBuf::from(&format!("{DEFAULT_ARTIFACTS_DIR}/lib64")); // Native library dependencies - static ref NATIVE_STATIC_LIBS: Vec = vec![String::from("thorvg"), String::from("turbojpeg"), String::from("png"), String::from("z")]; - static ref NATIVE_DYNAMIC_LIBS: Vec = vec![String::from("c++")]; + static ref TARGET_BUILD_SETTINGS: BuildSettings = match is_wasm_build() { + true => BuildSettings{ + static_libs: vec![String::from("thorvg")], + dynamic_libs: vec![], + link_args: vec![String::from("--no-entry")], + }, + _ => BuildSettings{ + static_libs: vec![String::from("thorvg"), String::from("turbojpeg"), String::from("png"), String::from("z")], + dynamic_libs: vec![String::from("c++")], + link_args: vec![], + }, + }; } fn find_path(var: &str, default: &Path, required: bool) -> PathBuf { @@ -43,6 +70,19 @@ fn register_dylib(lib: &String) { println!("cargo:rustc-link-lib=dylib={}", lib); } +fn register_link_arg(arg: &String) { + println!("cargo:rustc-link-arg={}", arg); +} + +fn apply_build_settings(build_settings: &BuildSettings) { + build_settings + .static_libs + .iter() + .for_each(register_static_lib); + build_settings.dynamic_libs.iter().for_each(register_dylib); + build_settings.link_args.iter().for_each(register_link_arg); +} + fn main() { let include_dir = find_path("ARTIFACTS_INCLUDE_DIR", &DEFAULT_INCLUDE_DIR, true); let lib_dir = find_path("ARTIFACTS_LIB_DIR", &DEFAULT_LIB_DIR, true); @@ -53,10 +93,8 @@ fn main() { register_link_path(&lib_dir); register_link_path(&lib64_dir); - // Ensure libraries are made available - NATIVE_STATIC_LIBS.iter().for_each(register_static_lib); - NATIVE_DYNAMIC_LIBS.iter().for_each(register_dylib); - println!("cargo:rustc-link-lib=static=thorvg"); + // Apply build settings + apply_build_settings(&TARGET_BUILD_SETTINGS); println!("cargo:rerun-if-changed=wrapper.h"); let bindings = bindgen::Builder::default()