From b1183ad5f2b628dc3e47dc7a0a60d735d2c4a06b Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 27 Jun 2024 15:01:47 +0200 Subject: [PATCH 1/7] Adding cmakefiles that allows to have crosscompilation possible for an example Signed-off-by: Omar Shrit --- .../CMake/Autodownload.cmake | 49 ++++++++++ .../CMake/ConfigureCrossCompile.cmake | 45 +++++++++ embedded/mlpack_embedded_cmake/CMakeLists.txt | 79 +++++++++++++++ embedded/mlpack_embedded_cmake/README.md | 18 ++++ .../board/crosscompile-toolchain.cmake | 40 ++++++++ .../board/flags-config.cmake | 95 +++++++++++++++++++ 6 files changed, 326 insertions(+) create mode 100644 embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake create mode 100644 embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake create mode 100644 embedded/mlpack_embedded_cmake/CMakeLists.txt create mode 100644 embedded/mlpack_embedded_cmake/README.md create mode 100644 embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake create mode 100644 embedded/mlpack_embedded_cmake/board/flags-config.cmake diff --git a/embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake b/embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake new file mode 100644 index 00000000..af78d624 --- /dev/null +++ b/embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake @@ -0,0 +1,49 @@ +## This function auto-downloads mlpack dependencies. +## You need to pass the LINK to download from, the name of +## the dependency, and the name of the compressed package such as +## armadillo.tar.gz +## At each download, this module sets a GENERIC_INCLUDE_DIR path, +## which means that you need to set the main path for the include +## directories for each package. +## Note that, the package should be compressed only as .tar.gz + +macro(get_deps LINK DEPS_NAME PACKAGE) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/${PACKAGE}") + file(DOWNLOAD ${LINK} + "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + STATUS DOWNLOAD_STATUS_LIST LOG DOWNLOAD_LOG + SHOW_PROGRESS) + list(GET DOWNLOAD_STATUS_LIST 0 DOWNLOAD_STATUS) + if (DOWNLOAD_STATUS EQUAL 0) + execute_process(COMMAND ${CMAKE_COMMAND} -E + tar xf "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/") + else () + list(GET DOWNLOAD_STATUS_LIST 1 DOWNLOAD_ERROR) + message(FATAL_ERROR + "Could not download ${DEPS_NAME}! Error code ${DOWNLOAD_STATUS}: ${DOWNLOAD_ERROR}! Error log: ${DOWNLOAD_LOG}") + endif() + endif() + # Get the name of the directory. + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}*.*") + if(${DEPS_NAME} MATCHES "stb") + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}") + endif() + # list(FILTER) is not available on 3.5 or older, but try to keep + # configuring without filtering the list anyway + # (it works only if the file is present as .tar.gz). + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0") + list(FILTER DIRECTORIES EXCLUDE REGEX ".*\.tar\.gz") + endif () + list(LENGTH DIRECTORIES DIRECTORIES_LEN) + if (DIRECTORIES_LEN GREATER 0) + list(GET DIRECTORIES 0 DEPENDENCY_DIR) + set(GENERIC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/deps/${DEPENDENCY_DIR}/include") + install(DIRECTORY "${GENERIC_INCLUDE_DIR}/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + else () + message(FATAL_ERROR + "Problem unpacking ${DEPS_NAME}! Expected only one directory ${DEPS_NAME};. Try to remove the directory ${CMAKE_BINARY_DIR}/deps and reconfigure.") + endif () +endmacro() diff --git a/embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake b/embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake new file mode 100644 index 00000000..0a39b829 --- /dev/null +++ b/embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake @@ -0,0 +1,45 @@ +# This file adds the necessary configurations to cross compile +# mlpack for embedded systems. You need to set the following variables +# from the command line: CMAKE_SYSROOT and TOOLCHAIN_PREFIX. +# This file will compile OpenBLAS if it is downloaded and it is not +# available on your system in order to find the BLAS library. If OpenBLAS will +# be compiled, the OPENBLAS_TARGET variable must be set. This can be done +# by, e.g., setting BOARD_NAME (which will set OPENBLAS_TARGET in +# `board/flags-config.cmake`). + +if (CMAKE_CROSSCOMPILING) + include(board/flags-config.cmake) + if (NOT CMAKE_SYSROOT AND (NOT TOOLCHAIN_PREFIX)) + message(FATAL_ERROR "Neither CMAKE_SYSROOT nor TOOLCHAIN_PREFIX are set; please set both of them and try again.") + elseif(NOT CMAKE_SYSROOT) + message(FATAL_ERROR "Cannot configure: CMAKE_SYSROOT must be set when performing cross-compiling!") + elseif(NOT TOOLCHAIN_PREFIX) + message(FATAL_ERROR "Cannot configure: TOOLCHAIN_PREFIX must be set when performing cross-compiling!") + endif() +endif() + +macro(search_openblas version) + set(BLA_STATIC ON) + find_package(BLAS) + if (NOT BLAS_FOUND OR (NOT BLAS_LIBRARIES)) + if(NOT OPENBLAS_TARGET) + message(FATAL_ERROR "Cannot compile OpenBLAS: OPENBLAS_TARGET is not set. Either set that variable, or set BOARD_NAME correctly!") + endif() + get_deps(https://github.com/xianyi/OpenBLAS/releases/download/v${version}/OpenBLAS-${version}.tar.gz OpenBLAS OpenBLAS-${version}.tar.gz) + if (NOT MSVC) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + set(ENV{COMMON_OPT} "${CMAKE_OPENBLAS_FLAGS}") # Pass our flags to OpenBLAS + execute_process(COMMAND make TARGET=${OPENBLAS_TARGET} BINARY=${OPENBLAS_BINARY} HOSTCC=gcc CC=${CMAKE_C_COMPILER} FC=${CMAKE_FORTRAN_COMPILER} NO_SHARED=1 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}) + endif() + file(GLOB OPENBLAS_LIBRARIES "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + set(BLAS_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(LAPACK_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(BLA_VENDOR OpenBLAS) + set(BLAS_FOUND ON) + endif() + endif() + find_library(GFORTRAN NAMES libgfortran.a) + find_library(PTHREAD NAMES libpthread.a) + set(CROSS_COMPILE_SUPPORT_LIBRARIES ${GFORTRAN} ${PTHREAD}) +endmacro() diff --git a/embedded/mlpack_embedded_cmake/CMakeLists.txt b/embedded/mlpack_embedded_cmake/CMakeLists.txt new file mode 100644 index 00000000..351af6bf --- /dev/null +++ b/embedded/mlpack_embedded_cmake/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 3.6) +project(main) + +include(CMake/Autodownload.cmake) +include(CMake/ConfigureCrossCompile.cmake) + +option(USE_OPENMP "If available, use OpenMP for parallelization." ON) + +# Set required standard to C++17. +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# If we're using gcc, then we need to link against pthreads to use std::thread, +# which we do in the tests. +if (CMAKE_COMPILER_IS_GNUCC) + find_package(Threads) + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +endif() + +search_openblas(0.3.26) + +get_deps(https://files.mlpack.org/armadillo-12.6.5.tar.gz armadillo armadillo-12.6.5.tar.gz) +set(ARMADILLO_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +find_package(Armadillo REQUIRED) +# Include directories for the previous dependencies. +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}) +set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES}) + +# Find stb_image.h and stb_image_write.h. +get_deps(https://mlpack.org/files/stb.tar.gz stb stb.tar.gz) +set(STB_IMAGE_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${STB_IMAGE_INCLUDE_DIR}") + +# Find ensmallen. +get_deps(https://www.ensmallen.org/files/ensmallen-latest.tar.gz ensmallen ensmallen-latest.tar.gz) +set(ENSMALLEN_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${ENSMALLEN_INCLUDE_DIR}") + +# Find cereal. +get_deps(https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.0.tar.gz cereal cereal-1.3.0.tar.gz) +set(CEREAL_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR}) + +# Detect OpenMP support in a compiler. If the compiler supports OpenMP, flags +# to compile with OpenMP are returned and added. Note that MSVC does not +# support a new-enough version of OpenMP to be useful. +if (USE_OPENMP) + find_package(OpenMP) +endif () + +if (OpenMP_FOUND AND OpenMP_CXX_VERSION VERSION_GREATER_EQUAL 3.0.0) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES}) +else () + # Disable warnings for all the unknown OpenMP pragmas. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") + set(OpenMP_CXX_FLAGS "") +endif () + +include_directories(BEFORE ${MLPACK_INCLUDE_DIRS}) +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src/) + +# Finally, add any cross-compilation support libraries (they may need to come +# last). If we are not cross-compiling, no changes will happen here. +set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${CROSS_COMPILE_SUPPORT_LIBRARIES}) + +add_executable(main main.cpp ${SOURCES_FILES}) +target_sources(main PRIVATE ${SOURCE_FILES}) + +target_include_directories(main PRIVATE + ${MLPACK_INCLUDE_DIRS} + /meta/mlpack/src/ +) + +target_link_libraries(main PRIVATE -static + ${MLPACK_LIBRARIES} +) + diff --git a/embedded/mlpack_embedded_cmake/README.md b/embedded/mlpack_embedded_cmake/README.md new file mode 100644 index 00000000..43185dc9 --- /dev/null +++ b/embedded/mlpack_embedded_cmake/README.md @@ -0,0 +1,18 @@ +## CMake files for mlpack + +This is a set of CMakefiles that autodowload all the mlpack dependencies. The +objective of this example is to provide the minimum configurations that allow +to build an mlpack application with in the objective of embedded system. + +These files contains the necessary cmake files that are ncessary in the +embedded context, especially the cross compilation step, and build a +statically linked binary, but this is not necessary as well since you +can use these configs to build any mlpack application for your machine as well. + +The main CMakeLists.txt assumes that the project name is `main` and that you +have a file that is called `main.cpp` that contains the mlpack C++ code you are +trying to compile. Feel free to modify these the way it suits you. + +If you are looking to integrate these CMakeFiles into your project, feel free +to modify them the way you want. The point of these files to provide a simple +working example and to keep things simple diff --git a/embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake b/embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake new file mode 100644 index 00000000..2b586e11 --- /dev/null +++ b/embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake @@ -0,0 +1,40 @@ +## This file handles cross-compilation configurations for aarch64, +## known as arm64. The objective of this file is to find and assign +## cross-compiler and the entire toolchain. +## +## This configuration works best with the buildroot toolchain. When using this +## file, be sure to set the TOOLCHAIN_PREFIX and CMAKE_SYSROOT variables, +## preferably via the CMake configuration command (e.g. `-DCMAKE_SYSROOT=<...>`). +## +## Currently, we recommend using buildroot toolchain for +## cross-compilation. Here is the link to download the toolchains: +## https://toolchains.bootlin.com/ + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSROOT) +set(TOOLCHAIN_PREFIX "" CACHE STRING "Path for toolchain for cross compiler and other compilation tools.") + +# Ensure that CMake tries to build static libraries when testing the compiler. +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_AR "${TOOLCHAIN_PREFIX}gcc-ar" CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld) +set(CMAKE_C_ARCHIVE_CREATE " qcs ") +set(CMAKE_C_ARCHIVE_FINISH true) +set(CMAKE_FORTRAN_COMPILER ${TOOLCHAIN_PREFIX}gfortran) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool") +set(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool") + +## Here are the standard ROOT_PATH if you are using the standard toolchain +## if you are using a different toolchain you have to specify that too. +set(CMAKE_FIND_ROOT_PATH "${CMAKE_SYSROOT}") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=${CMAKE_SYSROOT}" CACHE INTERNAL "" FORCE) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/embedded/mlpack_embedded_cmake/board/flags-config.cmake b/embedded/mlpack_embedded_cmake/board/flags-config.cmake new file mode 100644 index 00000000..0f661805 --- /dev/null +++ b/embedded/mlpack_embedded_cmake/board/flags-config.cmake @@ -0,0 +1,95 @@ +# This function provides a set of specific flags for each supported board +# depending on the processor type. The objective is to optimize for size. +# Thus, all of the following flags are chosen carefully to reduce binary +# footprints. + +# Set generic minimization flags for all platforms. +# These flags are the same for all cross-compilation cases and they are +# mainly to reduce the binary footprint. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s -fdata-sections -ffunction-sections") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer -fno-unwind-tables") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-asynchronous-unwind-tables -fvisibility=hidden") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fshort-enums -finline-small-functions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -findirect-inlining -fno-common") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmerge-all-constants -fno-ident") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unroll-loops -fno-math-errno") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector") +set(CMAKE_OPENBLAS_FLAGS "${CMAKE_CXX_FLAGS}") # OpenBLAS does not supoport flto +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--hash-style=gnu -Wl,--build-id=none") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,norelro") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +## Keep the following flag in comment, it will be relevant in the case of MCU's +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-nmagic,-Bsymbolic -nostartfiles") + +set(BOARD_NAME "" CACHE STRING "Specify Board name to optimize for.") +string(TOUPPER ${BOARD_NAME} BOARD) + +# Set specific platforms CMAKE CXX flags. +if(BOARD MATCHES "RPI0" OR BOARD MATCHES "RPI1" OR BOARD MATCHES "ARM11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm1176jzf-s") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp") + set(OPENBLAS_TARGET "ARMV6") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI2" OR BOARD MATCHES "CORTEXA7") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a7") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon-vfpv4") + set(OPENBLAS_TARGET "ARMV7") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "ARMV7") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA9") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a9") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "CORTEXA9") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA15") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a15") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "CORTEXA15") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI3" OR BOARD MATCHES "CORTEXA53") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a53 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA53") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "RPI4" OR BOARD MATCHES "CORTEXA72") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA72") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "JETSONAGX" OR BOARD MATCHES "CORTEXA76") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a76 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA76") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "BV") + set(OPENBLAS_TARGET "RISCV64_GENERIC") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "C906") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=thead-c906") + set(OPENBLAS_TARGET "RISCV64_GENERIC") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "x280") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=sifive-x280") + set(OPENBLAS_TARGET "x280") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "KATAMI") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(OPENBLAS_TARGET "KATAMI") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "COPPERMINE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(OPENBLAS_TARGET "COPPERMINE") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "NORTHWOOD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4") + set(OPENBLAS_TARGET "NORTHWOOD") + set(OPENBLAS_BINARY "32") +elseif(BOARD) + ## TODO: update documentation with a list of the supported boards. + message(FATAL_ERROR "Given BOARD_NAME is not known; please choose a supported board from the list") +endif() From 2d320b4d1969ea62daa34fa8a91b9e6b9f7f8896 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 27 Jun 2024 15:04:12 +0200 Subject: [PATCH 2/7] Adding random forest example Signed-off-by: Omar Shrit --- .../CMake/Autodownload.cmake | 49 ++++++++++ .../CMake/ConfigureCrossCompile.cmake | 45 +++++++++ .../crosscompile_random_forest/CMakeLists.txt | 79 +++++++++++++++ .../board/crosscompile-toolchain.cmake | 40 ++++++++ .../board/flags-config.cmake | 95 +++++++++++++++++++ embedded/crosscompile_random_forest/main.cpp | 35 +++++++ 6 files changed, 343 insertions(+) create mode 100644 embedded/crosscompile_random_forest/CMake/Autodownload.cmake create mode 100644 embedded/crosscompile_random_forest/CMake/ConfigureCrossCompile.cmake create mode 100644 embedded/crosscompile_random_forest/CMakeLists.txt create mode 100644 embedded/crosscompile_random_forest/board/crosscompile-toolchain.cmake create mode 100644 embedded/crosscompile_random_forest/board/flags-config.cmake create mode 100644 embedded/crosscompile_random_forest/main.cpp diff --git a/embedded/crosscompile_random_forest/CMake/Autodownload.cmake b/embedded/crosscompile_random_forest/CMake/Autodownload.cmake new file mode 100644 index 00000000..af78d624 --- /dev/null +++ b/embedded/crosscompile_random_forest/CMake/Autodownload.cmake @@ -0,0 +1,49 @@ +## This function auto-downloads mlpack dependencies. +## You need to pass the LINK to download from, the name of +## the dependency, and the name of the compressed package such as +## armadillo.tar.gz +## At each download, this module sets a GENERIC_INCLUDE_DIR path, +## which means that you need to set the main path for the include +## directories for each package. +## Note that, the package should be compressed only as .tar.gz + +macro(get_deps LINK DEPS_NAME PACKAGE) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/${PACKAGE}") + file(DOWNLOAD ${LINK} + "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + STATUS DOWNLOAD_STATUS_LIST LOG DOWNLOAD_LOG + SHOW_PROGRESS) + list(GET DOWNLOAD_STATUS_LIST 0 DOWNLOAD_STATUS) + if (DOWNLOAD_STATUS EQUAL 0) + execute_process(COMMAND ${CMAKE_COMMAND} -E + tar xf "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/") + else () + list(GET DOWNLOAD_STATUS_LIST 1 DOWNLOAD_ERROR) + message(FATAL_ERROR + "Could not download ${DEPS_NAME}! Error code ${DOWNLOAD_STATUS}: ${DOWNLOAD_ERROR}! Error log: ${DOWNLOAD_LOG}") + endif() + endif() + # Get the name of the directory. + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}*.*") + if(${DEPS_NAME} MATCHES "stb") + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}") + endif() + # list(FILTER) is not available on 3.5 or older, but try to keep + # configuring without filtering the list anyway + # (it works only if the file is present as .tar.gz). + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0") + list(FILTER DIRECTORIES EXCLUDE REGEX ".*\.tar\.gz") + endif () + list(LENGTH DIRECTORIES DIRECTORIES_LEN) + if (DIRECTORIES_LEN GREATER 0) + list(GET DIRECTORIES 0 DEPENDENCY_DIR) + set(GENERIC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/deps/${DEPENDENCY_DIR}/include") + install(DIRECTORY "${GENERIC_INCLUDE_DIR}/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + else () + message(FATAL_ERROR + "Problem unpacking ${DEPS_NAME}! Expected only one directory ${DEPS_NAME};. Try to remove the directory ${CMAKE_BINARY_DIR}/deps and reconfigure.") + endif () +endmacro() diff --git a/embedded/crosscompile_random_forest/CMake/ConfigureCrossCompile.cmake b/embedded/crosscompile_random_forest/CMake/ConfigureCrossCompile.cmake new file mode 100644 index 00000000..0a39b829 --- /dev/null +++ b/embedded/crosscompile_random_forest/CMake/ConfigureCrossCompile.cmake @@ -0,0 +1,45 @@ +# This file adds the necessary configurations to cross compile +# mlpack for embedded systems. You need to set the following variables +# from the command line: CMAKE_SYSROOT and TOOLCHAIN_PREFIX. +# This file will compile OpenBLAS if it is downloaded and it is not +# available on your system in order to find the BLAS library. If OpenBLAS will +# be compiled, the OPENBLAS_TARGET variable must be set. This can be done +# by, e.g., setting BOARD_NAME (which will set OPENBLAS_TARGET in +# `board/flags-config.cmake`). + +if (CMAKE_CROSSCOMPILING) + include(board/flags-config.cmake) + if (NOT CMAKE_SYSROOT AND (NOT TOOLCHAIN_PREFIX)) + message(FATAL_ERROR "Neither CMAKE_SYSROOT nor TOOLCHAIN_PREFIX are set; please set both of them and try again.") + elseif(NOT CMAKE_SYSROOT) + message(FATAL_ERROR "Cannot configure: CMAKE_SYSROOT must be set when performing cross-compiling!") + elseif(NOT TOOLCHAIN_PREFIX) + message(FATAL_ERROR "Cannot configure: TOOLCHAIN_PREFIX must be set when performing cross-compiling!") + endif() +endif() + +macro(search_openblas version) + set(BLA_STATIC ON) + find_package(BLAS) + if (NOT BLAS_FOUND OR (NOT BLAS_LIBRARIES)) + if(NOT OPENBLAS_TARGET) + message(FATAL_ERROR "Cannot compile OpenBLAS: OPENBLAS_TARGET is not set. Either set that variable, or set BOARD_NAME correctly!") + endif() + get_deps(https://github.com/xianyi/OpenBLAS/releases/download/v${version}/OpenBLAS-${version}.tar.gz OpenBLAS OpenBLAS-${version}.tar.gz) + if (NOT MSVC) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + set(ENV{COMMON_OPT} "${CMAKE_OPENBLAS_FLAGS}") # Pass our flags to OpenBLAS + execute_process(COMMAND make TARGET=${OPENBLAS_TARGET} BINARY=${OPENBLAS_BINARY} HOSTCC=gcc CC=${CMAKE_C_COMPILER} FC=${CMAKE_FORTRAN_COMPILER} NO_SHARED=1 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}) + endif() + file(GLOB OPENBLAS_LIBRARIES "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + set(BLAS_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(LAPACK_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(BLA_VENDOR OpenBLAS) + set(BLAS_FOUND ON) + endif() + endif() + find_library(GFORTRAN NAMES libgfortran.a) + find_library(PTHREAD NAMES libpthread.a) + set(CROSS_COMPILE_SUPPORT_LIBRARIES ${GFORTRAN} ${PTHREAD}) +endmacro() diff --git a/embedded/crosscompile_random_forest/CMakeLists.txt b/embedded/crosscompile_random_forest/CMakeLists.txt new file mode 100644 index 00000000..ccc5f0b6 --- /dev/null +++ b/embedded/crosscompile_random_forest/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 3.6) +project(RandomForest) + +include(CMake/Autodownload.cmake) +include(CMake/ConfigureCrossCompile.cmake) + +option(USE_OPENMP "If available, use OpenMP for parallelization." ON) + +# Set required standard to C++17. +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# If we're using gcc, then we need to link against pthreads to use std::thread, +# which we do in the tests. +if (CMAKE_COMPILER_IS_GNUCC) + find_package(Threads) + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +endif() + +search_openblas(0.3.26) + +get_deps(https://files.mlpack.org/armadillo-12.6.5.tar.gz armadillo armadillo-12.6.5.tar.gz) +set(ARMADILLO_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +find_package(Armadillo REQUIRED) +# Include directories for the previous dependencies. +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}) +set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES}) + +# Find stb_image.h and stb_image_write.h. +get_deps(https://mlpack.org/files/stb.tar.gz stb stb.tar.gz) +set(STB_IMAGE_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${STB_IMAGE_INCLUDE_DIR}") + +# Find ensmallen. +get_deps(https://www.ensmallen.org/files/ensmallen-latest.tar.gz ensmallen ensmallen-latest.tar.gz) +set(ENSMALLEN_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${ENSMALLEN_INCLUDE_DIR}") + +# Find cereal. +get_deps(https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.0.tar.gz cereal cereal-1.3.0.tar.gz) +set(CEREAL_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR}) + +# Detect OpenMP support in a compiler. If the compiler supports OpenMP, flags +# to compile with OpenMP are returned and added. Note that MSVC does not +# support a new-enough version of OpenMP to be useful. +if (USE_OPENMP) + find_package(OpenMP) +endif () + +if (OpenMP_FOUND AND OpenMP_CXX_VERSION VERSION_GREATER_EQUAL 3.0.0) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES}) +else () + # Disable warnings for all the unknown OpenMP pragmas. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") + set(OpenMP_CXX_FLAGS "") +endif () + +include_directories(BEFORE ${MLPACK_INCLUDE_DIRS}) +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src/) + +# Finally, add any cross-compilation support libraries (they may need to come +# last). If we are not cross-compiling, no changes will happen here. +set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${CROSS_COMPILE_SUPPORT_LIBRARIES}) + +add_executable(RandomForest main.cpp ${SOURCES_FILES}) +target_sources(RandomForest PRIVATE ${SOURCE_FILES}) + +target_include_directories(RandomForest PRIVATE + ${MLPACK_INCLUDE_DIRS} + /meta/mlpack/src/ +) + +target_link_libraries(RandomForest PRIVATE -static + ${MLPACK_LIBRARIES} +) + diff --git a/embedded/crosscompile_random_forest/board/crosscompile-toolchain.cmake b/embedded/crosscompile_random_forest/board/crosscompile-toolchain.cmake new file mode 100644 index 00000000..2b586e11 --- /dev/null +++ b/embedded/crosscompile_random_forest/board/crosscompile-toolchain.cmake @@ -0,0 +1,40 @@ +## This file handles cross-compilation configurations for aarch64, +## known as arm64. The objective of this file is to find and assign +## cross-compiler and the entire toolchain. +## +## This configuration works best with the buildroot toolchain. When using this +## file, be sure to set the TOOLCHAIN_PREFIX and CMAKE_SYSROOT variables, +## preferably via the CMake configuration command (e.g. `-DCMAKE_SYSROOT=<...>`). +## +## Currently, we recommend using buildroot toolchain for +## cross-compilation. Here is the link to download the toolchains: +## https://toolchains.bootlin.com/ + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSROOT) +set(TOOLCHAIN_PREFIX "" CACHE STRING "Path for toolchain for cross compiler and other compilation tools.") + +# Ensure that CMake tries to build static libraries when testing the compiler. +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_AR "${TOOLCHAIN_PREFIX}gcc-ar" CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld) +set(CMAKE_C_ARCHIVE_CREATE " qcs ") +set(CMAKE_C_ARCHIVE_FINISH true) +set(CMAKE_FORTRAN_COMPILER ${TOOLCHAIN_PREFIX}gfortran) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool") +set(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool") + +## Here are the standard ROOT_PATH if you are using the standard toolchain +## if you are using a different toolchain you have to specify that too. +set(CMAKE_FIND_ROOT_PATH "${CMAKE_SYSROOT}") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=${CMAKE_SYSROOT}" CACHE INTERNAL "" FORCE) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/embedded/crosscompile_random_forest/board/flags-config.cmake b/embedded/crosscompile_random_forest/board/flags-config.cmake new file mode 100644 index 00000000..0f661805 --- /dev/null +++ b/embedded/crosscompile_random_forest/board/flags-config.cmake @@ -0,0 +1,95 @@ +# This function provides a set of specific flags for each supported board +# depending on the processor type. The objective is to optimize for size. +# Thus, all of the following flags are chosen carefully to reduce binary +# footprints. + +# Set generic minimization flags for all platforms. +# These flags are the same for all cross-compilation cases and they are +# mainly to reduce the binary footprint. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s -fdata-sections -ffunction-sections") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer -fno-unwind-tables") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-asynchronous-unwind-tables -fvisibility=hidden") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fshort-enums -finline-small-functions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -findirect-inlining -fno-common") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmerge-all-constants -fno-ident") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unroll-loops -fno-math-errno") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector") +set(CMAKE_OPENBLAS_FLAGS "${CMAKE_CXX_FLAGS}") # OpenBLAS does not supoport flto +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--hash-style=gnu -Wl,--build-id=none") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,norelro") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +## Keep the following flag in comment, it will be relevant in the case of MCU's +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-nmagic,-Bsymbolic -nostartfiles") + +set(BOARD_NAME "" CACHE STRING "Specify Board name to optimize for.") +string(TOUPPER ${BOARD_NAME} BOARD) + +# Set specific platforms CMAKE CXX flags. +if(BOARD MATCHES "RPI0" OR BOARD MATCHES "RPI1" OR BOARD MATCHES "ARM11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm1176jzf-s") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp") + set(OPENBLAS_TARGET "ARMV6") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI2" OR BOARD MATCHES "CORTEXA7") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a7") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon-vfpv4") + set(OPENBLAS_TARGET "ARMV7") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "ARMV7") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA9") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a9") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "CORTEXA9") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "CORTEXA15") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a15") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(OPENBLAS_TARGET "CORTEXA15") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI3" OR BOARD MATCHES "CORTEXA53") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a53 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA53") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "RPI4" OR BOARD MATCHES "CORTEXA72") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA72") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "JETSONAGX" OR BOARD MATCHES "CORTEXA76") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a76 -mfloat-abi=hard") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp-armv8 -mneon-for-64bit") + set(OPENBLAS_TARGET "CORTEXA76") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "BV") + set(OPENBLAS_TARGET "RISCV64_GENERIC") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "C906") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=thead-c906") + set(OPENBLAS_TARGET "RISCV64_GENERIC") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "x280") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=sifive-x280") + set(OPENBLAS_TARGET "x280") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "KATAMI") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(OPENBLAS_TARGET "KATAMI") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "COPPERMINE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(OPENBLAS_TARGET "COPPERMINE") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "NORTHWOOD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4") + set(OPENBLAS_TARGET "NORTHWOOD") + set(OPENBLAS_BINARY "32") +elseif(BOARD) + ## TODO: update documentation with a list of the supported boards. + message(FATAL_ERROR "Given BOARD_NAME is not known; please choose a supported board from the list") +endif() diff --git a/embedded/crosscompile_random_forest/main.cpp b/embedded/crosscompile_random_forest/main.cpp new file mode 100644 index 00000000..bcb6e413 --- /dev/null +++ b/embedded/crosscompile_random_forest/main.cpp @@ -0,0 +1,35 @@ +#include + +using namespace mlpack; + +int main(int argc, char** argv) +{ + arma::mat dataset; + data::Load("../../data/covertype-small.csv", dataset); + + // Labels are the last row.\n", + // The dataset stores labels from 1 through 7, but we need 0 through 6\n", + // (in mlpack labels are zero-indexed), so we subtract 1.\n", + arma::Row labels = arma::conv_to>::from(dataset.row(dataset.n_rows - 1)) - 1; + dataset.shed_row(dataset.n_rows - 1); + + arma::mat trainSet, testSet; + arma::Row trainLabels, testLabels; + + // Split dataset randomly into training set and test set.\n", + data::Split(dataset, labels, trainSet, testSet, trainLabels, testLabels, 0.3 + /* Percentage of dataset to use for test set. */); + + RandomForest<> rf(trainSet, trainLabels, 7 /* Number of classes in dataset */, 10 /* 10 trees */); + // Predict the labels of the test points., + arma::Row output; + rf.Classify(testSet, output); + // Now print the accuracy. The 'probabilities' output could also be used to\n", + // generate an ROC curve.\n", + const size_t correct = arma::accu(output == testLabels); + std::cout << correct + << " correct out of " + << testLabels.n_elem << "\n" + << 100.0 * correct / testLabels.n_elem + << "%)." << std::endl; +} From 0ef23b5cd19085324e78d5ca86590e65dcadfed5 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 27 Jun 2024 15:07:43 +0200 Subject: [PATCH 3/7] Fix the readme Signed-off-by: Omar Shrit --- embedded/mlpack_embedded_cmake/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embedded/mlpack_embedded_cmake/README.md b/embedded/mlpack_embedded_cmake/README.md index 43185dc9..cfa1f7bc 100644 --- a/embedded/mlpack_embedded_cmake/README.md +++ b/embedded/mlpack_embedded_cmake/README.md @@ -4,10 +4,10 @@ This is a set of CMakefiles that autodowload all the mlpack dependencies. The objective of this example is to provide the minimum configurations that allow to build an mlpack application with in the objective of embedded system. -These files contains the necessary cmake files that are ncessary in the -embedded context, especially the cross compilation step, and build a -statically linked binary, but this is not necessary as well since you -can use these configs to build any mlpack application for your machine as well. +These files contains the necessary cmake files that are required in the +embedded context, especially the cross compilation step, and to build a +statically linked binary, you can use these configs to build any mlpack +application for any platform as long as you modify the configs accordingly. The main CMakeLists.txt assumes that the project name is `main` and that you have a file that is called `main.cpp` that contains the mlpack C++ code you are From 1b2c753b3c939b53417c09b61eaa6ab0b4a997d5 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Mon, 1 Jul 2024 11:23:49 +0200 Subject: [PATCH 4/7] Change the directory name Signed-off-by: Omar Shrit --- .../CMake/Autodownload.cmake | 0 .../CMake/ConfigureCrossCompile.cmake | 0 .../CMakeLists.txt | 0 .../{mlpack_embedded_cmake => embedded_cmake_template}/README.md | 0 .../board/crosscompile-toolchain.cmake | 0 .../board/flags-config.cmake | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/CMake/Autodownload.cmake (100%) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/CMake/ConfigureCrossCompile.cmake (100%) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/CMakeLists.txt (100%) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/README.md (100%) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/board/crosscompile-toolchain.cmake (100%) rename embedded/{mlpack_embedded_cmake => embedded_cmake_template}/board/flags-config.cmake (100%) diff --git a/embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake b/embedded/embedded_cmake_template/CMake/Autodownload.cmake similarity index 100% rename from embedded/mlpack_embedded_cmake/CMake/Autodownload.cmake rename to embedded/embedded_cmake_template/CMake/Autodownload.cmake diff --git a/embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake b/embedded/embedded_cmake_template/CMake/ConfigureCrossCompile.cmake similarity index 100% rename from embedded/mlpack_embedded_cmake/CMake/ConfigureCrossCompile.cmake rename to embedded/embedded_cmake_template/CMake/ConfigureCrossCompile.cmake diff --git a/embedded/mlpack_embedded_cmake/CMakeLists.txt b/embedded/embedded_cmake_template/CMakeLists.txt similarity index 100% rename from embedded/mlpack_embedded_cmake/CMakeLists.txt rename to embedded/embedded_cmake_template/CMakeLists.txt diff --git a/embedded/mlpack_embedded_cmake/README.md b/embedded/embedded_cmake_template/README.md similarity index 100% rename from embedded/mlpack_embedded_cmake/README.md rename to embedded/embedded_cmake_template/README.md diff --git a/embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake b/embedded/embedded_cmake_template/board/crosscompile-toolchain.cmake similarity index 100% rename from embedded/mlpack_embedded_cmake/board/crosscompile-toolchain.cmake rename to embedded/embedded_cmake_template/board/crosscompile-toolchain.cmake diff --git a/embedded/mlpack_embedded_cmake/board/flags-config.cmake b/embedded/embedded_cmake_template/board/flags-config.cmake similarity index 100% rename from embedded/mlpack_embedded_cmake/board/flags-config.cmake rename to embedded/embedded_cmake_template/board/flags-config.cmake From 3de6a6adb31562358a8480b71ebd0c6ec09ff158 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 4 Jul 2024 15:08:30 +0200 Subject: [PATCH 5/7] Remove the \n that was from jupyter Signed-off-by: Omar Shrit --- embedded/crosscompile_random_forest/main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embedded/crosscompile_random_forest/main.cpp b/embedded/crosscompile_random_forest/main.cpp index bcb6e413..3a2011f4 100644 --- a/embedded/crosscompile_random_forest/main.cpp +++ b/embedded/crosscompile_random_forest/main.cpp @@ -7,25 +7,25 @@ int main(int argc, char** argv) arma::mat dataset; data::Load("../../data/covertype-small.csv", dataset); - // Labels are the last row.\n", - // The dataset stores labels from 1 through 7, but we need 0 through 6\n", - // (in mlpack labels are zero-indexed), so we subtract 1.\n", + // Labels are the last row. + // The dataset stores labels from 1 through 7, but we need 0 through 6 + // (in mlpack labels are zero-indexed), so we subtract 1. arma::Row labels = arma::conv_to>::from(dataset.row(dataset.n_rows - 1)) - 1; dataset.shed_row(dataset.n_rows - 1); arma::mat trainSet, testSet; arma::Row trainLabels, testLabels; - // Split dataset randomly into training set and test set.\n", + // Split dataset randomly into training set and test set. data::Split(dataset, labels, trainSet, testSet, trainLabels, testLabels, 0.3 /* Percentage of dataset to use for test set. */); RandomForest<> rf(trainSet, trainLabels, 7 /* Number of classes in dataset */, 10 /* 10 trees */); - // Predict the labels of the test points., + // Predict the labels of the test points. arma::Row output; rf.Classify(testSet, output); - // Now print the accuracy. The 'probabilities' output could also be used to\n", - // generate an ROC curve.\n", + // Now print the accuracy. The 'probabilities' output could also be used to" + // generate an ROC curve." const size_t correct = arma::accu(output == testLabels); std::cout << correct << " correct out of " From 9871d10f9a4bc6bac27f1eed3325ad07803d9d8f Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 4 Jul 2024 15:24:06 +0200 Subject: [PATCH 6/7] Fix according to comments Signed-off-by: Omar Shrit --- embedded/crosscompile_random_forest/main.cpp | 15 +++++++++++ embedded/embedded_cmake_template/README.md | 28 ++++++++++++-------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/embedded/crosscompile_random_forest/main.cpp b/embedded/crosscompile_random_forest/main.cpp index 3a2011f4..865739f3 100644 --- a/embedded/crosscompile_random_forest/main.cpp +++ b/embedded/crosscompile_random_forest/main.cpp @@ -1,3 +1,18 @@ +/** + * This is a super simple example using random forest. The idea is show how we + * can cross compile this binary and use it on an embedded Linux device. + * + * It is up to the user to built something interesting out of this example, the + * following is just a starting point. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + * + * @author Omar Shrit + */ + #include using namespace mlpack; diff --git a/embedded/embedded_cmake_template/README.md b/embedded/embedded_cmake_template/README.md index cfa1f7bc..f104fbd0 100644 --- a/embedded/embedded_cmake_template/README.md +++ b/embedded/embedded_cmake_template/README.md @@ -1,18 +1,24 @@ -## CMake files for mlpack +## CMake files to cross compile an mlpack application -This is a set of CMakefiles that autodowload all the mlpack dependencies. The -objective of this example is to provide the minimum configurations that allow -to build an mlpack application with in the objective of embedded system. +This directory contains a minimal and simple CMake configuration that +autodownloads all the mlpack dependencies. This example can be used as a simple +starting point for building an mlpack application that will be compiled to an +embedded system. -These files contains the necessary cmake files that are required in the -embedded context, especially the cross compilation step, and to build a -statically linked binary, you can use these configs to build any mlpack -application for any platform as long as you modify the configs accordingly. +This example contains the necessary CMake files that are required in the +embedded context, especially for cross-compilation, and to build a statically +linked binary. You can use this configuration to build any mlpack +application for any platform, as long as you modify the configuration +accordingly. The main CMakeLists.txt assumes that the project name is `main` and that you have a file that is called `main.cpp` that contains the mlpack C++ code you are trying to compile. Feel free to modify these the way it suits you. -If you are looking to integrate these CMakeFiles into your project, feel free -to modify them the way you want. The point of these files to provide a simple -working example and to keep things simple +Please refer to our documentation for an entire guide on cross compilation. +Usually, we use buildroot toolchain to achieve so, To crosscompile, please +modify the following command accordingly: + +``` +cmake -DBUILD_TESTS=ON -DBOARD_NAME="RPI2" -DCMAKE_CROSSCOMPILE=ON -DCMAKE_TOOLCHAIN_FILE=/path/to/mlpack/board/crosscompile-toolchain.cmake -DTOOLCHAIN_PREFIX=/path/to/bootlin/toolchain/armv7-eabihf--glibc--stable-2023.08-1/bin/arm-buildroot-linux-gnueabihf- -DCMAKE_SYSROOT=/path/to/bootlin/toolchain/armv7-eabihf--glibc--stable-2024.02-1/arm-buildroot-linux-gnueabihf/sysroot ../ +``` From dd45e26170ed15c8576e3c9e62c37c1062f89130 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Thu, 4 Jul 2024 15:25:52 +0200 Subject: [PATCH 7/7] Remove last " Signed-off-by: Omar Shrit --- embedded/crosscompile_random_forest/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embedded/crosscompile_random_forest/main.cpp b/embedded/crosscompile_random_forest/main.cpp index 865739f3..86686061 100644 --- a/embedded/crosscompile_random_forest/main.cpp +++ b/embedded/crosscompile_random_forest/main.cpp @@ -39,8 +39,8 @@ int main(int argc, char** argv) // Predict the labels of the test points. arma::Row output; rf.Classify(testSet, output); - // Now print the accuracy. The 'probabilities' output could also be used to" - // generate an ROC curve." + // Now print the accuracy. The 'probabilities' output could also be used to + // generate an ROC curve. const size_t correct = arma::accu(output == testLabels); std::cout << correct << " correct out of "