You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/09/28 07:47:47 UTC

(nuttx-apps) 01/02: wamr: Add external module registration mechanism

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 9320597c00ec1f8f0bc2f20877516d33e49389fe
Author: Huang Qi <hu...@xiaomi.com>
AuthorDate: Fri Aug 23 10:25:06 2024 +0800

    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 <hu...@xiaomi.com>
---
 CMakeLists.txt                        |  1 +
 cmake/nuttx_add_wamrmod.cmake         | 76 ++++++++++++++++++++++++++++++++
 interpreters/wamr/.gitignore          |  2 +
 interpreters/wamr/CMakeLists.txt      | 13 ++++++
 interpreters/wamr/Kconfig             | 10 ++++-
 interpreters/wamr/Makefile            | 58 ++++++++++++++++++++++++-
 interpreters/wamr/Module.mk           | 37 ++++++++++++++++
 interpreters/wamr/registry/.gitignore |  3 ++
 interpreters/wamr/wamr_custom_init.c  | 82 +++++++++++++++++++++++++++++++++++
 9 files changed, 280 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d07eaef87..f35203b3e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/cmake/nuttx_add_wamrmod.cmake b/cmake/nuttx_add_wamrmod.cmake
new file mode 100644
index 000000000..231c64d9c
--- /dev/null
+++ b/cmake/nuttx_add_wamrmod.cmake
@@ -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()
diff --git a/interpreters/wamr/.gitignore b/interpreters/wamr/.gitignore
index 0cb73d0fd..2a85b17bf 100644
--- a/interpreters/wamr/.gitignore
+++ b/interpreters/wamr/.gitignore
@@ -1,3 +1,5 @@
 *.zip
 wamr
 wasm-micro-runtime-*
+wamr_external_module_list.h
+wamr_external_module_proto.h
diff --git a/interpreters/wamr/CMakeLists.txt b/interpreters/wamr/CMakeLists.txt
index ce3be5f35..1fe37c878 100644
--- a/interpreters/wamr/CMakeLists.txt
+++ b/interpreters/wamr/CMakeLists.txt
@@ -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()
diff --git a/interpreters/wamr/Kconfig b/interpreters/wamr/Kconfig
index fbad67be1..3811d5381 100644
--- a/interpreters/wamr/Kconfig
+++ b/interpreters/wamr/Kconfig
@@ -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
diff --git a/interpreters/wamr/Makefile b/interpreters/wamr/Makefile
index f7dcae4d6..f52d5adaa 100644
--- a/interpreters/wamr/Makefile
+++ b/interpreters/wamr/Makefile
@@ -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
diff --git a/interpreters/wamr/Module.mk b/interpreters/wamr/Module.mk
new file mode 100644
index 000000000..b30eb6c87
--- /dev/null
+++ b/interpreters/wamr/Module.mk
@@ -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
diff --git a/interpreters/wamr/registry/.gitignore b/interpreters/wamr/registry/.gitignore
new file mode 100644
index 000000000..3fd3b08fc
--- /dev/null
+++ b/interpreters/wamr/registry/.gitignore
@@ -0,0 +1,3 @@
+.updated
+*.pdat
+*.bdat
diff --git a/interpreters/wamr/wamr_custom_init.c b/interpreters/wamr/wamr_custom_init.c
new file mode 100644
index 000000000..1c4dd4303
--- /dev/null
+++ b/interpreters/wamr/wamr_custom_init.c
@@ -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;
+}