# ##############################################################################
# apps/tools/Wasm/WASI-SDK.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.
#
# ##############################################################################
# This file is to used for finding the WASI SDK and setting up the necessary
# flags for building WebAssembly applications with CMake or Makefile in NuttX
# build system.
#
# This file is intended to be included in the top-level CMakeLists.txt file of
# the application.
#
# For legacy Makefile-based build system, CMake will be called in the Makefile
# to do actual build.
# If no WASI_SDK_PATH is provided, the raise an error and stop the build
if(NOT DEFINED WASI_SDK_PATH)
message(FATAL_ERROR "WASI_SDK_PATH is not defined."
"Please set it to the path of the WASI SDK.")
endif()
# Set the system name, version and processor to WASI These are from original
# WASI SDK's cmake toolchain file
set(CMAKE_SYSTEM_NAME WASI)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR wasm32)
# Fetch the wasm compiler and linker from the WASI SDK
set(CMAKE_C_COMPILER ${WASI_SDK_PATH}/bin/clang)
set(CMAKE_CXX_COMPILER ${WASI_SDK_PATH}/bin/clang++)
# setup the flags for the compiler and linker
include_directories(${TOPDIR}/include ${TOPBINDIR}/include)
if(CONFIG_DEBUG_FULLOPT)
add_compile_options(-Oz)
elseif(CONFIG_DEBUG_CUSTOMOPT)
add_compile_options(${CONFIG_DEBUG_OPTLEVEL})
endif()
if(CONFIG_LTO_FULL OR CONFIG_LTO_THIN)
add_compile_options(-flto)
add_link_options(-flto)
endif()
add_compile_options(--sysroot=${TOPDIR})
add_compile_options(-nostdlib)
add_link_options(-nostdlib)
add_compile_options(-D__NuttX__)
if(NOT CONFIG_LIBM)
add_compile_options(-DCONFIG_LIBM=1)
include_directories(${APPDIR}/include/wasm)
endif()
if(CONFIG_ARCH_64BIT)
add_compile_options(--target=wasm64)
endif()
add_link_options(-Wl,--export=main)
add_link_options(-Wl,--export=__main_argc_argv)
add_link_options(-Wl,--export=__heap_base)
add_link_options(-Wl,--export=__data_end)
add_link_options(-Wl,--no-entry)
add_link_options(-Wl,--strip-all)
add_link_options(-Wl,--allow-undefined)
execute_process(
COMMAND ${CMAKE_C_COMPILER} --print-libgcc-file-name
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE WCC_COMPILER_RT_LIB)
# ~~~
# Function "wasm_add_application" to add a WebAssembly application to the
# build system.
#
# This function is used to add a WebAssembly application to the build system.
# It creates an executable target for the application and sets the necessary
# properties for building the application.
#
# Usage:
# wasm_add_application(NAME <name> SRCS <source files>
# [STACK_SIZE <stack size>] [INITIAL_MEMORY_SIZE <initial memory size>])
#
# Parameters:
# NAME: The name of the application (NAME.wasm).
# SRCS: The source files of the application.
# STACK_SIZE: The stack size of the application. Default is 2048.
# INITIAL_MEMORY_SIZE: The initial memory size of the application.
# Default is 65536 (One page), and must be a multiple of 65536.
# ~~~
function(wasm_add_application)
# Parse the APP_NAME and APP_SRCS from the arguments
set(APP_NAME "")
set(APP_SRCS "")
set(APP_STACK_SIZE "")
set(APP_INITIAL_MEMORY_SIZE "")
set(APP_INSTALL_NAME "")
set(APP_WAMR_MODE INT)
set(APP_WCFLAGS "")
set(APP_WLDFLAGS "")
set(APP_WRCFLAGS "")
set(APP_WINCLUDES "")
cmake_parse_arguments(
APP "" "NAME;STACK_SIZE;INITIAL_MEMORY_SIZE;WAMR_MODE;INSTALL_NAME"
"SRCS;WLDFLAGS;WRCFLAGS;WCFLAGS;WINCLUDES" ${ARGN})
# Check if the APP_NAME (NAME) is provided
if(NOT APP_NAME)
message(FATAL_ERROR "NAME is not provided.")
endif()
# Check if the APP_SRCS (SRCS) is provided
if(NOT APP_SRCS)
message(FATAL_ERROR "SRCS is not provided.")
endif()
if(NOT APP_STACK_SIZE)
set(APP_STACK_SIZE 2048)
endif()
if(NOT APP_INITIAL_MEMORY_SIZE)
set(APP_INITIAL_MEMORY_SIZE 65536)
endif()
# Create the executable target for the application
add_executable(${APP_NAME} ${APP_SRCS})
target_link_libraries(${APP_NAME} PRIVATE wasm_interface)
target_include_directories(${APP_NAME} PRIVATE ${APP_WINCLUDES})
target_compile_options(${APP_NAME} PRIVATE ${APP_WCFLAGS})
target_link_options(${APP_NAME} PRIVATE -z stack-size=${APP_STACK_SIZE})
target_link_options(${APP_NAME} PRIVATE
-Wl,--initial-memory=${APP_INITIAL_MEMORY_SIZE})
target_link_options(${APP_NAME} PRIVATE ${APP_WLDFLAGS})
target_link_libraries(${APP_NAME} PRIVATE ${WCC_COMPILER_RT_LIB})
# Set the target properties
set_target_properties(${APP_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME}.wasm)
# do WASM OPTIMIZATION
set(WASM_OPT_FLAGS -Oz --enable-bulk-memory)
if(CONFIG_ARCH_64BIT)
list(APPEND WASM_OPT_FLAGS --enable-memory64)
target_link_options(${APP_NAME} PRIVATE --target=wasm64)
endif()
add_custom_target(
${APP_NAME}_OPT ALL
COMMAND ${WASI_SDK_PATH}/wasm-opt ${WASM_OPT_FLAGS} -o ${APP_NAME}.wasm
${APP_NAME}.wasm
DEPENDS ${APP_NAME}
COMMENT "WASM build:Optimizing ${APP_NAME}")
# armv7a
if(CONFIG_ARCH_ARMV7A)
if(CONFIG_ARCH_CORTEXA5)
set(LLVM_CPUTYPE cortex-a5)
elseif(CONFIG_ARCH_CORTEXA7)
set(LLVM_CPUTYPE cortex-a7)
elseif(CONFIG_ARCH_CORTEXA8)
set(LLVM_CPUTYPE cortex-a8)
elseif(CONFIG_ARCH_CORTEXA9)
set(LLVM_CPUTYPE cortex-a9)
endif()
if(CONFIG_ARM_THUMB)
set(LLVM_ARCHTYPE thumbv7)
else()
set(LLVM_ARCHTYPE armv7a)
endif()
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
endif()
# armv7m
if(CONFIG_ARCH_ARMV7M)
if(CONFIG_ARCH_CORTEXM4)
set(LLVM_CPUTYPE cortex-m4)
elseif(CONFIG_ARCH_CORTEXM7)
set(LLVM_CPUTYPE cortex-m7)
else()
set(LLVM_CPUTYPE cortex-m3)
endif()
if(CONFIG_ARCH_CORTEXM3)
set(LLVM_ARCHTYPE thumbv7m)
else()
set(LLVM_ARCHTYPE thumbv7em)
endif()
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
endif()
# armv8m
if(CONFIG_ARCH_ARMV8M)
if(CONFIG_ARM_DS)
set(EXTCPUFLAGS +dsp)
endif()
if(CONFIG_ARM_PACBTI)
set(EXTCPUFLAGS ${EXTCPUFLAGS}+pacbti)
endif()
if(CONFIG_ARM_HAVE_MVE)
set(EXTCPUFLAGS ${EXTCPUFLAGS}+mve.fp+fp.dp)
endif()
if(CONFIG_ARCH_CORTEXM23)
set(LLVM_CPUTYPE cortex-m23)
elseif(CONFIG_ARCH_CORTEXM33)
set(LLVM_CPUTYPE cortex-m33)
elseif(CONFIG_ARCH_CORTEXM35P)
set(LLVM_CPUTYPE cortex-m35p)
elseif(CONFIG_ARCH_CORTEXM55)
set(LLVM_CPUTYPE cortex-m55)
elseif(CONFIG_ARCH_CORTEXM85)
set(LLVM_CPUTYPE cortex-m85)
endif()
set(LLVM_ARCHTYPE thumbv8m.main${EXTCPUFLAGS})
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
endif()
# armv7r
if(CONFIG_ARCH_ARMV7R)
if(CONFIG_ARCH_CORTEXR4)
set(LLVM_CPUTYPE cortex-r4)
elseif(CONFIG_ARCH_CORTEXR5)
set(LLVM_CPUTYPE cortex-r5)
elseif(CONFIG_ARCH_CORTEXR7)
set(LLVM_CPUTYPE cortex-r7)
endif()
if(CONFIG_ARM_THUMB)
set(LLVM_ARCHTYPE thumbv7r)
else()
set(LLVM_ARCHTYPE armv7r)
endif()
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
endif()
# armv6m
if(CONFIG_ARCH_ARMV6M)
set(LLVM_CPUTYPE cortex-m0)
set(LLVM_ARCHTYPE thumbv6m)
set(LLVM_ABITYPE eabi)
endif()
# arch x86_64
if(CONFIG_ARCH_X86_64)
set(LLVM_CPUTYPE x86-64)
set(LLVM_ARCHTYPE x86_64)
set(LLVM_ABITYPE gnu)
endif()
set(RCFLAGS)
if(NOT DEFINED ENV{WASM_TOOLCHAIN_PATH})
message(
FATAL_ERROR
"WASM_TOOLCHAIN_PATH environment variable is not set. Please set it to the path of the WASM toolchain."
)
endif()
set(WRC $ENV{WASM_TOOLCHAIN_PATH}/wamrc)
if(CONFIG_ARCH_XTENSA)
set(WTARGET "xtensa")
elseif(CONFIG_ARCH_X86_64)
set(WTARGET "x86_64")
elseif(CONFIG_ARCH_X86)
set(WTARGET "i386")
elseif(CONFIG_ARCH_MIPS)
set(WTARGET "mips")
elseif(CONFIG_ARCH_SIM)
list(APPEND RCFLAGS --disable-simd)
if(CONFIG_SIM_M32)
set(WTARGET "i386")
else()
set(WTARGET "x86_64")
endif()
elseif(LLVM_ARCHTYPE MATCHES "thumb")
string(FIND "${LLVM_ARCHTYPE}" "+" PLUS_INDEX)
if(PLUS_INDEX EQUAL -1)
set(WTARGET "${LLVM_ARCHTYPE}")
else()
string(SUBSTRING "${LLVM_ARCHTYPE}" 0 ${PLUS_INDEX} WTARGET)
endif()
else()
set(WTARGET ${LLVM_ARCHTYPE})
endif()
set(WCPU ${LLVM_CPUTYPE})
if("${LLVM_ABITYPE}" STREQUAL "eabihf")
set(WABITYPE "gnueabihf")
else()
set(WABITYPE "${LLVM_ABITYPE}")
endif()
list(APPEND RCFLAGS --target=${WTARGET})
list(APPEND RCFLAGS --cpu=${WCPU})
list(APPEND RCFLAGS --target-abi=${WABITYPE})
if(CONFIG_INTERPRETERS_WAMR_GC)
list(APPEND RCFLAGS --enable-gc)
endif()
list(APPEND RCFLAGS ${APP_WRCFLAGS} ${WASM_AOT_FLAGS})
if(CONFIG_INTERPRETERS_WAMR_AOT)
if("${APP_WAMR_MODE}" STREQUAL "AOT")
# generate AoT
add_custom_target(
${APP_NAME}_AOT ALL
COMMAND ${WRC} ${RCFLAGS} -o ${APP_NAME}.aot ${APP_NAME}.wasm
DEPENDS ${APP_NAME}_OPT
COMMENT "Wamrc Generate AoT: ${APP_NAME}.aot")
set(APP_INSTALL_BIN ${APP_NAME}.aot)
if(NOT APP_INSTALL_NAME)
set(APP_INSTALL_NAME ${APP_NAME}.aot)
endif()
elseif("${APP_WAMR_MODE}" STREQUAL "XIP")
# generate XIP
add_custom_target(
${APP_NAME}_AOT ALL
COMMAND ${WRC} ${RCFLAGS} --enable-indirect-mode
--disable-llvm-intrinsics -o ${APP_NAME}.xip ${APP_NAME}.wasm
DEPENDS ${APP_NAME}_OPT
COMMENT "Wamrc Generate XIP: ${APP_NAME}.xip")
set(APP_INSTALL_BIN ${APP_NAME}.xip)
if(NOT APP_INSTALL_NAME)
set(APP_INSTALL_NAME ${APP_NAME}.xip)
endif()
endif()
endif()
if(NOT APP_INSTALL_BIN)
set(APP_INSTALL_BIN ${APP_NAME}.wasm)
endif()
if(NOT APP_INSTALL_NAME)
set(APP_INSTALL_NAME ${APP_NAME}.wasm)
endif()
# install WASM BIN
add_custom_target(
${APP_NAME}_INSTALL ALL
COMMAND ${CMAKE_COMMAND} -E copy ${APP_INSTALL_BIN}
${TOPBINDIR}/wasm/${APP_INSTALL_NAME}
DEPENDS ${APP_NAME}_OPT
COMMENT "Install WASM BIN: ${APP_INSTALL_NAME}")
endfunction()
# ~~~
# Function "wasm_add_library" to add a WebAssembly library to the build system.
#
# This function is used to add a WebAssembly library to the build system.
# It creates a static library target for the library and sets the necessary
# properties for building the library.
#
# Usage:
# wasm_add_library(NAME <name> SRCS <source files>)
#
# Parameters:
# NAME: The name of the library (libNAME.a).
# SRCS: The source files of the library.
# ~~~
function(wasm_add_library)
# Parse the LIB_NAME and LIB_SRCS from the arguments
set(LIB_NAME "")
set(LIB_SRCS "")
set(APP_WCFLAGS "")
set(APP_WINCLUDES "")
cmake_parse_arguments(LIB "" "NAME" "SRCS;WCFLAGS;WINCLUDES" ${ARGN})
# Check if the LIB_NAME (NAME) is provided
if(NOT LIB_NAME)
message(FATAL_ERROR "NAME is not provided.")
endif()
# Check if the LIB_NAME (NAME) is already declared If it is, then skip the
# rest of the function
if(TARGET ${LIB_NAME})
message(STATUS "Target ${LIB_NAME} already declared.")
return()
endif()
# Check if the LIB_SRCS (SRCS) is provided
if(NOT LIB_SRCS)
message(FATAL_ERROR "SRCS is not provided.")
endif()
# Create the static library target for the library
add_library(${LIB_NAME} STATIC ${LIB_SRCS})
target_include_directories(${LIB_NAME} PRIVATE ${LIB_WINCLUDES})
target_compile_options(${LIB_NAME} PRIVATE ${LIB_WCFLAGS})
add_dependencies(wasm_interface ${LIB_NAME})
target_link_libraries(wasm_interface INTERFACE ${LIB_NAME})
# Set the target properties
set_target_properties(${LIB_NAME} PROPERTIES OUTPUT_NAME ${LIB_NAME})
endfunction()