Cross-Compiling OSQP for ARM STM32F405

Hello,

I am working on a project that involves solving QP problems onboard a Crazyflie2.1 STM32F405 computing unit. I was drawn to OSQP since it seems embeddable. Can OSQP be compiled for this architecture?

I am not an expert in embedded programming, but looking around I got to the point of attempting to link the static library libosqp.a with the Crazyflie Firmware project. In this process I realized that I had built the libosqp.a file based on my native Linux x86 architecture and therefore the cross compiler for Crazyflie (arm-none-eabi-gcc) could not link libosqp.a with the rest of the Crazyflie project. The compilation error was
bin/libosqp.a: error adding symbols: file format not recognized collect2: error: ld returned 1 exit status

Next, I tried to cross-compile libosqp.a with the correct architecture (ARM STM32) using the cross compiler arm-none-eabi-gcc. I attempted to do this by adding the following lines at the beginning of the CMakeLists.txt file in the root directory of the osqp project.

#---------------------------------------------
# TODO CROSS COMPILE
set(CMAKE_SYSTEM_NAME Generic) # 'Generic' is used for embedded systems

set(CMAKE_C_COMPILER /usr/bin/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER /usr/bin/arm-none-eabi-gcc)

# tells CMake not to try to link executables during its interal checks
# things are not going to link properly without a linker script
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_OBJCOPY /usr/bin/arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP /usr/bin/arm-none-eabi-objdump)
set(CMAKE_SIZE /usr/bin/arm-none-eabi-size)
set(CMAKE_DEBUGGER /usr/bin/arm-none-eabi-gdb)
set(CMAKE_DEBUGGER /usr/bin/arm-none-eabi-gdb)
set(CMAKE_CPPFILT /usr/bin/arm-none-eabi-c++filt)

#--------------------------------------------



# Minimum version required
cmake_minimum_required (VERSION 3.2)

# Project name
project (osqp)
...

After adding those lines, I run in the command line within the blank build/ directory:
cmake -G "Unix Makefiles" -DEMBEDDED=2 ..
And the command seems to run fine. The only warning is

CMake Warning (dev) at lin_sys/direct/qdldl/qdldl_sources/CMakeLists.txt:132 (add_library):
  ADD_LIBRARY called with SHARED option but the target platform does not
  support dynamic linking.  Building a STATIC library instead.  This may lead
  to problems.

Finally, I attempt to compile the osqp project with the new architecture by running
cmake --build .
However, the compilation fails on linking C executable out/qdldl_example with the following trace:

[ 88%] Linking C executable out/qdldl_example
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): in function `exit':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/stdlib/../../../../../newlib/libc/stdlib/exit.c:64: undefined reference to `_exit'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-sbrkr.o): in function `_sbrk_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/sbrkr.c:51: undefined reference to `_sbrk'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-writer.o): in function `_write_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/writer.c:49: undefined reference to `_write'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-closer.o): in function `_close_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/closer.c:47: undefined reference to `_close'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): in function `_fstat_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/fstatr.c:55: undefined reference to `_fstat'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-isattyr.o): in function `_isatty_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/isattyr.c:52: undefined reference to `_isatty'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-lseekr.o): in function `_lseek_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/lseekr.c:49: undefined reference to `_lseek'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-readr.o): in function `_read_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/readr.c:49: undefined reference to `_read'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-abort.o): in function `abort':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/stdlib/../../../../../newlib/libc/stdlib/abort.c:59: undefined reference to `_exit'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-signalr.o): in function `_kill_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/signalr.c:53: undefined reference to `_kill'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/libc.a(lib_a-signalr.o): in function `_getpid_r':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libc/reent/../../../../../newlib/libc/reent/signalr.c:83: undefined reference to `_getpid'
collect2: error: ld returned 1 exit status
make[2]: *** [lin_sys/direct/qdldl/qdldl_sources/CMakeFiles/qdldl_example.dir/build.make:85: lin_sys/direct/qdldl/qdldl_sources/out/qdldl_example] Error 1
make[1]: *** [CMakeFiles/Makefile2:283: lin_sys/direct/qdldl/qdldl_sources/CMakeFiles/qdldl_example.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

Any help would be appreciated. I apologize for the long post.

Thank you for your time,

-Victor

It definitely should compile on ARM platforms, and it appears that the issue is inside the QDLDL solver library actually instead of OSQP itself.

I think the easiest thing you can do right now is to go into the QDLDL source code itself and modify the CMakeLists.txt like this (it is inside the lin_sys/direct/qdldl/qdldl_sources directory):

  • Remove lines 132-144 to fix the warning about the shared library (this will remove the creation of the shared library)
  • Remove lines 147-148 to fix the compile error (this will remove the demo program)

I think that should be enough to get it to build without errors.

1 Like

Thank you! Those changes allowed the OSQP project to build with the cross-compiler settings. I am still working on linking the library with the rest of the Crazyflie firmware project.

-Victor

1 Like

Great to hear. We are working on a proper fix for this so hopefully in the next OSQP version you won’t have this issue and can build without having to modify the QDLDL sources.

Let us know how the integration with the rest of the Crazyflie firmware goes, and hopefully there aren’t any more problems with it.