26
Nov 09

Calling ITK from MATLAB MEX files

Here we will see how to use cmake to write mex files that interface to ITK. All the steps involved are identical to the ones we saw in the previous post on compiling MATLAB MEX functions with cmake. The differences will be in the CMakeLists.txt file and, of course, in the c++ code (cmexitk.cxx). The program is the MEX version of the HelloWorld! example from the ITK documentation.

Please notice that in Mandriva Linux, I compiled ITK as shared libraries and with gcc-4.2.4!

This is the content of the CMakeLists.txt file. In bold are the additions and changes compares to what we saw in the previous post.


# Set the minimum CMAKE required to 2.8.
cmake_minimum_required( VERSION 2.8 )

# Find ITK
FIND_PACKAGE( ITK )
IF( ITK_FOUND )
INCLUDE( ${ITK_USE_FILE} )
ELSE( ITK_FOUND )
MESSAGE( FATAL_ERROR "ITK not found. Please set ITK_DIR." )
ENDIF( ITK_FOUND )

# Find MATLAB (mind that Find_Matlab.cmake might need to be modified to
# find your MATLAB installation)
FIND_PACKAGE( Matlab )
IF( MATLAB_FOUND )
INCLUDE_DIRECTORIES( ${MATLAB_INCLUDE_DIR} )
ELSE( MATLAB_FOUND )
MESSAGE( FATAL_ERROR "MATLAB not found!" )
ENDIF( MATLAB_FOUND )

# Mex libs have specific extensions, which are platform dependent.
# The following will not work on a MAC, but the tests can be easily extended.
IF( WIN32 )
IF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
# x86
SET(MATLAB_MEXFILE_EXT mexw32)
ELSE( CMAKE_SIZEOF_VOID_P EQUAL 4 )
# x64
SET(MATLAB_MEXFILE_EXT mexw64)
ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
ELSE( WIN32 )
IF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
# Linux x86
SET(MATLAB_MEXFILE_EXT mexglx)
ELSE( CMAKE_SIZEOF_VOID_P EQUAL 4 )
# Linux x64
SET(MATLAB_MEXFILE_EXT mexa64)
ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
ENDIF( WIN32 )

# We create a library cmexitk
ADD_LIBRARY( cmexitk SHARED cmexitk.cxx )

# Define as MATLAB MEX file
ADD_DEFINITIONS( -DMATLAB_MEX_FILE )

# The file mexFunction.def exports the library access point (mexFunction)
IF( WIN32 )
SET_TARGET_PROPERTIES( cmexitk PROPERTIES
LINK_FLAGS "/export:mexFunction" )
ENDIF( WIN32 )

# Set the correct file extension
SET_TARGET_PROPERTIES( cmexitk PROPERTIES
PREFIX ""
SUFFIX ".${MATLAB_MEXFILE_EXT}"
)
# We link against the ITK and MATLAB MEX libraries
TARGET_LINK_LIBRARIES( cmexitk ${ITK_LIBRARIES} ${MATLAB_LIBRARIES} )

The cpp file cmexitk.cxx looks like this:


/*
* cmexitk.cxx
*
*/
#include "itkImage.h"
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
{
// Create an itk::Image
typedef itk::Image< unsigned short, 3 > ImageType;
ImageType::Pointer image = ImageType::New();
// Print Hello World on the MATLAB console
mexPrintf( "Hello World from MEX and ITK!\n" );
}

Building the library is done as explained in the previous post.
Make sure to save the file as .cxx and not as .c, or the compiler will try to compile it as C code (and this won’t work)!


24
Nov 09

Compiling MATLAB MEX functions with cmake

This post (heavily inspired by this and this) will show you how to use cmake (version 2.8) to build a MEX library for MATLAB. This is the first step toward interfacing MATLAB to ITK (the Insight ToolKit) and VTK (the Visualization ToolKit). For the sake of introduction, MEX stands for MATLAB Executable. MEX files are dynamically linked subroutines produced from C, C++ or Fortran source code that, when compiled, can be run from within MATLAB in the same way as MATLAB M-files or built-in functions. Here, we will see how to create a simple c/c++ MEX library for MATLAB using cmake on Mandriva Linux 2010 64 bit (using gcc 4.2) and Microsoft Windows XP 64.

We will need two files, CMakeLists.txt and cmex.c. CMakeLists.txt will be used by cmake to build platform-dependent files for compilation (e.g. a Makefile in Linux, a Visual Studio solution in Windows). cmex.c is the actual c code for the MEX library (which is going to be incredibly simple for the sake of the demonstration).

Here is the content of CMakeLists.txt, with in green the variables defined by the FindMatlab.cmake module (see below):


PROJECT(CMEX)

# Set the minimum CMAKE required to 2.8.
cmake_minimum_required( VERSION 2.8 )

# Find MATLAB (mind that Find_Matlab.cmake might need to be modified to
# find your MATLAB installation)
FIND_PACKAGE( Matlab )
IF( MATLAB_FOUND )
  INCLUDE_DIRECTORIES( ${MATLAB_INCLUDE_DIR} )
ELSE( MATLAB_FOUND )
  MESSAGE( FATAL_ERROR "MATLAB not found!" )
ENDIF( MATLAB_FOUND )

# Mex libs have specific extensions, which are platform dependent.
# The following will not work on a MAC, but the tests can be easily extended.
IF( WIN32 )
  IF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
    # x86
    SET(MATLAB_MEXFILE_EXT mexw32)
  ELSE( CMAKE_SIZEOF_VOID_P EQUAL 4 )
    # x64
    SET(MATLAB_MEXFILE_EXT mexw64)
  ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
ELSE( WIN32 )
  IF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
    # Linux x86
    SET(MATLAB_MEXFILE_EXT mexglx)
  ELSE( CMAKE_SIZEOF_VOID_P EQUAL 4 )
    # Linux x64
    SET(MATLAB_MEXFILE_EXT mexa64)
 ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
ENDIF( WIN32 )

# We create a library cmex
ADD_LIBRARY( cmex SHARED cmex.c )

# Define as MATLAB MEX file
ADD_DEFINITIONS( -DMATLAB_MEX_FILE )

# The file mexFunction.def exports the library access point (mexFunction)
IF( WIN32)
  SET_TARGET_PROPERTIES( cmex PROPERTIES LINK_FLAGS "/export:mexFunction" )
ENDIF( WIN32 )

# Set the correct file extension
SET_TARGET_PROPERTIES( cmex PROPERTIES
  PREFIX ""
  SUFFIX ".${MATLAB_MEXFILE_EXT}" )

# We link against the MATLAB MEX libraries
TARGET_LINK_LIBRARIES( cmex ${MATLAB_LIBRARIES} )

The call to Find_Package(Matlab) might fail for your specific MATLAB installation (it for sure failed for mine), since the FindMatlab.cmake module that comes with cmake  contains some hard-coded, default paths that won’t fit most installations. If this is the case, you will have to change it slightly (on Mandriva Linux 2010 under /usr/share/cmake/Modules/FindMatlab.cmake, on Windows XP under C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules) to look for MATLAB in the right place. For my installation, the relevant changes are in red below.

Here is a tripped-down version of FindMatlab.cmake as distributed with cmake 2.8. The green variables are used by CMakeLists.txt:


# - this module looks for Matlab
# Defines:
# MATLAB_INCLUDE_DIR: include path for mex.h, engine.h
# MATLAB_LIBRARIES: required libraries: libmex, etc
# MATLAB_MEX_LIBRARY: path to libmex.lib
# MATLAB_MX_LIBRARY: path to libmx.lib
# MATLAB_ENG_LIBRARY: path to libeng.lib

#=============================================================================
# Copyright 2005-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distributed this file outside of CMake, substitute the full
# License text for the above reference.)

SET(MATLAB_FOUND 0)
IF(WIN32)
   IF(${CMAKE_GENERATOR} MATCHES "Visual Studio 9")
     SET(MATLAB_ROOT "C:/Program Files/MATLAB/R2009b/extern/lib/win64/microsoft")
   ELSE(${CMAKE_GENERATOR} MATCHES "Visual Studio 9")
     IF(MATLAB_FIND_REQUIRED)
       MESSAGE(FATAL_ERROR "Generator not compatible: ${CMAKE_GENERATOR}")
     ENDIF(MATLAB_FIND_REQUIRED)
   ENDIF(${CMAKE_GENERATOR} MATCHES "Visual Studio 9")
   FIND_LIBRARY(MATLAB_MEX_LIBRARY
     libmex
     ${MATLAB_ROOT}
   )
   FIND_LIBRARY(MATLAB_MX_LIBRARY
     libmx
     ${MATLAB_ROOT}
   )
   FIND_LIBRARY(MATLAB_ENG_LIBRARY
     libeng
     ${MATLAB_ROOT}
   )

   FIND_PATH(MATLAB_INCLUDE_DIR
     "mex.h"
     "C:/Program Files/MATLAB/R2009b/extern/include"
   )
ELSE( WIN32 )
   IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
     # Regular x86
     SET( MATLAB_ROOT /usr/local/r2009b/bin/glnx86/ )
   ELSE(CMAKE_SIZEOF_VOID_P EQUAL 4)
     # AMD64:
     SET(MATLAB_ROOT /usr/local/r2009b/bin/glnxa64/ )
   ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4)
     FIND_LIBRARY(MATLAB_MEX_LIBRARY
   mex
     ${MATLAB_ROOT}
   )
   FIND_LIBRARY(MATLAB_MX_LIBRARY
     mx
     ${MATLAB_ROOT}
   )
   FIND_LIBRARY(MATLAB_ENG_LIBRARY
     eng
     ${MATLAB_ROOT}
   )
   FIND_PATH(MATLAB_INCLUDE_DIR
     "mex.h"
     "/usr/local/r2009b/extern/include/"
   )
ENDIF(WIN32)

# This is common to UNIX and Win32:
SET(MATLAB_LIBRARIES
${MATLAB_MEX_LIBRARY}
${MATLAB_MX_LIBRARY}
${MATLAB_ENG_LIBRARY}
)

IF(MATLAB_INCLUDE_DIR AND MATLAB_LIBRARIES)
   SET(MATLAB_FOUND 1)
ENDIF(MATLAB_INCLUDE_DIR AND MATLAB_LIBRARIES)

MARK_AS_ADVANCED(
   MATLAB_LIBRARIES
   MATLAB_MEX_LIBRARY
   MATLAB_MX_LIBRARY
   MATLAB_ENG_LIBRARY
   MATLAB_INCLUDE_DIR
   MATLAB_FOUND
   MATLAB_ROOT
)

Finally, the cmex.c file contains a very simple MEX function that returns the number of elements in the passed input array:


/*
* cmex.c
*
*/

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
{
plhs[ 0 ] = mxCreateDoubleMatrix( 1, 1, mxREAL );
*mxGetPr( plhs[ 0 ] ) = ( double ) mxGetNumberOfElements( prhs[ 0 ] );
}

Copy or save the two files CMakeLists.txt and cmex.c to a directory of your choice, e.g. /home/{you}/Devel/cmex. Now you can cmake (or ccmake, or cmake-gui) the project. At the bash prompt ($), after having changed to the directory containing the three files, type:


$ cmake .

This should result in the following (or similar) output.


-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to /home/{you}/Devel/cmex

Please mind that in Windows 64 bit using cmake as shown above does not work because the test for 64 bit fails. Using cmake-gui (and selecting Visual Studio 2008 64 bit as the compiler) in contrast works as expected.

And now make (or open the solution in Visual Studio and compile):


$ make

that should say…


Scanning dependencies of target cmex
[100%] Building C object CMakeFiles/cmex.dir/cmex.c.o
Linking C shared library cmex.mexa64
[100%] Built target cmex

You can now copy/add the generated cmex.mexa64 (or cmex.mexglx, cmex.mexw32, cmex.mexw64) file to your MATLAB path and use it as follows:

>> cmex( rand( 5, 5 ) )

ans =

25

where >> is the MATLAB prompt.


27
Oct 09

CUDA: Compiling 64-bit code with MS Visual Studio 2008

Start the Visual Studio 2008 Win64 x64 Command Prompt or, equivalently, the standard Windows Command Prompt (cmd) and run:

"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat"

Compile using:

nvcc -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin" -o test.exe test.cu