Compiling libtorch to WebAssembly with Emscripten using CMake build - cmake

I am trying run my PyTorch model (exported to TorchScript) in the browser using WebAssembly. To do this, I need to compile libtorch using Emscripten. As PyTorch docs suggest using CMake as a compiler I stuck with that.
I've manage to compile libtorch using CMake without issues as specified here. Secondly, I also manage to compile a simple test program to WASM using Emscripten and CMake (for conciseness and focusing on the problem-at-hand I haven't included the CMakeLists.txt files for either of these)
Where the issues start is when I try to compile both together, here's my CMake file:
set(project "wasm-example")
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
set(CMAKE_TOOLCHAIN_FILE $HOME/.local/share/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake)
set(CMAKE_BUILD_TYPE Debug)
project(${project})
SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_PREFIX_PATH $PWD/libtorch)
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Using prefix path: ${CMAKE_PREFIX_PATH}")
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
include(CTest)
enable_testing()
set(SOURCE_FILES main.cpp)
# process exported functions
set(exports_string "")
list(JOIN exports "," exports_string)
# set compiler and flags
set(CMAKE_C_COMPILER emcc)
set(CMAKE_CPP_COMPILER em++)
set(CMAKE_CXX_FLAGS "-s WASM=1 -s EXIT_RUNTIME=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=\"[\"cwrap\", \"getValue\", \"setValue\"]\" ${TORCH_CXX_FLAGS}")
message(STATUS "Set CMAKE_CXX_FLAGS to: ${CMAKE_CXX_FLAGS}")
# find external target_link_libraries
find_package(Torch REQUIRED)
# specify the project
add_executable(${project} ${SOURCE_FILES})
target_link_libraries(${project} "${TORCH_LIBRARIES}")
set_property(TARGET ${project} PROPERTY CXX_STANDARD 14)
Note that I'm using the CPU-only distribution of libtorch, the CUDA-enabled version leads to even more issues because cuda is dynamic-only.
cmake ..src passes, however make throws several errors:
wasm-ld: error: unknown argument: --no-as-needed
wasm-ld: error: unknown argument: --as-needed
wasm-ld: error: unknown argument: --no-as-needed
wasm-ld: error: unknown argument: --as-needed
wasm-ld: error: unknown file type: /home/max/repos/sandbox/cpp/wasm-example/libtorch/lib/libtorch_cpu.so
wasm-ld: error: unknown file type: /home/max/repos/sandbox/cpp/wasm-example/libtorch/lib/libtorch.so
Clearly Emscripten is having some trouble with the dynamic nature of libtorch, so my first question would be if it's even possible to compile dynamic libraries using Emscripten? If this is possible, it would be interesting to try and compile GPU-enabled libtorch using Emscripten.
UPDATE
I tried to compile with the static CPU-only distribution of libtorch, but this leads to the exact same errors. However, an old GitHub issue on the Pytorch github was just revived stating that I'm not the only one with this problem. Hopefully this GitHub issue will address the issues I'm having.

Related

CMake and MinGW cannot disable "is deprecated" warnings also setting CMAKE_WARN_DEPRECATED

I am using CMake version 3.23 with MinGW compiler
This are the basic CMAKE settings:
CMAKE_MINIMUM_REQUIRED(VERSION 3.23)
## GENERAL INITIALIZATION
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
I use CMake -G "MinGW Makefiles" .. to build the project with MinGW generator and everything works. To compile I can use both CMake --build . or mingw32-make.exe: they both warks but gives the warnings that I am describing.
The problem is that I am using some external libraries (boost, turtle) that uses the template<class> class std::auto_ptr that is deprecated.
For this reason, when I compile my project, I get this warning:
C:/turtle/include/turtle/detail/action.hpp:220:22: warning: 'template<class> class std::auto_ptr' is deprecated [-Wdeprecated-declarations]
mutable std::auto_ptr< Result > v_;
^~~~~~~~
And many other of this type as well.
As I mentioned, those warnings are not a problem for compilation, but I would like to disable them.
I have tried to set CMAKE_WARN_DEPRECATED:
SET(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
but it does not work.
I have also tried
add_compile_options(-Wno-deprecated-declarations)
but it does not work as well.
EDIT:
As suggested in the comments by Alex Reinking CMAKE_WARN_DEPRECATED is not related to compilation warning but to CMAKE warning.
The only way I've found to eliminate the warnings was to redefine CMAKE_CXX_FLAGS:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
Hope it can be helpful

Unknown CMake command "CMAKE_DEPENDENT_OPTION"

I faced with an issue that my installed on Ubuntu cmake
cmake --version
cmake version 3.17.2
doesn't recognize CMAKE_DEPENDENT_OPTION command.
So, my CMakeLists.txt with dependent option example from cmake.org/v3.16:
cmake_minimum_required(VERSION 3.4.1)
project(myexe)
CMAKE_DEPENDENT_OPTION(USE_FOO "Use Foo" ON
"USE_BAR;NOT USE_ZOT" OFF)
file(GLOB SRC_FILES "src/*.cpp")
add_executable(${PROJECT_NAME} ${SRC_FILES})
The following error is displayed when running cmake:
CMake Error at CMakeLists.txt:5 (CMAKE_DEPENDENT_OPTION):
Unknown CMake command "CMAKE_DEPENDENT_OPTION".
Why does it happen because the spec says it is supported? Thanks for any help!
You need to add
include(CMakeDependentOption)
before accessing this function.

How to get cmake generate -std=c++14 flag for qcc compiler

I'm trying to cross compile some c++ library for QNX neutrino using cmake. In CMakeLists.txt file I specified CMAKE_CXX_STANDARD 14 required, but the resulting compiler command line does not contain the -std=c++14 option.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
I've tried using target compile features:
target_compile_features(my_library PRIVATE cxx_std_14)
but that gives me the following error:
CMake Error at CMakeLists.txt:53 (target_compile_features):
target_compile_features no known features for CXX compiler
"QCC"
version 5.4.0.
When I'm using check_cxx_compiler_flag feature, it seems to recognize the option:
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++14 CXX14_SUPPORT)
if(CXX14_SUPPORT)
message("c++14 support found")
else()
message("c++14 unsupported")
endif()
This outputs message
c++14 support found
Running qcc manually it accepts the -std=c++14 option just fine and the code using std::make_unique compiles just fine.
Also using the native compiler (Ubuntu 18.04, gcc) everything work fine with cmake generated makefiles. make VERBOSE=1 displays the following command line (I removed some directories):
/usr/local/bin/c++ -Dshm_transfer_EXPORTS -I... -fPIC -std=gnu++14 -o CMakeFiles/shm_transfer.dir/src/SharedMemoryTransfer.cpp.o -c .../SharedMemoryTransfer.cpp
as opposed to the command line using qcc toolchain:
.../qnx700/host/linux/x86_64/usr/bin/qcc -lang-c++ -Vgcc_ntox86_64 -lang-c++ -Dshm_transfer_EXPORTS -I... -fPIC -o CMakeFiles/shm_transfer.dir/src/SharedMemoryTransfer.cpp.o -c .../SharedMemoryTransfer.cpp
I would have expected the cmake command to recognize that qcc supports the -std=c++14 option and generates the corresponding command lines because of the CMAKE_CXX_STANDARD setting.
Use
set_property(TARGET ${PROJECT_NAME} PROPERTY LINKER_LANGUAGE CXX)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
. Using this you can stick the compiler setting to the target, while global flags are dis encouraged and can be overwritten by other cmake consumers. This the reason I assume why the deprecated set(CMAKE_CXX_STANDARD 14) did not help you: I can not see your full CMakeLists.txt and bet you have many sub folders and other targets, which could reset the CMAKE_CXX_STANDARD them selfs. Also make sure of the ordering of the CMake commands.
And you can replace ${PROJECT_NAME} with my_library if you want.
add_compile_options(-std=gnu++14)
Add this to your project level CMakeLists.txt file, not in toolchain.

STM32 Project with CMake

I am trying to create and compile an ARM-based STM32 project using CMake.
CMakeLsts.txt is the following:
cmake_minimum_required(VERSION 3.7)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
# Enable logging messages
#set(CMAKE_VERBOSE_MAKEFILE ON)
# Project name
set(PROJECT_NAME FixtureTACO)
PROJECT(${PROJECT_NAME} C CXX ASM)
SET(CMAKE_CXX_STANDARD 11)
###################### CHIP CONFIGURATION ##########################
SET(ROOT_PROJ ${CMAKE_CURRENT_SOURCE_DIR})
SET(CPU "cortex-m4")
SET(ARCH_NAME "arm")
SET(ARCH_VER "v7e-m")
SET(FAMILY "stm32f3")
SET(CHIP "STM32F303xC")
SET(ARCH "${ARCH_NAME}${ARCH_VER}")
####################################################################
# MCU Config
set(FPU "-mfpu=fpv4-sp-d16")
set(FLOAT_ABI "-mfloat-abi=hard")
# Toolchain path
set(TOOLCHAIN_PATH "")
set(ARM_LIB "/usr/lib/arm-none-eabi/lib/${ARCH}")
# Specify C, C++ and ASM compilers
SET(CMAKE_C_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-gcc)
SET(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-g++)
set(AS ${TOOLCHAIN_PATH}arm-none-eabi-as)
set(AR ${TOOLCHAIN_PATH}arm-none-eabi-ar)
set(OBJCOPY ${TOOLCHAIN_PATH}arm-none-eabi-objcopy)
set(OBJDUMP ${TOOLCHAIN_PATH}arm-none-eabi-objdump)
set(SIZE ${TOOLCHAIN_PATH}arm-none-eabi-size)
set(GDB ${TOOLCHAIN_PATH}arm-none-eabi-gdb)
set(SIZE ${TOOLCHAIN_PATH}arm-none-eabi-size)
# Definitions passed at compile time (#defines)
add_definitions(-DFAMILY=${FAMILY})
add_definitions(-DCHIP=${CHIP})
add_definitions(-D${CHIP})
add_definitions(-DUSE_FULL_LL_DRIVER)
add_definitions(-USE_HAL_DRIVER)
add_definitions(-DHSE_VALUE=8000000)
add_definitions(-DHSE_STARTUP_TIMEOUT=100)
add_definitions(-DLSE_STARTUP_TIMEOUT=5000)
add_definitions(-DLSE_VALUE=32768)
add_definitions(-DHSI_VALUE=8000000)
add_definitions(-DLSI_VALUE=40000)
add_definitions(-DDD_VALUE=3300)
add_definitions(-DPREFETCH_ENABLE=1)
# Compilation flags
add_compile_options(-mcpu=${CPU})
add_compile_options(-march=${ARCH})
add_compile_options(-mthumb)
add_compile_options(${FPU})
add_compile_options(${FLOAT_ABI})
add_compile_options(-Og)
add_compile_options(-Wall)
add_compile_options(-fdata-sections)
add_compile_options(-ffunction-sections)
# Only for debugging
add_compile_options(-g -gdwarf-2)
# Linker script path
file(GLOB_RECURSE LINKER_SCRIPT ${ROOT_PROJ}/platforms/${FAMILY}/Linker/*.ld)
# Variables initialized first time
SET(CMAKE_CXX_FLAGS_INIT "-std=c++11")
SET(CMAKE_C_FLAGS_INIT "-std=gnu99")
################################## Source code ###############################################################
# Retrieve all sources # "platforms/${FAMILY}/Startup/*.s"
file(GLOB SOURCES "platforms/${FAMILY}/Startup/*.s" "src/*.cpp" "src/*.c" "platforms/${FAMILY}/Hal/src/*.c" "platforms/${FAMILY}/Device/*.c")
#Retrieve all locations of headers
file(GLOB_RECURSE HEADERS "includes/*.h" "src/*.h" "platforms/${FAMILY}*.h")
set (INCLUDE_DIRS "")
foreach (_headerFile ${HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND INCLUDE_DIRS ${_dir})
endforeach()
list(REMOVE_DUPLICATES INCLUDE_DIRS)
include_directories(${INCLUDE_DIRS})
link_directories(${ARM_LIB})
################################## Source code END ###########################################################
set(EXE_NAME "${PROJECT_NAME}_${CHIP}")
add_executable(${EXE_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${CPU} -mthumb ${FPU} ${FLOAT_ABI} --specs=nano.specs -T${LINKER_SCRIPT} -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map,--cref -Wl,--gc-sections")
# Libs and external dependencies
target_link_libraries(${EXE_NAME}.elf -lc -lm -lnosys)
# Outputs
set(ELF_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.elf)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${EXE_NAME}.bin)
add_custom_command(TARGET "${EXE_NAME}.elf" POST_BUILD
# Build .hex and .bin files
COMMAND ${OBJCOPY} -Obinary ${ELF_FILE} ${BIN_FILE}
COMMAND ${OBJCOPY} -Oihex ${ELF_FILE} ${HEX_FILE}
COMMENT "Building ${PROJECT_NAME}.bin and ${PROJECT_NAME}.hex"
# Copy files to a custom build directory
COMMAND ${CMAKE_COMMAND} -E copy ${ELF_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.elf"
COMMAND ${CMAKE_COMMAND} -E copy ${HEX_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.hex"
COMMAND ${CMAKE_COMMAND} -E copy ${BIN_FILE} "${ROOT_PROJ}/builds/${CHIP}/${EXE_NAME}.bin"
# Display sizes
COMMAND ${SIZE} --format=berkeley ${EXE_NAME}.elf ${EXE_NAME}.hex
COMMENT "Invoking: Cross ARM GNU Print Size"
)
add_custom_target(UPLOAD
${GDB} -iex "target remote tcp:127.0.0.1:3333"
-iex "monitor program ${EXE_NAME}.elf"
-iex "monitor reset init"
-iex "disconnect" -iex "quit ")
When I try to compile I am getting the following errors:
[ 82%] Building C object CMakeFiles/FixtureTACO_STM32F303xC.elf.dir/platforms/stm32f3/Hal/src/stm32f3xx_ll_utils.c.obj
[ 86%] Building ASM object CMakeFiles/FixtureTACO_STM32F303xC.elf.dir/platforms/stm32f3/Startup/startup_stm32f303xc.s.obj
cc: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead
cc: error: unrecognized command line option ‘-mthumb’; did you mean ‘-mtbm’?
cc: error: unrecognized command line option ‘-mfpu=fpv4-sp-d16’
cc: error: unrecognized command line option ‘-mfloat-abi=hard’
The error occurs ONLY when an assembly file (startup.s in this case) is present in source files and when FPU and FLOAR_ABI flags are present. As you can see, error occurs when startup_stm32f303xc.s is compiled.
I suspect that I am adding those flags in the wrong place but I have no clue where to add them in order to get it works.
Later edit: I already have installed arm 7 compiler on my ubuntu system. I can use it without specifying any path as it is already present in environment variables. I can compile without problems ARM code (from Makefiles) for other targets on machine. My problem is with cmake.
In your line set(TOOLCHAIN_PATH "") you must add a path to compiler. First go to get your free GCC ARM ToolChain. Download for your OS. and then just copy to your favorite location. If you using Linux you can use my path configurations:
1.) Copy gcc arm compirel to /opt/ directory:
sudo tar xjfv ~/Downloads/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2 -C /opt/
For more "sexy" path you can do symbolic link:
sudo ln -s /opt/gcc-arm-none-eabi-7-2018-q2-update/ /opt/gcc-arm-none-eabi
After that go to your CMakeLists.txt and rewrite your set command to:
set(TOOLCHAIN_PATH "/opt/gcc-arm-none-eabi/bin")
But there is better solution to build your project for STM32, but with already done stm32-cmake template project, specifically made for STM32 family. It is mush easier done with something working. You will also need two prerequisites STM32CubeMX installed and again GCC ARM ToolChain. If you want to know how to use this template just DM me and I will you give a quick guidance.
OK, I finally managed to figure it out!
I had to replace
set(AS ${TOOLCHAIN_PATH}arm-none-eabi-as)
with
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PATH}arm-none-eabi-gcc)
It is not a mistake, it is gcc compiler. You can also append these flags: -x assembler-with-cpp.
CMake didn't know about my custom ASM compiler so it was using default system ASM compiler unless I force it by writing CMAKE_ASM_COMPILER. Now the project is being build and works fine on microcontroller.
The other answers were ok, but had half of the solution. Only ASM filese were compiled with wrong compiler.
I think you try to compile code for ARM using x86 compiler. It will not work. You need to download the ARM toolchain and use the correct compiler.
-mcpu is depreciated in the x86 branch, but is not in the ARM branch
another options just not exist in the x86 compiler.

Build MPICH with CMake

I need to force my Cmake to build and link my MPI code with MPICH. My MPICH is installed using the Ubuntu Package manager, in a standard location /usr/lib/mpich/. However, CMake still looks for the OpenMPI libraries, which I do not use. How can I instruct CMake to look for MPICH instead?
Below, you can see the output of some basic diagnostics:
$ whereis openmpi
openmpi:
$ whereis mpich
mpich: /usr/lib/mpich /usr/include/mpich
$ mpicc -v
mpicc for MPICH version 3.2
Below, I also provide the Cmake script and the errors I get from cmake and the mpirun.mpich. My Cmake is 3.5.1 and I run on Ubuntu Xenial 16.04.
cmake_minimum_required(VERSION 3.0)
message (STATUS "Adding mpiService")
find_package(MPI REQUIRED)
set(CMAKE_C_COMPILER mpicc)
set(CMAKE_CXX_COMPILER mpicxx)
set(MPI_GUESS_LIBRARY_NAME MPICH2)
message(STATUS ${MPI_INCLUDE_PATH})
message(STATUS ${MPI_C_LIBRARIES})
#add_definitions(-DOMPI_SKIP_MPICXX)
add_executable(mpiService main.cpp)
set(CMAKE_VERBOSE_MAKEFILE ON)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
target_link_libraries(
mpiService
PRIVATE
${MPI_C_LIBRARIES}
)
From the Cmake STATUS I get the following output:
/usr/lib/openmpi/include/openmpi/opal/mca/event/libevent2021/libevent/usr/lib/openmpi/include/openmpi/opal/mca/event/libevent2021/libevent/include/usr/lib/openmpi/include/usr/lib/openmpi/include/openmpi
/usr/lib/openmpi/lib/libmpi.so
And when I run the binary I get the following:
ubuntu#node1:~$ mpirun.mpich -np 2 --host node1,node2 mpiService
mpiService: error while loading shared libraries: libmpi.so.12: cannot open shared object file: No such file or directory
mpiService: error while loading shared libraries: libmpi.so.12: cannot open shared object file: No such file or directory
How can I instruct CMake to look for MPICH instead?
According to FindMPI documentation, you may set MPI_<lang>_COMPILER variable to the desired MPI compiler:
Set MPI_<lang>_COMPILER to the MPI wrapper (mpicc, etc.) of your
choice and reconfigure. FindMPI will attempt to determine all the
necessary variables using THAT compiler's compile and link flags.
set(MPI_CXX_COMPILER <path-to-mpich-compiler>)
find_package(MPI REQUIRED)
Alternatively, since CMake version 3.10, variable MPI_EXECUTABLE_SUFFIX can be set instead:
A suffix which is appended to all names that are being looked for. For instance you may set this to .mpich or .openmpi to prefer the one or the other on Debian and its derivatives.
set(MPI_EXECUTABLE_SUFFIX ".mpich")
find_package(MPI REQUIRED)
Herewith my current solution.
find_package(MPI REQUIRED)
# ----------------
# This is the only thing that made it work
# ----------------
set(MPI_C_LIBRARIES "/usr/lib/mpich/lib/libmpich.so")
set(MPI_INCLUDE_PATH "/usr/include/mpich")
# ----------------
add_executable(mpiService main.cpp)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
target_link_libraries(
mpiService
${MPI_C_LIBRARIES}
)
I personally do not like this solution, as I have to explicitly specify the path. Any other proposed solution was still building with OpenMPI. If I find a better alternative, I will re-post.