2013-12-23 02:01:39 +08:00
# Set up cache options
option ( GTSAM_MEX_BUILD_STATIC_MODULE "Build MATLAB wrapper statically (increases build time)" OFF )
set ( GTSAM_BUILD_MEX_BINARY_FLAGS "" CACHE STRING "Extra flags for running Matlab MEX compilation" )
set ( GTSAM_TOOLBOX_INSTALL_PATH "" CACHE PATH "Matlab toolbox destination, blank defaults to CMAKE_INSTALL_PREFIX/gtsam_toolbox" )
if ( NOT GTSAM_TOOLBOX_INSTALL_PATH )
set ( GTSAM_TOOLBOX_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/gtsam_toolbox" )
endif ( )
# GTSAM_MEX_BUILD_STATIC_MODULE is not for Windows - on Windows any static
# are already compiled into the library by the linker
if ( GTSAM_MEX_BUILD_STATIC_MODULE AND WIN32 )
message ( FATAL_ERROR "GTSAM_MEX_BUILD_STATIC_MODULE should not be set on Windows - the linker already automatically compiles in any dependent static libraries. To create a standalone toolbox pacakge, simply ensure that CMake finds the static versions of all dependent libraries (Boost, etc)." )
endif ( )
# Try to automatically configure mex path
if ( APPLE )
file ( GLOB matlab_bin_directories "/Applications/MATLAB*/bin" )
set ( mex_program_name "mex" )
elseif ( WIN32 )
file ( GLOB matlab_bin_directories "C:/Program Files*/MATLAB/*/bin" )
set ( mex_program_name "mex.bat" )
else ( )
file ( GLOB matlab_bin_directories "/usr/local/MATLAB/*/bin" )
set ( mex_program_name "mex" )
endif ( )
# Run find_program explicitly putting $PATH after our predefined program
# directories using 'ENV PATH' and 'NO_SYSTEM_ENVIRONMENT_PATH' - this prevents
# finding the LaTeX mex program (totally unrelated to MATLAB Mex) when LaTeX is
# on the system path.
list ( REVERSE matlab_bin_directories ) # Reverse list so the highest version (sorted alphabetically) is preferred
find_program ( mex_command ${ mex_program_name }
P A T H S $ { m a t l a b _ b i n _ d i r e c t o r i e s } E N V P A T H
N O _ D E F A U L T _ P A T H )
mark_as_advanced ( FORCE mex_command )
# Now that we have mex, trace back to find the Matlab installation root
get_filename_component ( mex_command "${mex_command}" REALPATH )
get_filename_component ( mex_path "${mex_command}" PATH )
get_filename_component ( MATLAB_ROOT "${mex_path}/.." ABSOLUTE )
set ( MATLAB_ROOT "${MATLAB_ROOT}" CACHE PATH "Path to MATLAB installation root (e.g. /usr/local/MATLAB/R2012a)" )
# User-friendly wrapping function. Builds a mex module from the provided
# interfaceHeader. For example, for the interface header /path/to/gtsam.h,
# this will build the wrap module 'gtsam'.
# Params:
# interfaceHeader : Absolute or relative path to the interface definition file
# linkLibraries : All dependent CMake target names, library names, or full library paths
# extraIncludeDirs : Extra include directories, in addition to those already passed to include_directories(...)
# extraMexFlags : Any additional compiler flags
function ( wrap_and_install_library interfaceHeader linkLibraries extraIncludeDirs extraMexFlags )
2014-02-17 13:44:13 +08:00
wrap_library_internal ( "${interfaceHeader}" "${linkLibraries}" "${extraIncludeDirs}" "${mexFlags}" )
2013-12-23 02:01:39 +08:00
install_wrapped_library_internal ( "${interfaceHeader}" )
endfunction ( )
2014-02-19 02:43:54 +08:00
# Internal function that wraps a library and compiles the wrapper
2013-12-23 02:01:39 +08:00
function ( wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs extraMexFlags )
if ( UNIX AND NOT APPLE )
if ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set ( mexModuleExt mexa64 )
else ( )
set ( mexModuleExt mexglx )
endif ( )
elseif ( APPLE )
set ( mexModuleExt mexmaci64 )
elseif ( MSVC )
if ( CMAKE_CL_64 )
set ( mexModuleExt mexw64 )
else ( )
set ( mexModuleExt mexw32 )
endif ( )
endif ( )
# Wrap codegen interface
#usage: wrap interfacePath moduleName toolboxPath headerPath
# interfacePath : *absolute* path to directory of module interface file
# moduleName : the name of the module, interface file must be called moduleName.h
# toolboxPath : the directory in which to generate the wrappers
# headerPath : path to matlab.h
# Extract module name from interface header file name
get_filename_component ( interfaceHeader "${interfaceHeader}" ABSOLUTE )
get_filename_component ( modulePath "${interfaceHeader}" PATH )
get_filename_component ( moduleName "${interfaceHeader}" NAME_WE )
# Paths for generated files
set ( generated_files_path "${PROJECT_BINARY_DIR}/wrap/${moduleName}" )
set ( generated_cpp_file "${PROJECT_BINARY_DIR}/wrap/${moduleName}/${moduleName}_wrapper.cpp" )
set ( compiled_mex_modules_root "${PROJECT_BINARY_DIR}/wrap/${moduleName}_mex" )
message ( STATUS "Building wrap module ${moduleName}" )
# Find matlab.h in GTSAM
if ( "${PROJECT_NAME}" STREQUAL "GTSAM" )
set ( matlab_h_path "${PROJECT_SOURCE_DIR}" )
else ( )
if ( NOT GTSAM_INCLUDE_DIR )
message ( FATAL_ERROR "You must call find_package(GTSAM) before using wrap" )
endif ( )
list ( GET GTSAM_INCLUDE_DIR 0 installed_includes_path )
set ( matlab_h_path "${installed_includes_path}/wrap" )
endif ( )
# Add -shared or -static suffix to targets
set ( correctedOtherLibraries "" )
set ( otherLibraryTargets "" )
2014-02-17 13:44:50 +08:00
set ( otherLibraryNontargets "" )
2014-02-17 13:44:13 +08:00
foreach ( lib ${ moduleName } ${ linkLibraries } )
2013-12-23 02:01:39 +08:00
if ( TARGET ${ lib } )
list ( APPEND correctedOtherLibraries ${ lib } )
list ( APPEND otherLibraryTargets ${ lib } )
elseif ( TARGET ${ lib } -shared ) # Prefer the shared library if we have both shared and static)
list ( APPEND correctedOtherLibraries ${ lib } -shared )
list ( APPEND otherLibraryTargets ${ lib } -shared )
elseif ( TARGET ${ lib } -static )
list ( APPEND correctedOtherLibraries ${ lib } -static )
list ( APPEND otherLibraryTargets ${ lib } -static )
else ( )
list ( APPEND correctedOtherLibraries ${ lib } )
2014-02-17 13:44:50 +08:00
list ( APPEND otherLibraryNontargets ${ lib } )
2013-12-23 02:01:39 +08:00
endif ( )
endforeach ( )
2014-02-17 13:44:50 +08:00
# Check libraries for conflicting versions built-in to MATLAB
set ( dependentLibraries "" )
if ( NOT "${otherLibraryTargets}" STREQUAL "" )
foreach ( target ${ otherLibraryTargets } )
get_target_property ( dependentLibrariesOne ${ target } INTERFACE_LINK_LIBRARIES )
list ( APPEND dependentLibraries ${ dependentLibrariesOne } )
endforeach ( )
endif ( )
list ( APPEND dependentLibraries ${ otherLibraryNontargets } )
check_conflicting_libraries_internal ( "${dependentLibraries}" )
2013-12-23 02:01:39 +08:00
# Set up generation of module source file
file ( MAKE_DIRECTORY "${generated_files_path}" )
add_custom_command (
O U T P U T $ { g e n e r a t e d _ c p p _ f i l e }
D E P E N D S $ { i n t e r f a c e H e a d e r } w r a p $ { m o d u l e _ l i b r a r y _ t a r g e t } $ { o t h e r L i b r a r y T a r g e t s }
C O M M A N D
w r a p
$ { m o d u l e P a t h }
$ { m o d u l e N a m e }
$ { g e n e r a t e d _ f i l e s _ p a t h }
$ { m a t l a b _ h _ p a t h }
V E R B A T I M
W O R K I N G _ D I R E C T O R Y $ { g e n e r a t e d _ f i l e s _ p a t h } )
# Set up building of mex module
string ( REPLACE ";" " " extraMexFlagsSpaced "${extraMexFlags}" )
string ( REPLACE ";" " " mexFlagsSpaced "${GTSAM_BUILD_MEX_BINARY_FLAGS}" )
add_library ( ${ moduleName } _wrapper MODULE ${ generated_cpp_file } ${ interfaceHeader } )
target_link_libraries ( ${ moduleName } _wrapper ${ correctedOtherLibraries } )
set_target_properties ( ${ moduleName } _wrapper PROPERTIES
O U T P U T _ N A M E " $ { m o d u l e N a m e } _ w r a p p e r "
P R E F I X " "
S U F F I X " . $ { m e x M o d u l e E x t } "
L I B R A R Y _ O U T P U T _ D I R E C T O R Y " $ { c o m p i l e d _ m e x _ m o d u l e s _ r o o t } "
A R C H I V E _ O U T P U T _ D I R E C T O R Y " $ { c o m p i l e d _ m e x _ m o d u l e s _ r o o t } "
R U N T I M E _ O U T P U T _ D I R E C T O R Y " $ { c o m p i l e d _ m e x _ m o d u l e s _ r o o t } "
C L E A N _ D I R E C T _ O U T P U T 1 )
set_property ( TARGET ${ moduleName } _wrapper APPEND_STRING PROPERTY COMPILE_FLAGS " ${extraMexFlagsSpaced} ${mexFlagsSpaced} \" -I ${ MATLAB_ROOT } /extern/include\ " -DMATLAB_MEX_FILE -DMX_COMPAT_32" )
set_property ( TARGET ${ moduleName } _wrapper APPEND PROPERTY INCLUDE_DIRECTORIES ${ extraIncludeDirs } )
# Disable build type postfixes for the mex module - we install in different directories for each build type instead
foreach ( build_type ${ CMAKE_CONFIGURATION_TYPES } )
string ( TOUPPER "${build_type}" build_type_upper )
set_target_properties ( ${ moduleName } _wrapper PROPERTIES ${ build_type_upper } _POSTFIX "" )
endforeach ( )
# Set up platform-specific flags
if ( MSVC )
if ( CMAKE_CL_64 )
set ( mxLibPath "${MATLAB_ROOT}/extern/lib/win64/microsoft" )
else ( )
set ( mxLibPath "${MATLAB_ROOT}/extern/lib/win32/microsoft" )
endif ( )
target_link_libraries ( ${ moduleName } _wrapper "${mxLibPath}/libmex.lib" "${mxLibPath}/libmx.lib" "${mxLibPath}/libmat.lib" )
set_target_properties ( ${ moduleName } _wrapper PROPERTIES LINK_FLAGS "/export:mexFunction" )
set_property ( SOURCE "${generated_cpp_file}" APPEND PROPERTY COMPILE_FLAGS "/bigobj" )
elseif ( APPLE )
set ( mxLibPath "${MATLAB_ROOT}/bin/maci64" )
target_link_libraries ( ${ moduleName } _wrapper "${mxLibPath}/libmex.dylib" "${mxLibPath}/libmx.dylib" "${mxLibPath}/libmat.dylib" )
endif ( )
# Hacking around output issue with custom command
# Deletes generated build folder
add_custom_target ( wrap_ ${ moduleName } _distclean
C O M M A N D c m a k e - E r e m o v e _ d i r e c t o r y $ { g e n e r a t e d _ f i l e s _ p a t h }
C O M M A N D c m a k e - E r e m o v e _ d i r e c t o r y $ { c o m p i l e d _ m e x _ m o d u l e s _ r o o t } )
endfunction ( )
2014-02-19 02:43:54 +08:00
# Internal function that installs a wrap toolbox
2013-12-23 02:01:39 +08:00
function ( install_wrapped_library_internal interfaceHeader )
get_filename_component ( moduleName "${interfaceHeader}" NAME_WE )
set ( generated_files_path "${PROJECT_BINARY_DIR}/wrap/${moduleName}" )
# NOTE: only installs .m and mex binary files (not .cpp) - the trailing slash on the directory name
# here prevents creating the top-level module name directory in the destination.
message ( STATUS "Installing Matlab Toolbox to ${GTSAM_TOOLBOX_INSTALL_PATH}" )
if ( GTSAM_BUILD_TYPE_POSTFIXES )
foreach ( build_type ${ CMAKE_CONFIGURATION_TYPES } )
string ( TOUPPER "${build_type}" build_type_upper )
if ( "${build_type_upper}" STREQUAL "RELEASE" )
set ( build_type_tag "" ) # Don't create release mode tag on installed directory
else ( )
set ( build_type_tag "${build_type}" )
endif ( )
# Split up filename to strip trailing '/' in GTSAM_TOOLBOX_INSTALL_PATH if there is one
get_filename_component ( location "${GTSAM_TOOLBOX_INSTALL_PATH}" PATH )
get_filename_component ( name "${GTSAM_TOOLBOX_INSTALL_PATH}" NAME )
install ( DIRECTORY "${generated_files_path}/" DESTINATION "${location}/${name}${build_type_tag}" CONFIGURATIONS "${build_type}" FILES_MATCHING PATTERN "*.m" )
install ( TARGETS ${ moduleName } _wrapper
L I B R A R Y D E S T I N A T I O N " $ { l o c a t i o n } / $ { n a m e } $ { b u i l d _ t y p e _ t a g } " C O N F I G U R A T I O N S " $ { b u i l d _ t y p e } "
R U N T I M E D E S T I N A T I O N " $ { l o c a t i o n } / $ { n a m e } $ { b u i l d _ t y p e _ t a g } " C O N F I G U R A T I O N S " $ { b u i l d _ t y p e } " )
endforeach ( )
else ( )
install ( DIRECTORY "${generated_files_path}/" DESTINATION ${ GTSAM_TOOLBOX_INSTALL_PATH } FILES_MATCHING PATTERN "*.m" )
install ( TARGETS ${ moduleName } _wrapper
L I B R A R Y D E S T I N A T I O N $ { G T S A M _ T O O L B O X _ I N S T A L L _ P A T H }
R U N T I M E D E S T I N A T I O N $ { G T S A M _ T O O L B O X _ I N S T A L L _ P A T H } )
endif ( )
endfunction ( )
2014-02-19 02:43:54 +08:00
# Internal function to check for libraries installed with MATLAB that may conflict
# and prints a warning to move them if problems occur.
2014-02-17 13:44:50 +08:00
function ( check_conflicting_libraries_internal libraries )
if ( UNIX )
# Set path for matlab's built-in libraries
if ( APPLE )
set ( mxLibPath "${MATLAB_ROOT}/bin/maci64" )
else ( )
if ( CMAKE_CL_64 )
set ( mxLibPath "${MATLAB_ROOT}/bin/glnxa64" )
else ( )
set ( mxLibPath "${MATLAB_ROOT}/bin/glnx86" )
endif ( )
endif ( )
# List matlab's built-in libraries
file ( GLOB matlabLibs RELATIVE "${mxLibPath}" "${mxLibPath}/lib*" )
# Convert to base names
set ( matlabLibNames "" )
foreach ( lib ${ matlabLibs } )
get_filename_component ( libName "${lib}" NAME_WE )
list ( APPEND matlabLibNames "${libName}" )
endforeach ( )
# Get names of link libraries
set ( linkLibNames "" )
foreach ( lib ${ libraries } )
string ( FIND "${lib}" "/" slashPos )
if ( NOT slashPos EQUAL -1 )
# If the name is a path, just get the library name
get_filename_component ( libName "${lib}" NAME_WE )
list ( APPEND linkLibNames "${libName}" )
else ( )
# It's not a path, so see if it looks like a filename
get_filename_component ( ext "${lib}" EXT )
if ( NOT "${ext}" STREQUAL "" )
# It's a filename, so get the base name
get_filename_component ( libName "${lib}" NAME_WE )
list ( APPEND linkLibNames "${libName}" )
else ( )
# It's not a filename so it must be a short name, add the "lib" prefix
list ( APPEND linkLibNames "lib${lib}" )
endif ( )
endif ( )
endforeach ( )
# Remove duplicates
list ( REMOVE_DUPLICATES linkLibNames )
set ( conflictingLibs "" )
foreach ( lib ${ linkLibNames } )
list ( FIND matlabLibNames "${lib}" libPos )
if ( NOT libPos EQUAL -1 )
if ( NOT conflictingLibs STREQUAL "" )
set ( conflictingLibs "${conflictingLibs}, " )
endif ( )
set ( conflictingLibs "${conflictingLibs}${lib}" )
endif ( )
endforeach ( )
if ( NOT "${conflictingLibs}" STREQUAL "" )
message ( WARNING "GTSAM links to the libraries [ ${conflictingLibs} ] on your system, but "
" M A T L A B i s d i s t r i b u t e d w i t h i t s o w n v e r s i o n s o f t h e s e l i b r a r i e s w h i c h m a y c o n f l i c t . "
" I f y o u g e t s t r a n g e e r r o r s o r c r a s h e s w i t h t h e G T S A M M A T L A B w r a p p e r , m o v e t h e s e "
" l i b r a r i e s o u t o f M A T L A B ' s b u i l t - i n l i b r a r y d i r e c t o r y , w h i c h i s $ { m x L i b P a t h } o n "
" y o u r s y s t e m . M A T L A B w i l l u s u a l l y s t i l l w o r k w i t h t h e s e l i b r a r i e s m o v e d a w a y , b u t "
" i f n o t , y o u ' l l h a v e t o c o m p i l e t h e s t a t i c G T S A M M A T L A B w r a p p e r m o d u l e . " )
endif ( )
endif ( )
endfunction ( )
2013-12-23 02:01:39 +08:00
# Helper function to install MATLAB scripts and handle multiple build types where the scripts
# should be installed to all build type toolboxes
function ( install_matlab_scripts source_directory patterns )
set ( patterns_args "" )
foreach ( pattern ${ patterns } )
list ( APPEND patterns_args PATTERN "${pattern}" )
endforeach ( )
if ( GTSAM_BUILD_TYPE_POSTFIXES )
foreach ( build_type ${ CMAKE_CONFIGURATION_TYPES } )
string ( TOUPPER "${build_type}" build_type_upper )
if ( "${build_type_upper}" STREQUAL "RELEASE" )
set ( build_type_tag "" ) # Don't create release mode tag on installed directory
else ( )
set ( build_type_tag "${build_type}" )
endif ( )
# Split up filename to strip trailing '/' in GTSAM_TOOLBOX_INSTALL_PATH if there is one
get_filename_component ( location "${GTSAM_TOOLBOX_INSTALL_PATH}" PATH )
get_filename_component ( name "${GTSAM_TOOLBOX_INSTALL_PATH}" NAME )
install ( DIRECTORY "${source_directory}" DESTINATION "${location}/${name}${build_type_tag}" CONFIGURATIONS "${build_type}" FILES_MATCHING ${ patterns_args } PATTERN ".svn" EXCLUDE )
endforeach ( )
else ( )
install ( DIRECTORY "${source_directory}" DESTINATION "${GTSAM_TOOLBOX_INSTALL_PATH}" FILES_MATCHING ${ patterns_args } PATTERN ".svn" EXCLUDE )
endif ( )
endfunction ( )