wamr: Add external module registration mechanism

This patch adds module registration mechanism for WAMR runtime.

To register a module, these steps are required:
1. Include Module.mk in your module's Makefile
2. Define WAMR_MODULE_NAME as the module name
3. Implement bool wamr_module_WAMR_MODULE_NAME_register(void) function in your module's source file
4. Enable INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY in menuconfig

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
This commit is contained in:
Huang Qi 2024-08-23 10:25:06 +08:00 committed by Xiang Xiao
parent df4cdbaae9
commit 9320597c00
9 changed files with 280 additions and 2 deletions

View file

@ -30,6 +30,7 @@ if(CONFIG_APPS_DIR)
# add apps cmake modules
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
include(nuttx_add_luamod)
include(nuttx_add_wamrmod)
nuttx_add_library(apps)
if(NOT EXISTS {NUTTX_APPS_BINDIR}/dummy.c)
file(TOUCH ${NUTTX_APPS_BINDIR}/dummy.c)

View file

@ -0,0 +1,76 @@
# ##############################################################################
# cmake/nuttx_add_wamrmod.cmake
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################
set(WAMR_MODULE_DIR ${CMAKE_BINARY_DIR}/wamrmod)
if(NOT EXISTS {WAMR_MODULE_DIR})
file(MAKE_DIRECTORY ${WAMR_MODULE_DIR})
endif()
include(nuttx_parse_function_args)
# ~~~
# nuttx_add_wamrmod
#
# Description:
# Register custom module into WAMR runtime
#
# Example:
# nuttx_add_wamrmod(
# MODS
# ${custom_mods}
# )
# ~~~
function(nuttx_add_wamrmod)
# parse arguments into variables
nuttx_parse_function_args(
FUNC
nuttx_add_wamrmod
MULTI_VALUE
MODS
REQUIRED
MODS
ARGN
${ARGN})
set(WAMR_MODULE_LIST ${WAMR_MODULE_DIR}/wamr_external_module_list.h)
set(WAMR_MODULE_PROTO ${WAMR_MODULE_DIR}/wamr_external_module_proto.h)
foreach(mod ${MODS})
set(MOD_PDAT ${WAMR_MODULE_DIR}/${mod}.pdat)
set(MOD_BDAT ${WAMR_MODULE_DIR}/${mod}.bdat)
add_custom_command(
OUTPUT ${MOD_PDAT} ${MOD_BDAT}
COMMAND ${CMAKE_COMMAND} -E echo "wamr_module_${mod}_register," >>
${WAMR_MODULE_LIST}
COMMAND ${CMAKE_COMMAND} -E echo "bool wamr_module_${mod}_register(void);"
>> ${WAMR_MODULE_PROTO}
COMMAND ${CMAKE_COMMAND} -E touch ${MOD_PDAT}
COMMAND ${CMAKE_COMMAND} -E touch ${MOD_BDAT}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
VERBATIM
COMMENT "WAMR Module: Gen and Updating external module => ${mod}")
add_custom_target(wamr_module_${mod} DEPENDS ${MOD_PDAT} ${MOD_BDAT})
add_dependencies(apps_context wamr_module_${mod})
endforeach()
endfunction()

View file

@ -1,3 +1,5 @@
*.zip
wamr
wasm-micro-runtime-*
wamr_external_module_list.h
wamr_external_module_proto.h

View file

@ -71,4 +71,17 @@ if(CONFIG_INTERPRETERS_WAMR)
DEPENDS
wamr)
if(CONFIG_INTERPRETERS_WAMR_LIBC_NUTTX
OR CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY)
nuttx_append_source_file_properties(
${WAMR_DIR}/product-mini/platforms/nuttx/main.c COMPILE_FLAGS
-Dwasm_runtime_full_init=wamr_custom_init)
target_sources(wamr PRIVATE wamr_custom_init.c)
endif()
# Add ${CMAKE_BINARY_DIR}/wamrmod to the include directories
if(CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY)
target_include_directories(wamr PRIVATE ${CMAKE_BINARY_DIR}/wamrmod)
endif()
endif()

View file

@ -248,4 +248,12 @@ config INTERPRETERS_WAMR_CONFIGUABLE_BOUNDS_CHECKS
disable bounds checks passing --disable-bounds-checks to
iwasm.
endif # INTERPRETERS_WAMR
config INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY
bool "Enable external module registry"
default n
---help---
This option enables the support for loading WASM modules from
external libraries, which is useful when you want to extend the
functionality of WAMR without modifying its source code.
endif

View file

@ -39,6 +39,23 @@ PROGNAME = iwasm
PRIORITY = $(CONFIG_INTERPRETERS_WAMR_PRIORITY)
STACKSIZE = $(CONFIG_INTERPRETERS_WAMR_STACKSIZE)
MODULE = $(CONFIG_INTERPRETERS_WAMR)
endif
WAMR_NEED_CUSTOM_INIT = n
# Check if we need to build custom init code
ifeq ($(CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY),y)
WAMR_NEED_CUSTOM_INIT = y
endif
# If we need custom init code, add it to the build
ifeq ($(WAMR_NEED_CUSTOM_INIT),y)
# When the loadable module configuration is enabled,we need to use CELFFLAGS
$(WAMR_UNPACK)/product-mini/platforms/nuttx/main.c_CFLAGS = -Dwasm_runtime_full_init=wamr_custom_init
$(WAMR_UNPACK)/product-mini/platforms/nuttx/main.c_CELFFLAGS = -Dwasm_runtime_full_init=wamr_custom_init
CSRCS += wamr_custom_init.c
endif
$(WAMR_TARBALL):
@ -51,11 +68,50 @@ $(WAMR_UNPACK): $(WAMR_TARBALL)
$(Q) mv wasm-micro-runtime-$(WAMR_VERSION) $(WAMR_UNPACK)
$(Q) touch $(WAMR_UNPACK)
# Register the external WAMR module
ifeq ($(CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY),y)
PDATLIST = $(strip $(call RWILDCARD, registry, *.pdat))
BDATLIST = $(strip $(call RWILDCARD, registry, *.bdat))
registry$(DELIM).updated:
$(Q) touch registry$(DELIM).updated
wamr_external_module_list.h: registry$(DELIM).updated
ifeq ($(BDATLIST),)
$(call DELFILE, wamr_external_module_list.h)
$(Q) touch wamr_external_module_list.h
else
$(call CATFILE, wamr_external_module_list.h, $(BDATLIST))
endif
wamr_external_module_proto.h: registry$(DELIM).updated
ifeq ($(PDATLIST),)
$(call DELFILE, wamr_external_module_proto.h)
$(Q) touch wamr_external_module_proto.h
else
$(call CATFILE, wamr_external_module_proto.h, $(PDATLIST))
endif
depend:: $(GLUECSRCS) wamr_external_module_list.h wamr_external_module_proto.h
endif # CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY
clean::
$(call DELFILE, wamr_external_module_list.h)
$(call DELFILE, wamr_external_module_proto.h)
clean_context::
$(call DELFILE, $(BDATLIST))
$(call DELFILE, $(PDATLIST))
# Download and unpack tarball if no git repo found
ifeq ($(wildcard $(WAMR_UNPACK)/.git),)
context:: $(WAMR_UNPACK)
endif
distclean::
distclean:: clean clean_context
ifeq ($(wildcard $(WAMR_UNPACK)/.git),)
$(call DELDIR, $(WAMR_UNPACK))
$(call DELFILE, $(WAMR_TARBALL))
endif

View file

@ -0,0 +1,37 @@
############################################################################
# apps/interpreters/wamr/Module.mk
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
WAMR_MODULE_REGISTRY = $(APPDIR)$(DELIM)interpreters$(DELIM)wamr$(DELIM)registry
define WAMR_MODULE_REGISTER
$(Q) echo Register WAMR Module: $1
$(Q) echo "$2," > "$(WAMR_MODULE_REGISTRY)$(DELIM)$1.bdat"
$(Q) echo "bool $2(void);" > "$(WAMR_MODULE_REGISTRY)$(DELIM)$1.pdat"
$(Q) touch "$(WAMR_MODULE_REGISTRY)$(DELIM).updated"
endef
ifneq ($(WAMR_MODULE_NAME),)
WAMR_MODULE_LIST := $(addprefix $(WAMR_MODULE_REGISTRY)$(DELIM),$(addsuffix .bdat,$(WAMR_MODULE_NAME)))
$(WAMR_MODULE_LIST): $(DEPCONFIG) Makefile
$(call WAMR_MODULE_REGISTER,$(firstword $(WAMR_MODULE_NAME)),$(firstword wamr_module_$(WAMR_MODULE_NAME)_register))
$(eval WAMR_MODULE_NAME=$(filter-out $(firstword $(WAMR_MODULE_NAME)),$(WAMR_MODULE_NAME)))
register:: $(WAMR_MODULE_LIST)
endif

3
interpreters/wamr/registry/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.updated
*.pdat
*.bdat

View file

@ -0,0 +1,82 @@
/****************************************************************************
* apps/interpreters/wamr/wamr_custom_init.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <semaphore.h>
#include <sys/param.h>
#include <sys/types.h>
#include <iconv.h>
#include "wasm_native.h"
#include "wamr_custom_init.h"
#ifdef CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY
#include "wamr_external_module_proto.h"
#endif
/****************************************************************************
* Private Data
****************************************************************************/
typedef bool (*module_register_t)(void);
#ifdef CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY
static const module_register_t g_wamr_modules[] =
{
#include "wamr_external_module_list.h"
};
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
bool wamr_custom_init(RuntimeInitArgs *init_args)
{
bool ret = wasm_runtime_full_init(init_args);
if (!ret)
{
return ret;
}
/* Add extra init hook here */
#ifdef CONFIG_INTERPRETERS_WAMR_EXTERNAL_MODULE_REGISTRY
for (int i = 0; i < nitems(g_wamr_modules); i++)
{
ret = g_wamr_modules[i]();
if (!ret)
{
return ret;
}
}
#endif
return ret;
}