Latest articles:

CMake Matlab/Simulink crosscompiling

aus der Kategorie Coding

Begin


Recently i had the pleasure to compile a lot of C++ code for a release and it was kind of painful to switch back and forth between windows and linux.
The work-flow was as following. Writing code and testing under Linux, using CMake to generate a Visual Studio project, compile a static library, use matlabs mex to generate a mex file for use with simulink. Every single step in this process was as painful as it sounds and most importantly bugs might occure in every stage described. A nice way out of this misery seemed to be using a cross-compiler for generating a static library which could be used under windows.
Little did I know, it was possibile to completely generate a .mexw32/.mexw64 file which could be directly used in simulink.

During my search for cross-compiling I found out that I needed a toolchain for compiling.
With debian the following toolchain can be used for 32-bit applications
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR "32")

# which compilers to use for C and C++
SET(CMAKE_C_COMPILER   i686-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER  i686-w64-mingw32-windres)

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 )

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search 
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

and for 64-bit application the following toolchain should be valid:
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR "64")

# which compilers to use for C and C++
SET(CMAKE_C_COMPILER   x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER  x86_64-w64-mingw32-windres)

# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32/ )

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search 
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Note that CMAKE_SYSTEM_PROCESSOR is misused here for later on deciding between 32- and 64-bit systems.
The following CMakeLists.txt can be used to generate a *.mex* file:
cmake_minimum_required (VERSION 2.6)

OPTION (BUILD_SIMULINK_INTERFACE "Build simulink interfaces" OFF)
### set path to matlab here
SET(MATLAB_WINDOWS_DIRECTORY "MATLAB-NOT-FOUND" CACHE PATH "Path to Matlab" )

if (BUILD_SIMULINK_INTERFACE)
    ### needed link directory for matlab
    LINK_DIRECTORIES( ${CMAKE_LIBRARY_PATH} ${MATLAB_WINDOWS_DIRECTORY}/bin/win${TARGET_BIT}/ ) 
    ### simulink paths
    INCLUDE_DIRECTORIES(${PATH_TO_MATLAB}/rtw/c/src ${PATH_TO_MATLAB}/stateflow/c/mex/include ${PATH_TO_MATLAB}/simulink/include) 
    ### a lot of libraries that are needed for matlab and mingw
    SET(SIMULINK_LIBRARIES mex mx mwlapack mwblas eng advapi32 user32 gdi32 kernel32 mingwex) 
    ### This tells simulink we are building an s-function
    ADD_DEFINITIONS(-DMATLAB_MEX_FILE) 

    ### .mex* is a nothing more than a shared library, therefore we set this SHARED
    ADD_LIBRARY(simulinkLib SHARED ${S_FUNCTION_FILES_HERE} )   
    TARGET_LINK_LIBRARIES (simulinkLib ${DIFFERENT_LIBRARIES_HERE} ${SIMULINK_LIBRARIES})
endif(BUILD_SIMULINK_INTERFACE)


The generation of the code can be toggled with the option BUILD_SIMULINK_INTERFACE and one has to set the path to the windows matlab directory. If one does not want to have a full blown matlab/simulink installation running the following directories from the matlab root directory should be sufficient:
  • /bin/win32 or /bin/win64
  • /rtw/c/src
  • /stateflow/c/mex/include
  • /simulink/include

hzgf. am 02. September 2014