Build 4diac FORTE for Multiple Target on WSL

Build 4diac FORTE for Multiple Target on WSL
Photo by Stefan Cosma / Unsplash

Eclipse 4diac™ provides an open source infrastructure for distributed industrial process measurement and control systems based on the IEC 61499 standard. 4diac includes: development environment (4diac IDE), runtime environment (4diac FORTE), function block library, and example projects.

The 4diac FORTE is a small portable implementation of an IEC 61499 runtime environment targeting small embedded control devices (16/32 Bit), implemented in C++. It supports online-reconfiguration of its applications and the real-time capable execution of all function block types provided by the IEC 61499 standard.

Supported communication layers: Ethernet (TCP/UDP), Ethernet PowerLink using openPOWERLINK V1.8.0, FBDK ASN.1 encoding, Modbus TCP client using libmodbus, MQTT using Eclipse Paho, OPC UA using open62541, OPC DA client using OPC Client library release 0.4, RS232.

Supported operating system: eCos, NET+OS 7, Posix: Cygwin, Linux (i386, PPC, ARM), rcX, VxWorks, PikeOS, Windows, freeRTOS.

Supported board: BeagleBone Black, Digi Connect ME (ARM7), emBRICK for Raspberry PI and BeagleBone Black, KIPR's CBC v2 robot controller, Lego Mindstorms EV3 (ARM7), NXH 51-ETM, Raspberry PI.

Supported Programmable Logic Controllers (PLCs): Bachmann electronic M1 PLC, Raspberry-SPS, WAGO PFC200, MicroControl uMIC.200, icom MR-router series.

Linux is a perfect environment for compiling programs for different machine targets and WSL is an easy way to set up a Linux environment on a Windows desktop. Another alternative is MSYS but it is limited to Windows targets and compilation is noticeably slow.

Windows Subsystem for Linux (WSL) is a feature of Windows that allows developers to run a Linux environment without the need for a separate virtual machine or dual booting.

Installing WSL is outside the scope here, please read the document from Microsoft regarding how to install WSL with the default Ubuntu Linux distribution. Let's start cross compiling FORTE on WSL for the Raspberry Pi 4B and/or Windows target.

Update:

A bash script for all of these tasks are included at the end of this post!

Install the additional software needed on WSL

For Raspberry Pi 4B target:

$ sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu git make cmake automake autoconf libtool cmake-gui
$ mkdir $HOME/forte

For Windows target, the g++-mingw-w64 package built into Ubuntu 22.04 doesn't seem to work properly so we need a newer version of the package from another source, extract it in your $HOME directory:

$ cd
$ sudo apt-get install gcc-mingw-w64 g++-mingw-w64
$ wget -c https://github.com/xpack-dev-tools/mingw-w64-gcc-xpack/releases/download/v13.2.0-1/xpack-mingw-w64-gcc-13.2.0-1-linux-x64.tar.gz
$ tar xvf xpack-mingw-w64-gcc-13.2.0-1-linux-x64.tar.gz
$ export PATH=$HOME/xpack-mingw-w64-gcc-13.2.0-1/bin:$PATH

Update:

I decided to upgrade Ubuntu WSL from 22.04 LTS "Jammy Jellyfish" to 24.04 LTS "Noble Numbat" to use gcc-mingw-w64 and g++-mingw-w64 packages from Ubuntu distribution but had a problem with FORTE that compilation result did not run without any error message. In order for FORTE compilation results run successfully we have to change gcc and g++ thread model from default win32 to posix, do the following:
$ sudo do-release-upgrade -d # upgrade Ubuntu to 24.04
$ sudo update-alternatives --list x86_64-w64-mingw32-gcc
/usr/bin/x86_64-w64-mingw32-gcc-posix
/usr/bin/x86_64-w64-mingw32-gcc-win32
$ sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
$ sudo update-alternatives --list x86_64-w64-mingw32-g++
/usr/bin/x86_64-w64-mingw32-g++-posix
/usr/bin/x86_64-w64-mingw32-g++-win32
$ sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix

Update:

Upgrade to Ubuntu 24.04 make me feel stupid because the compilation result for Raspberry doesn't work anymore with an error message "/lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found" even though I compiled using gcc version 11. Incompatible libc version!
$ ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu3.6) 2.35
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
I suggest sticking with Ubuntu version 22.04 or switch to GNU toolchain from Arm but then requires an adjustments in compilation: change compiler from aarch64-linux-gnu-* to aarch64-none-linux-gnu-*
$ cd
$ wget -c https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/11.3.rel1/binrel/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
$ tar xvf arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
$ export PATH=$HOME/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin:$PATH

Download and build libmodbus static library

$ cd ~/forte
$ git clone https://github.com/stephane/libmodbus.git --depth=1
$ cd libmodbus

For Raspberry target:

$ ./autogen.sh
$ ./configure --with-pic --enable-static --enable-shared=no --host=aarch64-linux-gnu --prefix=$HOME/forte/install/aarch64
$ make -j3
$ make install
$ make clean

For Windows target:

$ ./autogen.sh
$ ./configure --with-pic --enable-static --enable-shared=no --host=x86_64-w64-mingw32 --prefix=$HOME/forte/install/x86_w64
$ make -j3
$ make install
$ make clean

Download and build LuaJIT shared library with Lua 5.2 compatibility enabled

$ cd ~/forte
$ git clone https://github.com/LuaJIT/LuaJIT.git --depth=1
$ cd LuaJIT

For Raspberry target:

$ make -j3 CROSS=aarch64-linux-gnu- CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT
$ make install CROSS=aarch64-linux-gnu- CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT PREFIX=$HOME/forte/install/aarch64
$ make clean

For Windows target:

$ make -j3 CROSS=x86_64-w64-mingw32- CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT TARGET_SYS=Windows
$ mv src/luajit.exe src/luajit # a trick to prevent `make install` failure
$ cp src/lua51.dll ~/forte/install/x86_w64/lib/ # manual copy lua shared library
$ make install CROSS=x86_64-w64-mingw32- CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT TARGET_SYS=Windows PREFIX=$HOME/forte/install/x86_w64
$ make clean

Download and build OpenSSL

$ cd ~/forte
$ git clone https://github.com/openssl/openssl.git --depth=1
$ cd openssl

Build OpenSSL shared library for Raspberry target:

$ ./Configure linux-aarch64 shared --cross-compile-prefix=aarch64-linux-gnu- --prefix=$HOME/forte/install/aarch64
$ make -j3
$ make install
$ make clean

Build OpenSSL static library for Windows target:

$ ./Configure mingw64 no-shared -static --cross-compile-prefix=x86_64-w64-mingw32- --prefix=$HOME/forte/install/x86_w64
$ make -j3
$ make install
$ cp $HOME/forte/install/x86_w64/lib64/libcrypto.a $HOME/forte/install/x86_w64/lib/ # create a duplicate copy to lib
$ cp $HOME/forte/install/x86_w64/lib64/libssl.a $HOME/forte/install/x86_w64/lib/ # create a duplicate copy to lib
$ make clean

Download and build Paho MQTT static library

$ cd ~/forte
$ git clone https://github.com/eclipse/paho.mqtt.c.git --depth=1

For Raspberry target:

$ cd ~/forte
$ mkdir -p build/paho/aarch64
$ which aarch64-linux-gnu-gcc # check where gcc location
/usr/bin/aarch64-linux-gnu-gcc
$ which aarch64-linux-gnu-++ # check where g++ location
/usr/bin/aarch64-linux-gnu-g++

Run CMake from inside Ubuntu sub menu on Windows start menu and set:

Source code: /home/user/forte/paho.mqtt.c
Build binaries: /home/user/forte/build/paho/aarch64

Run Configure and select Unix Makefiles for cross compiling and set:

C compiler: /usr/bin/aarch64-linux-gnu-gcc
C++ compiler: /usr/bin/aarch64-linux-gnu-g++

Click Finish and set the setup as follows, it may be necessary to generate repeatedly to fulfill all the setups without errors.

CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/aarch64
PAHO_BUILD_SHARED=OFF
PAHO_BUILD_STATIC=ON
PAHO_ENABLE_TESTING=OFF
PAHO_WITH_SSL=ON
OPENSSL_INCLUDE_DIR=/home/user/forte/install/aarch64/include
OPENSSL_ROOT_DIR=/home/user/forte/install/aarch64
OPENSSL_CRYPTO_LIBRARY=/home/user/forte/install/aarch64/lib/libcrypto.so
OPENSSL_SSL_LIBRARY=/home/user/forte/install/aarch64/lib/libssl.so

Compile and install Paho MQTT:

make -j3
make install
make clean

For Windows target:

$ cd ~/forte
$ mkdir -p build/paho/x86_w64
$ which x86_64-w64-mingw32-gcc # check where gcc location
/home/user/xpack-mingw-w64-gcc-13.2.0-1/bin/x86_64-w64-mingw32-gcc
$ which x86_64-w64-mingw32-g++ # check where g++ location
/home/user/xpack-mingw-w64-gcc-13.2.0-1/bin/x86_64-w64-mingw32-g++

Run CMake from inside Ubuntu sub menu on Windows start menu and set:

Source code: /home/user/forte/paho.mqtt.c
Build binaries: /home/user/forte/build/paho/x86_w64

Run Configure and select Unix Makefiles for cross compiling and set:

C compiler: /home/user/xpack-mingw-w64-gcc-13.2.0-1/bin/x86_64-w64-mingw32-gcc
C++ compiler: /home/user/xpack-mingw-w64-gcc-13.2.0-1/bin/x86_64-w64-mingw32-g++

Click Finish and set the setup as follows, it may be necessary to generate repeatedly to fulfill all the setups without errors.

MINGW=ON # Manually added bool entry to tell CMake we are in a MINGW environment
CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/x86_w64
PAHO_BUILD_SHARED=OFF
PAHO_BUILD_STATIC=ON
PAHO_ENABLE_TESTING=OFF
PAHO_WITH_SSL=ON
OPENSSL_INCLUDE_DIR=/home/user/forte/install/x86_w64/include
OPENSSL_ROOT_DIR=/home/user/forte/install/x86_w64
OPENSSL_CRYPTO_LIBRARY=/home/user/forte/install/x86_w64/lib/libcrypto.a
OPENSSL_SSL_LIBRARY=/home/user/forte/install/x86_w64/lib/libssl.a

Follow Raspberry step to compile and install Paho MQTT.

Download and build open62541 OPC UA static library

$ cd ~/forte
$ git clone https://github.com/open62541/open62541.git -b pack/v1.3.9 --depth=1
$ cd open62541
$ git submodule update --init --recursive --depth 1

For Raspberry target:

Run CMake and set:

Source code: /home/user/forte/open62541
Build binaries: /home/user/forte/build/open62541/aarch64

Follow previous CMake configuration step and set:

CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/aarch64
UA_ARCHITECTURE=posix
UA_ENABLE_AMALGAMATION=ON
CMAKE_INSTALL_PREFIX=/home/user/forte/install/aarch64
UA_ENABLE_DISCOVERY=ON
UA_ENABLE_DISCOVERY_MULTICAST=ON
UA_ENABLE_ENCRYPTION=OPENSSL
OPENSSL_INCLUDE_DIR=/home/user/forte/install/aarch64/include
OPENSSL_CRYPTO_LIBRARY=/home/user/forte/install/aarch64/lib/libcrypto.so
OPENSSL_SSL_LIBRARY=/home/user/forte/install/aarch64/lib/libssl.so

Follow previous step to compile and install open62541.

For Windows target:

Run CMake and set:

Source code: /home/user/forte/open62541
Build binaries: /home/user/forte/build/open62541/x86_w64

Follow previous CMake configuration step and set:

MINGW=ON # Manually added bool entry to tell CMake we are in a MINGW environment
CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/x86_w64
UA_ARCHITECTURE=win32
UA_ENABLE_AMALGAMATION=ON
CMAKE_INSTALL_PREFIX=/home/user/forte/install/x86_w64
UA_ENABLE_DISCOVERY=ON
UA_ENABLE_DISCOVERY_MULTICAST=ON
UA_ENABLE_ENCRYPTION=OPENSSL
OPENSSL_INCLUDE_DIR=/home/user/forte/install/x86_w64/include
OPENSSL_CRYPTO_LIBRARY=/home/user/forte/install/x86_w64/lib/libcrypto.a
OPENSSL_SSL_LIBRARY=/home/user/forte/install/x86_w64/lib/libssl.a

Follow previous step to compile and install open62541.

Download and build 4diac's FORTE development branch:

We will compile a development version of FORTE and therefore require a milestone version of the IDE which can be downloaded from 4diac's milestone software repository.

$ cd ~/forte
$ git clone https://git.eclipse.org/r/4diac/org.eclipse.4diac.forte.git -b develop --depth=100
$ cd org.eclipse.4diac.forte
$ git checkout -b local # a local branch to fix a compilation error
$ sed -i '39s/include )/include\/modbus )/' src/com/modbus/CMakeLists.txt
$ sed -i '41s/libmodbus.lib ) /modbus )/' src/com/modbus/CMakeLists.txt

For Raspberry target:

Run CMake and set:

Source code: /home/user/forte/org.eclipse.4diac.forte
Build binaries: /home/user/forte/build/forte/aarch64

Follow previous CMake configuration step and set:

CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/aarch64
FORTE_ARCHITECTURE=posix
FORTE_COM_HTTP=ON
FORTE_COM_MODBUS=ON
FORTE_COM_OPC_UA=ON
FORTE_COM_PAHOMQTT=ON
FORTE_EXTERNAL_MODULES_DIRECTORY=/home/user/forte/ext_modules
FORTE_MODULE_CONVERT=ON
FORTE_MODULE_IEC61131=ON
FORTE_MODULE_RECONFIGURATION=ON
FORTE_MODULE_RT_Events=ON
FORTE_MODULE_UTILS=ON
FORTE_MODULE_SysFs=ON
FORTE_USE_LUATYPES=LuaJIT
FORTE_COM_MODBUS_LIB_DIR=/home/user/forte/install/aarch64
FORTE_COM_OPC_UA_ENCRYPTION=ON
FORTE_COM_OPC_UA_INCLUDE_DIR=/home/user/forte/install/aarch64/include
FORTE_COM_OPC_UA_LIB=libopen62541.a
FORTE_COM_OPC_UA_LIB_DIR=/home/user/forte/install/aarch64/lib
FORTE_COM_OPC_UA_MULTICAST=ON
FORTE_COM_PAHOMQTT_INCLUDE_DIR=/home/user/forte/install/aarch64/include
FORTE_COM_PAHOMQTT_LIB=libpaho-mqtt3as.a # MQTT asynchronous with SSL support
FORTE_COM_PAHOMQTT_LIB_DIR=/home/user/forte/install/aarch64/lib
FORTE_COM_SER=ON
LUAJIT_INCLUDE_DIR=/home/user/forte/install/aarch64/include/luajit-2.1
LUAJIT_LIBRARY=/home/user/forte/install/aarch64/lib/libluajit-5.1.so
FORTE_COM_OPC_UA_ENCRYPTION_MBEDTLS=OFF
FORTE_COM_OPC_UA_ENCRYPTION_INCLUDE_DIR=/home/user/forte/install/aarch64/include
FORTE_COM_OPC_UA_ENCRYPTION_LIB_DIR=/home/user/forte/install/aarch64/lib

Compile and install FORTE:

$ make -j3
$ make install
$ cd ~/forte/install/aarch64/
$ cp lib/libcrypto.so.3 lib/libssl.so.3 bin/
$ cp lib/libluajit-5.1.so.2.1.1703358377 bin/libluajit-5.1.so.2
$ aarch64-linux-gnu-strip bin/* # remove symbols and debugging information for a smaller binary size
FORTE on Raspberry Pi 4B over SSH Access

For Windows target:

Run CMake and set:

Source code: /home/user/forte/org.eclipse.4diac.forte
Build binaries: /home/user/forte/build/forte/x86_w64

Follow previous CMake configuration step and set:

MINGW=ON # Manually added bool entry to tell CMake we are in a MINGW environment
CMAKE_C_STANDARD_LIBRARIES=-lws2_32 -lcrypt32 # Manually added for libmodbus and openssl
CMAKE_CXX_STANDARD_LIBRARIES=-lws2_32 -lcrypt32 # Manually added for libmodbus and openssl
CMAKE_BUILD_TYPE=Release
CMAKE_INSTALL_PREFIX=/home/user/forte/install/x86_w64
FORTE_ARCHITECTURE=win32
FORTE_COM_HTTP=ON
FORTE_COM_MODBUS=ON
FORTE_COM_OPC_UA=ON
FORTE_COM_PAHOMQTT=ON
FORTE_EXTERNAL_MODULES_DIRECTORY=/home/user/forte/ext_modules
FORTE_MODULE_CONVERT=ON
FORTE_MODULE_IEC61131=ON
FORTE_MODULE_RECONFIGURATION=ON
FORTE_MODULE_RT_Events=ON
FORTE_MODULE_UTILS=ON
FORTE_USE_LUATYPES=LuaJIT
FORTE_COM_MODBUS_LIB_DIR=/home/user/forte/install/x86_w64
FORTE_COM_OPC_UA_ENCRYPTION=ON
FORTE_COM_OPC_UA_INCLUDE_DIR=/home/user/forte/install/x86_w64/include
FORTE_COM_OPC_UA_LIB=libopen62541.a
FORTE_COM_OPC_UA_LIB_DIR=/home/user/forte/install/x86_w64/lib
FORTE_COM_OPC_UA_MULTICAST=ON
FORTE_COM_PAHOMQTT_INCLUDE_DIR=/home/user/forte/install/x86_w64/include
FORTE_COM_PAHOMQTT_LIB=libpaho-mqtt3as.a # MQTT asynchronous with SSL support
FORTE_COM_PAHOMQTT_LIB_DIR=/home/user/forte/install/x86_w64/lib
FORTE_COM_SER=ON
LUAJIT_INCLUDE_DIR=/home/user/forte/install/x86_w64/include/luajit-2.1
LUAJIT_LIBRARY=/home/user/forte/install/x86_w64/lib/lua51.dll
FORTE_COM_OPC_UA_ENCRYPTION_MBEDTLS=OFF
FORTE_COM_OPC_UA_ENCRYPTION_INCLUDE_DIR=/home/user/forte/install/aarch64/include
FORTE_COM_OPC_UA_ENCRYPTION_LIB_DIR=/home/user/forte/install/x86_w64/lib

Compile and install FORTE:

$ make -j3
$ cp src/forte.exe $HOME/forte/install/x86_w64/bin
$ $HOME/forte/install/x86_w64/lib/lua51.dll $HOME/forte/install/x86_w64/bin
$ x86_64-w64-mingw32-strip ~/forte/install/x86_w64/bin/*

Ubuntu WSL mount WSL drive on Explorer with the famous Tux the Penguin icon. For Windows target, we can run FORTE directly from WSL drive with a double click.

FORTE Windows Native outside WSL
FORTE Linux Native inside WSL

To make it easier, here is a long and dumb bash script to build 4diac's FORTE and all it's dependencies in single shot!

Update:

I found OpenSSL not working properly yet with Open62541 OPC UA library version 1.3.9 and updated below script use Mbed-TLS as encryption support to FORTE OPC UA client. I attach some patches for FORTE to 4diac forum, please check it.
#!/bin/bash
echo "----------------------------------------------------------------------------"
echo " Build FORTE for Raspberry Pi aarch64, Windows x86_w64, or Linux x86_64"
echo "----------------------------------------------------------------------------"
echo ""
echo " Includes Modbus, OPC UA, MQTT, OpenSSL, and LuaJIT support"
echo ""
echo "----------------------------------------------------------------------------"

install_if_not_exist() {
  if dpkg -s "$1" &>/dev/null; then
    PKG_EXIST=$(dpkg -s "$1" | grep "install ok installed")
    if [[ -n "$PKG_EXIST" ]]; then
      return
    fi
  fi
  sudo apt install "$1" -y
}

#run this before execute this script
#sudo apt update -y

if [ $# -eq 0 ]; then
  arch="aarch64"
else
  arch=$1
fi

mkdir -p $HOME/toolchain/

if [ "$arch" == "x86_64" ]; then
  forte_arch="x86_64"
  forte_toolchain_dir=""
  #comment out to install gcc and g++ compiler
  #install_if_not_exist gcc-x86-64-linux-gnu
  #install_if_not_exist g++-x86-64-linux-gnu
  forte_compiler_prefix="x86_64-linux-gnu-"
  forte_cmake_ua_arch="posix"
  forte_cmake_arch="Posix"
  forte_cmake_luajit_lib="libluajit-5.1.so"
elif [ "$arch" == "x86_w64" ]; then
  forte_arch="x86_w64"
  forte_toolchain_dir="$HOME/toolchain/xpack-mingw-w64-gcc-13.2.0-1"
  # [ ! -d "$forte_toolchain_dir" ] && wget -c https://github.com/xpack-dev-tools/mingw-w64-gcc-xpack/releases/download/v13.2.0-1/xpack-mingw-w64-gcc-13.2.0-1-linux-x64.tar.gz -O $HOME/toolchain/xpack-mingw-w64-gcc-13.2.0-1-linux-x64.tar.gz
  # [ ! -d "$forte_toolchain_dir" ] && tar xvf $HOME/toolchain/xpack-mingw-w64-gcc-13.2.0-1-linux-x64.tar.gz -C $HOME/toolchain/
  forte_compiler_prefix="x86_64-w64-mingw32-"
  forte_cmake_ua_arch="win32"
  forte_cmake_arch="Win32"
  forte_cmake_extra="-DMINGW:BOOL=ON"
  forte_luajit_config="TARGET_SYS=Windows"
  forte_cmake_luajit_lib="lua51.dll"
  forte_cmake_libs="-lws2_32 -lcrypt32 -lbcrypt"
elif [ "$arch" == "aarch64" ]; then
  forte_arch="aarch64"
  forte_toolchain_dir="$HOME/toolchain/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu"
  # [ ! -d "$forte_toolchain_dir" ] && wget -c https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz -O $HOME/toolchain/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
  # [ ! -d "$forte_toolchain_dir" ] && tar xvf $HOME/toolchain/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz -C $HOME/toolchain/
  forte_compiler_prefix="aarch64-none-linux-gnu-"
  forte_cmake_ua_arch="posix"
  forte_cmake_arch="Posix"
  forte_cmake_luajit_lib="libluajit-5.1.so"
  #extra module for Raspberry
  forte_cmake_extra="-DFORTE_MODULE_SysFs=ON"
elif [ "$arch" == "aarch64-musl" ]; then
  forte_arch="aarch64-musl"
  forte_toolchain_dir="$HOME/toolchain/aarch64--musl--stable-2023.11-1"
  # [ ! -d "$forte_toolchain_dir" ] && wget -c https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--musl--stable-2023.11-1.tar.bz2
  # [ ! -d "$forte_toolchain_dir" ] && tar xvf aarch64--musl--stable-2023.11-1.tar.bz2 -C $HOME/toolchain/
  #disable musl toolchain python version to prevent mbedtls build failed
  [ -L "$forte_toolchain_dir/bin/python" ] && mv $forte_toolchain_dir/bin/python $forte_toolchain_dir/bin/python.bak
  [ -L "$forte_toolchain_dir/bin/python3" ] && mv $forte_toolchain_dir/bin/python3 $forte_toolchain_dir/bin/python3.bak
  [ -f "$forte_toolchain_dir/bin/python3.11" ] && mv $forte_toolchain_dir/bin/python3.11 $forte_toolchain_dir/bin/python3.11.bak
  [ -L "$forte_toolchain_dir/bin/python-config" ] && mv $forte_toolchain_dir/bin/python-config $forte_toolchain_dir/bin/python-config.bak
  [ -L "$forte_toolchain_dir/bin/python3-config" ] && mv $forte_toolchain_dir/bin/python3-config $forte_toolchain_dir/bin/python3-config.bak
  [ -f "$forte_toolchain_dir/bin/python3.11-config" ] && mv $forte_toolchain_dir/bin/python3.11-config $forte_toolchain_dir/bin/python3.11-config.bak
  forte_compiler_prefix="aarch64-linux-"
  forte_cmake_ua_arch="posix"
  forte_cmake_arch="Posix"
  forte_cmake_luajit_lib="libluajit-5.1.a"
  forte_cmake_extra="-DFORTE_MODULE_SysFs=ON -DMUSL:BOOL=ON"
else
  echo "!!!! Invalid argument! Please check https://blog.kiiota.com/4diacs-forte-cross-build-on-wsl/ "
  exit
fi
export PATH=$forte_toolchain_dir/bin:$PATH

forte_root_dir="$PWD"
forte_sources_dir="$forte_root_dir/sources"
forte_build_dir="$forte_root_dir/build/$forte_arch"
forte_install_dir="$forte_root_dir/install/$forte_arch"

[ ! -d "$forte_sources_dir" ] && mkdir -p "$forte_sources_dir"
[ ! -d "$forte_build_dir" ] && mkdir -p "$forte_build_dir"
[ ! -d "$forte_install_dir" ] && mkdir -p "$forte_install_dir"

echo "==== Install package dependencies..."
install_if_not_exist git
install_if_not_exist make
install_if_not_exist cmake
#automake, autoconf, libtool for libmodbus
install_if_not_exist automake
install_if_not_exist autoconf
install_if_not_exist libtool
#python3-jsonschema for mbedtls
install_if_not_exist python3-jsonschema
echo "==== Dependecies install completed"

echo "==== Download dependencies and FORTE source codes..."
cd $forte_sources_dir
if [ ! -d "libmodbus" ]; then
  echo "---- Download libmodbus source..."
  git clone https://github.com/stephane/libmodbus.git --depth=1
fi

if [ ! -d "LuaJIT" ]; then
  echo "---- Download LuaJIT source..."
  git clone https://github.com/LuaJIT/LuaJIT.git --depth=1
fi

if [ ! -d "mbedtls" ]; then
  echo "---- Download mbedtls source..."
  git clone https://github.com/Mbed-TLS/mbedtls.git --depth=1
fi

if [ ! -d "paho.mqtt.c" ]; then
  echo "---- Download paho.mqtt.c source..."
  git clone https://github.com/eclipse/paho.mqtt.c.git --depth=1
fi

if [ ! -d "open62541" ]; then
  echo "---- Download open62541 source..."
  git clone https://github.com/open62541/open62541.git -b pack/v1.3.9 --depth=1
  cd open62541
  git submodule update --init --recursive --depth 1
  cd ../
fi

if [ ! -d "org.eclipse.4diac.forte" ]; then
  echo "---- Download org.eclipse.4diac.forte source..."
  git clone https://git.eclipse.org/r/4diac/org.eclipse.4diac.forte.git -b develop --depth=1
fi
echo "==== Download source codes completed"

echo "==== Build FORTE for $forte_arch target begin..."
echo "==== Build dependencies from sources..."
cd $forte_sources_dir
#build libmodbus if static library not exists
if [ -d "libmodbus" ] && [ ! -e $forte_install_dir/lib/libmodbus.a ]; then
  echo "---- Build libmodbus from source..."
  cd libmodbus
  ./autogen.sh &>/dev/null
  ./configure --with-pic --enable-static --enable-shared=no --host=${forte_compiler_prefix:0:-1} --prefix=$forte_install_dir &>/dev/null
  make clean &>/dev/null
  make -j4 &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Build libmodbus succeeded"
  else
    echo "!!!! Build libmodbus failed!"
    exit
  fi
  make install &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Libraries install completed"
  else
    echo "!!!! Install libmodbus failed!"
    exit
  fi
  make clean &>/dev/null
fi

cd $forte_sources_dir
#build libluajit if shared library not exists
if [ -d "LuaJIT" ] && ([ ! -e $forte_install_dir/lib/libluajit-5.1.so ] && [ ! -e $forte_install_dir/lib/lua51.dll ]); then
  echo "---- Build LuaJIT from source..."
  cd LuaJIT
  make clean &>/dev/null
  make -j4 CROSS=$forte_compiler_prefix CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT $forte_luajit_config  &>/dev/null
  if [[ $? -eq 0 ]]; then
    if [ "$forte_arch" == "x86_w64" ]; then
      #special tricks for windows
      mv src/luajit.exe src/luajit
      cp src/lua51.dll $forte_install_dir/lib/
    fi
    echo "---- Build libluajit succeeded"
  else
    echo "!!!! Build libluajit failed!"
    exit
  fi
  make install CROSS=$forte_compiler_prefix- CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT PREFIX=$forte_install_dir  &>/dev/null
  if [[ $? -eq 0 ]]; then
    if [ "$forte_arch" == "x86_w64" ]; then
      mv $forte_install_dir/bin/luajit $forte_install_dir/bin/luajit.exe
    fi
    echo "---- Libraries install completed"
  else
    echo "!!!! Install libluajit failed!"
    exit
  fi
  make clean &>/dev/null
fi

cd $forte_sources_dir
CMAKE_ARGS=$(cat <<-END
  -DCMAKE_C_COMPILER:FILEPATH=${forte_compiler_prefix}gcc \
  -DCMAKE_CXX_COMPILER:FILEPATH=${forte_compiler_prefix}g++ \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_INSTALL_PREFIX=$forte_install_dir \
  -DENABLE_PROGRAMS=OFF \
  -DENABLE_TESTING=OFF \
  -DCMAKE_C_COMPILER_WORKS=ON \
  $forte_cmake_extra
END
)
if [ -d "mbedtls" ] && [ ! -e $forte_install_dir/lib/libmbedcrypto.a ]; then
  echo "---- Build libmbedcrypto, libmbedtls, libmbedx509 from source..."
  mkdir -p $forte_build_dir/mbedtls
  cd $forte_build_dir/mbedtls
  #I have to run cmake twice to make it fully applied
  cmake -G "Unix Makefiles" "-DCMAKE_C_STANDARD_LIBRARIES=$forte_cmake_libs" $CMAKE_ARGS $forte_sources_dir/mbedtls &>/dev/null
  cmake -G "Unix Makefiles" "-DCMAKE_C_STANDARD_LIBRARIES=$forte_cmake_libs" $CMAKE_ARGS $forte_sources_dir/mbedtls &>/dev/null
  make -j4 &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Build libmbedcrypto, libmbedtls, libmbedx509 succeeded"
  else
    echo "!!!! Build libmbedcrypto, libmbedtls, libmbedx509 failed!"
    exit
  fi
  make install &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Libraries install completed"
  else
    echo "!!!! Install libmbedcrypto, libmbedtls, libmbedx509 failed!"
    exit
  fi
  make clean &>/dev/null
  unset CMAKE_ARGS
fi

cd $forte_sources_dir
CMAKE_ARGS=$(cat <<-END
  -DCMAKE_C_COMPILER=${forte_compiler_prefix}gcc \
  -DCMAKE_CXX_COMPILER=${forte_compiler_prefix}g++ \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_INSTALL_PREFIX=$forte_install_dir \
  -DPAHO_BUILD_SHARED=OFF \
  -DPAHO_BUILD_STATIC=ON \
  -DPAHO_ENABLE_TESTING=OFF \
  -DPAHO_HIGH_PERFORMANCE=TRUE \
  -DPAHO_WITH_SSL=OFF \
  -DOPENSSL_INCLUDE_DIR=$forte_install_dir/include \
  -DOPENSSL_ROOT_DIR=$forte_install_dir \
  -DCMAKE_C_COMPILER_WORKS=ON \
  $forte_cmake_extra
END
)
if [ -d "paho.mqtt.c" ] && [ ! -e $forte_install_dir/lib/libpaho-mqtt3a.a ]; then
  echo "---- Build libpaho-mqtt from source..."
  mkdir -p $forte_build_dir/paho.mqtt.c
  cd $forte_build_dir/paho.mqtt.c
  #I have to run cmake twice to make it fully applied
  cmake -G "Unix Makefiles" $CMAKE_ARGS $forte_sources_dir/paho.mqtt.c &>/dev/null
  cmake -G "Unix Makefiles" $CMAKE_ARGS $forte_sources_dir/paho.mqtt.c &>/dev/null
  make -j4 &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Build libpaho-mqtt succeeded"
  else
    echo "!!!! Build libpaho-mqtt failed!"
    exit
  fi
  make install &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Libraries install completed"
  else
    echo "!!!! Install libpaho-mqtt failed!"
    exit
  fi
  make clean &>/dev/null
  unset CMAKE_ARGS
fi

cd $forte_sources_dir
CMAKE_ARGS=$(cat <<-END
  -DCMAKE_C_COMPILER=${forte_compiler_prefix}gcc \
  -DCMAKE_CXX_COMPILER=${forte_compiler_prefix}g++ \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_INSTALL_PREFIX=$forte_install_dir \
  -DUA_ARCHITECTURE=$forte_cmake_ua_arch \
  -DUA_ENABLE_AMALGAMATION=ON \
  -DUA_ENABLE_DISCOVERY=ON \
  -DUA_ENABLE_DISCOVERY_MULTICAST=ON \
  -DUA_ENABLE_ENCRYPTION=MBEDTLS \
  -DMBEDTLS_INCLUDE_DIR=$forte_install_dir/include \
  -DMBEDCRYPTO_LIBRARY=$forte_install_dir/lib/libmbedcrypto.a \
  -DMBEDTLS_LIBRARY=$forte_install_dir/lib/libmbedtls.a \
  -DMBEDX509_LIBRARY=$forte_install_dir/lib/libmbedx509.a \
  -DCMAKE_C_COMPILER_WORKS=ON \
  $forte_cmake_extra
END
)
if [ -d "open62541" ] && [ ! -e $forte_install_dir/lib/libopen62541.a ]; then
  echo "---- Build libopen62541 from source..."
  mkdir -p $forte_build_dir/open62541
  cd $forte_build_dir/open62541
  #I have to run cmake twice to make it fully applied
  cmake -G "Unix Makefiles" $CMAKE_ARGS "-DCMAKE_C_FLAGS_MINSIZEREL:STRING=-Wno-error -Os -DNDEBUG" $forte_sources_dir/open62541 &>/dev/null
  cmake -G "Unix Makefiles" $CMAKE_ARGS "-DCMAKE_C_FLAGS_MINSIZEREL:STRING=-Wno-error -Os -DNDEBUG" $forte_sources_dir/open62541 &>/dev/null
  make -j4 &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Build libopen62541 succeeded"
  else
    echo "!!!! Build libopen62541 failed!"
    exit
  fi
  make install &>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "---- Libraries installed in $forte_install_dir"
  else
    echo "!!!! Install libopen62541 failed!"
    exit
  fi
  make clean &>/dev/null
  unset CMAKE_ARGS
fi
echo "==== Dependencies build completed"

echo "==== Build 4diac's FORTE from sources..."
cd $forte_sources_dir
CMAKE_ARGS=$(cat <<-END
  -DCMAKE_C_COMPILER=${forte_compiler_prefix}gcc \
  -DCMAKE_CXX_COMPILER=${forte_compiler_prefix}g++ \
  -DCMAKE_BUILD_TYPE=MinSizeRel \
  -DCMAKE_INSTALL_PREFIX=$forte_install_dir \
  -DFORTE_ARCHITECTURE=$forte_cmake_arch \
  -DFORTE_COM_HTTP=ON \
  -DFORTE_COM_SER=ON \
  -DFORTE_COM_MODBUS=ON \
  -DFORTE_COM_MODBUS_LIB_DIR=$forte_install_dir \
  -DFORTE_COM_OPC_UA=ON \
  -DFORTE_COM_OPC_UA_ENCRYPTION=ON \
  -DFORTE_COM_OPC_UA_INCLUDE_DIR=$forte_install_dir/include \
  -DFORTE_COM_OPC_UA_LIB=libopen62541.a \
  -DFORTE_COM_OPC_UA_LIB_DIR=$forte_install_dir/lib \
  -DFORTE_COM_OPC_UA_MULTICAST=ON \
  -DFORTE_COM_PAHOMQTT=ON \
  -DFORTE_COM_PAHOMQTT_INCLUDE_DIR=$forte_install_dir/include \
  -DFORTE_COM_PAHOMQTT_LIB=libpaho-mqtt3a.a \
  -DFORTE_COM_PAHOMQTT_LIB_DIR=$forte_install_dir/lib \
  -DFORTE_EXTERNAL_MODULES_DIRECTORY=$forte_root_dir/ext_modules \
  -DFORTE_MODULE_CONVERT=ON \
  -DFORTE_MODULE_IEC61131=ON \
  -DFORTE_MODULE_RECONFIGURATION=ON \
  -DFORTE_MODULE_RT_Events=ON \
  -DFORTE_MODULE_UTILS=ON \
  -DFORTE_MODULE_KUMAJAYA=ON \
  -DFORTE_USE_LUATYPES=LuaJIT \
  -DLUAJIT_INCLUDE_DIR=$forte_install_dir/include/luajit-2.1 \
  -DLUAJIT_LIBRARY=$forte_install_dir/lib/$forte_cmake_luajit_lib \
  -DFORTE_COM_OPC_UA_ENCRYPTION_MBEDTLS=ON \
  -DFORTE_COM_OPC_UA_ENCRYPTION_INCLUDE_DIR=$forte_install_dir/include \
  -DFORTE_COM_OPC_UA_ENCRYPTION_LIB_DIR=$forte_install_dir/lib \
  -DFORTE_IPLayerRecvBufferSize=25000 \
  -DFORTE_TESTS=OFF \
  $forte_cmake_extra
END
)
#let forte build multiple time
if [ -d "org.eclipse.4diac.forte" ]; then
  echo "---- Build FORTE from source..."
  mkdir -p $forte_build_dir/org.eclipse.4diac.forte
  cd $forte_build_dir/org.eclipse.4diac.forte
  #I have to run cmake twice to make it fully applied
  cmake -G "Unix Makefiles" $CMAKE_ARGS "-DCMAKE_CXX_STANDARD_LIBRARIES:STRING=$forte_cmake_libs" $forte_sources_dir/org.eclipse.4diac.forte &>/dev/null
  cmake -G "Unix Makefiles" $CMAKE_ARGS "-DCMAKE_CXX_STANDARD_LIBRARIES:STRING=$forte_cmake_libs" $forte_sources_dir/org.eclipse.4diac.forte
  make -j4
  if [[ $? -eq 0 ]]; then
    if [ "$forte_arch" == "x86_w64" ]; then
      #special tricks for windows
      [ -f "src/CMakeFiles/CMakeRelink.dir/forte.exe" ] && mv src/CMakeFiles/CMakeRelink.dir/forte.exe src/CMakeFiles/CMakeRelink.dir/forte
    fi
    echo "---- Build forte succeeded"
  else
    echo "!!!! Build forte failed!"
    exit
  fi
  make install
  if [[ $? -eq 0 ]]; then
    ${forte_compiler_prefix}strip $forte_install_dir/bin/forte
    if [ "$forte_arch" == "x86_w64" ]; then
      mv $forte_install_dir/bin/forte $forte_install_dir/bin/forte.exe
      #copy the only library needed by forte
      cp $forte_install_dir/lib/lua51.dll $forte_install_dir/bin/
      [ -f "src/CMakeFiles/CMakeRelink.dir/forte" ] && mv src/CMakeFiles/CMakeRelink.dir/forte src/CMakeFiles/CMakeRelink.dir/forte.exe
    fi
    echo "---- Binary installed in $forte_install_dir"
  else
    echo "!!!! Install forte failed!"
    echo "!!!! Try run the script once again."
    exit
  fi
fi
echo "==== Build 4diac's FORTE completed"
echo "==== Build 4diac's FORTE for $forte_arch end"