275 lines
12 KiB
CMake
275 lines
12 KiB
CMake
# 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/borg/toolbox")
|
|
if(NOT GTSAM_TOOLBOX_INSTALL_PATH)
|
|
set(GTSAM_TOOLBOX_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/borg/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}
|
|
PATHS ${matlab_bin_directories} ENV PATH
|
|
DOC "Command to use for executing mex (if on path, 'mex' will work)"
|
|
NO_SYSTEM_ENVIRONMENT_PATH)
|
|
|
|
|
|
# Function to setup codegen and building of the wrap toolbox
|
|
#
|
|
# params:
|
|
# moduleName : the name of the module, interface file must be called moduleName.h
|
|
# mexFlags : Compilation flags to be passed to the mex compiler
|
|
# modulePath : relative path to module markup header file (called moduleName.h)
|
|
# otherLibraries : list of library targets this should depend on
|
|
# toolboxPath : the directory in which to generate/build wrappers
|
|
# wrap_header_path : path to the installed wrap header
|
|
function(wrap_library_generic moduleName mexFlags modulePath otherLibraries toolbox_path wrap_header_path)
|
|
|
|
set(module_markup_header_file "${moduleName}.h")
|
|
set(module_markup_header_path "${CMAKE_CURRENT_SOURCE_DIR}/${modulePath}/${module_markup_header_file}")
|
|
|
|
# Add wrap cpp file first
|
|
set(mexSources "")
|
|
list(APPEND mexSources ${moduleName}_wrapper.cpp)
|
|
|
|
# Add boost libraries
|
|
string(TOUPPER ${CMAKE_BUILD_TYPE} build_type_toupper)
|
|
if("${build_type_toupper}" STREQUAL "DEBUG")
|
|
list(APPEND otherLibraries ${Boost_SERIALIZATION_LIBRARY_DEBUG} ${Boost_FILESYSTEM_LIBRARY_DEBUG}
|
|
${Boost_SYSTEM_LIBRARY_DEBUG} ${Boost_THREAD_LIBRARY_DEBUG} ${Boost_DATE_TIME_LIBRARY_DEBUG}
|
|
${Boost_REGEX_LIBRARY_DEBUG})
|
|
if(Boost_TIMER_LIBRARY_DEBUG AND NOT GTSAM_DISABLE_NEW_TIMERS) # Only present in Boost >= 1.48.0
|
|
list(APPEND otherLibraries ${Boost_TIMER_LIBRARY_DEBUG} ${Boost_CHRONO_LIBRARY_DEBUG})
|
|
if(GTSAM_MEX_BUILD_STATIC_MODULE)
|
|
list(APPEND otherLibraries -Wl,--no-as-needed -lrt)
|
|
endif()
|
|
endif()
|
|
else()
|
|
list(APPEND otherLibraries ${Boost_SERIALIZATION_LIBRARY_RELEASE} ${Boost_FILESYSTEM_LIBRARY_RELEASE}
|
|
${Boost_SYSTEM_LIBRARY_RELEASE} ${Boost_THREAD_LIBRARY_RELEASE} ${Boost_DATE_TIME_LIBRARY_RELEASE}
|
|
${Boost_REGEX_LIBRARY_RELEASE})
|
|
if(Boost_TIMER_LIBRARY_RELEASE AND NOT GTSAM_DISABLE_NEW_TIMERS) # Only present in Boost >= 1.48.0
|
|
list(APPEND otherLibraries ${Boost_TIMER_LIBRARY_RELEASE} ${Boost_CHRONO_LIBRARY_RELEASE})
|
|
if(GTSAM_MEX_BUILD_STATIC_MODULE)
|
|
list(APPEND otherLibraries -Wl,--no-as-needed -lrt)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# Sort otherLibraries into files and targets, add -shared or -static to other dependency library names
|
|
set(otherLibraryTargets "")
|
|
set(otherLibraryLinks "")
|
|
set(otherLibraryArchives "")
|
|
foreach(lib ${moduleName} ${otherLibraries})
|
|
if(TARGET ${lib})
|
|
list(APPEND otherLibraryTargets ${lib})
|
|
elseif(TARGET ${lib}-shared) # Prefer the shared library if we have both shared and static
|
|
list(APPEND otherLibraryTargets ${lib}-shared)
|
|
elseif(TARGET ${lib}-static)
|
|
list(APPEND otherLibraryTargets ${lib}-static)
|
|
else()
|
|
if(${lib} MATCHES "^.+\\.a$")
|
|
list(APPEND otherLibraryArchives ${lib})
|
|
else()
|
|
list(APPEND otherLibraryLinks ${lib})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
# Get path to libraries with current build type
|
|
foreach(target ${otherLibraryTargets})
|
|
if(GTSAM_MEX_BUILD_STATIC_MODULE)
|
|
# If building the wrapper statically, add the target's sources to the mex sources
|
|
get_target_property(librarySources ${target} SOURCES)
|
|
list(APPEND mexSources ${librarySources})
|
|
else()
|
|
# If not building wrapper staticically, link to the target library
|
|
get_target_property(libraryFile ${target} LOCATION_${build_type_toupper})
|
|
get_target_property(targetType ${target} TYPE)
|
|
if(WIN32 AND NOT targetType STREQUAL STATIC_LIBRARY)
|
|
# On Windows with a shared library, we link to the import library file
|
|
get_filename_component(libraryDir ${libraryFile} PATH)
|
|
get_filename_component(libraryName ${libraryFile} NAME_WE)
|
|
get_filename_component(oneUpDir ${libraryDir} NAME)
|
|
string(TOUPPER "${oneUpDir}" oneUpDir)
|
|
if("${oneUpDir}" STREQUAL BIN OR "${oneUpDir}" STREQUAL LIB)
|
|
# One level up is 'bin' or 'lib' so we do not have an extra
|
|
# subdirectory for the build configuration.
|
|
set(libraryFile "${libraryDir}/../lib/${libraryName}.lib")
|
|
else()
|
|
# One level up was neither 'bin' nor 'lib' so assume we also
|
|
# have a subdirectory for the build configuration.
|
|
set(libraryFile "${libraryDir}/../../lib/${build_type_toupper}/${libraryName}.lib")
|
|
endif()
|
|
endif()
|
|
list(APPEND otherLibraryLinks ${libraryFile})
|
|
endif()
|
|
endforeach()
|
|
|
|
# Bad hack - if static wrapper and this is GTSAM, add colamd to the include path
|
|
if(GTSAM_MEX_BUILD_STATIC_MODULE AND (${moduleName} STREQUAL "gtsam" OR ${moduleName} STREQUAL "gtsam_unstable"))
|
|
list(APPEND mexFlags
|
|
"-I${PROJECT_SOURCE_DIR}/gtsam/3rdparty/CCOLAMD/Include" "-I${PROJECT_SOURCE_DIR}/gtsam/3rdparty/UFconfig")
|
|
endif()
|
|
|
|
# If using Boost shared libs, set up auto linking for shared libs
|
|
if(NOT Boost_USE_STATIC_LIBS)
|
|
list(APPEND mexFlags "-DBOOST_ALL_DYN_LINK")
|
|
endif()
|
|
|
|
# Add the CXXFLAGS from building the library
|
|
if(MSVC)
|
|
set(compile_flag_var "COMPFLAGS")
|
|
set(link_flag_var "LINKFLAGS")
|
|
set(cxx_flags_extra "/bigobj")
|
|
else()
|
|
set(compile_flag_var "CXXFLAGS")
|
|
set(link_flag_var "LDFLAGS")
|
|
set(cxx_flags_extra "")
|
|
endif()
|
|
list(APPEND mexFlags "${compile_flag_var}=$${compile_flag_var} ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${build_type_toupper}} ${cxx_flags_extra}")
|
|
|
|
# If building a static module on UNIX, extract dependent .a libraries and add their .o files
|
|
if(UNIX AND GTSAM_MEX_BUILD_STATIC_MODULE)
|
|
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/wrap/external_archives)
|
|
foreach(archive ${otherLibraryArchives})
|
|
get_filename_component(archive_name ${archive} NAME_WE)
|
|
set(extraction_dir ${CMAKE_BINARY_DIR}/wrap/external_archives/${archive_name})
|
|
file(MAKE_DIRECTORY ${extraction_dir})
|
|
# Extract archive
|
|
execute_process(
|
|
COMMAND ar x ${archive}
|
|
WORKING_DIRECTORY ${extraction_dir})
|
|
# Get list of .o's in archive
|
|
execute_process(
|
|
COMMAND ar t ${archive}
|
|
OUTPUT_VARIABLE object_files OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
string(REPLACE "\n" ";" object_list ${object_files})
|
|
set(object_list_absolute "")
|
|
foreach(object ${object_list})
|
|
list(APPEND object_list_absolute ${extraction_dir}/${object})
|
|
endforeach()
|
|
list(APPEND mexSources ${object_list_absolute})
|
|
endforeach()
|
|
set(otherLibraryArchives "")
|
|
endif()
|
|
|
|
# Add libraries to command line
|
|
string(REPLACE ";" " " otherLibraryArchivesSpaced "${otherLibraryArchives}")
|
|
list(APPEND mexFlags "${link_flag_var}=$${link_flag_var} ${otherLibraryArchivesSpaced}")
|
|
list(APPEND mexFlags ${otherLibraryLinks})
|
|
|
|
# Add -g if debug mode
|
|
if(${build_type_toupper} STREQUAL DEBUG OR ${build_type_toupper} STREQUAL RELWITHDEBINFO)
|
|
list(APPEND mexFlags -g)
|
|
endif()
|
|
|
|
# Verbose mex - print mex compilation flags to help notice flag problems
|
|
list(APPEND mexFlags -v)
|
|
|
|
# Add sources
|
|
set(mexSourcesFiltered "")
|
|
foreach(src ${mexSources})
|
|
if(src MATCHES "^.+\\.cpp$" OR src MATCHES "^.+\\.c$" OR src MATCHES "^.+\\.o$")
|
|
list(APPEND mexSourcesFiltered ${src})
|
|
endif()
|
|
endforeach()
|
|
set(mexFlags ${mexSourcesFiltered} ${mexFlags})
|
|
|
|
string(REPLACE ";" "' '" mexFlagsForDisplay "${mexFlags}")
|
|
message(STATUS "Building Matlab Wrapper, mexFlags: [ '${mexFlagsForDisplay}' ]")
|
|
|
|
# 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
|
|
|
|
# Code generation command
|
|
# FIXME: doesn't get cleaned properly because cmake doesn't track the dependency
|
|
# TODO: convert to a custom_command with output specified
|
|
get_target_property(wrap_LOCATION wrap LOCATION_${CMAKE_BUILD_TYPE})
|
|
add_custom_target(wrap_${moduleName}
|
|
ALL # Forces wrap to always be run, but no files are touched if they don't change
|
|
COMMAND
|
|
${wrap_LOCATION}
|
|
${CMAKE_CURRENT_SOURCE_DIR}/${modulePath}
|
|
${moduleName}
|
|
${toolbox_path}
|
|
${wrap_header_path}
|
|
VERBATIM)
|
|
add_dependencies(wrap_${moduleName} wrap ${module_markup_header_path})
|
|
|
|
# Hacking around output issue with custom command
|
|
# Deletes generated build folder
|
|
add_custom_target(wrap_${moduleName}_distclean
|
|
COMMAND
|
|
cmake -E remove_directory ${toolbox_path})
|
|
|
|
# Make building mex binaries a part of the all (and install) target
|
|
set(build_all "ALL")
|
|
|
|
# If building wrapper statically, we compile all the library sources
|
|
# with mex, so need no extra dependencies, but if not building statically,
|
|
# we depend on the libraries since we will link to them.
|
|
if(GTSAM_MEX_BUILD_STATIC_MODULE)
|
|
set(wrap_build_dependencies "")
|
|
else()
|
|
set(wrap_build_dependencies ${moduleTarget} ${otherLibraryTargets})
|
|
endif()
|
|
|
|
# Actual build target for building mex files
|
|
add_custom_target(wrap_${moduleName}_build ${build_all}
|
|
COMMAND "${MEX_COMMAND}" ${mexFlags}
|
|
VERBATIM
|
|
WORKING_DIRECTORY ${toolbox_path})
|
|
add_dependencies(wrap_${moduleName}_build wrap_${moduleName} ${wrap_build_dependencies})
|
|
|
|
endfunction(wrap_library_generic)
|
|
|
|
# Function to setup codegen, building and installation of the wrap toolbox
|
|
# This wrap setup function assumes that the toolbox will be installed directly,
|
|
# with predictable matlab.h sourcing. Use this version when the toolbox will be used
|
|
# from the installed version, rather than in place.
|
|
# Assumes variable GTSAM_WRAP_HEADER_PATH has been set
|
|
# params:
|
|
# moduleName : the name of the module, interface file must be called moduleName.h
|
|
# mexFlags : Compilation flags to be passed to the mex compiler
|
|
# modulePath : relative path to module markup header file (called moduleName.h)
|
|
# otherLibraries : list of library targets this should depend on
|
|
function(wrap_library moduleName mexFlags modulePath otherLibraries)
|
|
# Toolbox generation path goes in build folder
|
|
set(toolbox_base_path ${CMAKE_BINARY_DIR}/wrap)
|
|
set(toolbox_path ${toolbox_base_path}/${moduleName})
|
|
|
|
# Call generic version of function
|
|
wrap_library_generic("${moduleName}" "${mexFlags}" "${modulePath}" "${otherLibraries}" "${toolbox_path}" "${GTSAM_WRAP_HEADER_PATH}")
|
|
|
|
# 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}")
|
|
install(DIRECTORY ${toolbox_path}/ DESTINATION ${GTSAM_TOOLBOX_INSTALL_PATH} FILES_MATCHING PATTERN "*.m")
|
|
install(DIRECTORY ${toolbox_path}/ DESTINATION ${GTSAM_TOOLBOX_INSTALL_PATH} FILES_MATCHING PATTERN "*.mex*")
|
|
endfunction(wrap_library)
|