From a8e7e859e58a7b6225ad8c04a09230c1f3a43ef4 Mon Sep 17 00:00:00 2001 From: Diego Ferigo Date: Fri, 9 Oct 2020 17:51:40 +0200 Subject: [PATCH] Refactor CMake project for Matlab bindings --- bindings/matlab/CMakeLists.txt | 228 +++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 95 deletions(-) diff --git a/bindings/matlab/CMakeLists.txt b/bindings/matlab/CMakeLists.txt index 6f2c80a1eea..43772a12131 100644 --- a/bindings/matlab/CMakeLists.txt +++ b/bindings/matlab/CMakeLists.txt @@ -1,38 +1,10 @@ -# As Matlab support is higly experimental for now in swig, we split the binding generation in two phases: -# * Generation of the .cxx code, left to the author of the library that needs to have a recent (non-standard) swig +# As Matlab support is highly experimental for now in swig, we split the binding generation in two phases: +# +# * Generation of the .cxx code, left to the author of the library that needs to have a recent (non-standard) swig. # * Compilation of the .cxx, that is left to the user that compiles the library. -# For doing this we split the traditional swig_add_module macro in two macro: one for generating the wrapper and one -# for compiling it. As soon as upstream swig distributed by the distro gains Matlab support, we can drop this workaround -macro(SWIG_GENERATE_MODULE name language) - SWIG_MODULE_INITIALIZE(${name} ${language}) - set(swig_dot_i_sources) - set(swig_other_sources) - foreach(it ${ARGN}) - if(${it} MATCHES ".*\\.i$") - set(swig_dot_i_sources ${swig_dot_i_sources} "${it}") - else() - set(swig_other_sources ${swig_other_sources} "${it}") - endif() - endforeach() - - set(swig_generated_sources) - foreach(it ${swig_dot_i_sources}) - SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it}) - set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}") - endforeach() -endmacro() - -macro(SWIG_COMPILE_MODULE_MEX name language) - SWIG_MODULE_INITIALIZE(${name} ${language}) - matlab_add_mex(NAME ${SWIG_MODULE_${name}_REAL_NAME} - MODULE - SRC ${swig_generated_sources} - ${swig_other_sources}) - # Avoid the "d" suffix for mex files as it prevents the bindings to call the mex file correctly - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES DEBUG_POSTFIX "") -endmacro() # Options related to installation directories +# # If you want to install bindings for packaging you may need to install # following several rules (for example placing the .m files in share # and the compiled libraries in some architecture-specific directory) @@ -41,13 +13,19 @@ endmacro() # the bindings for a developer that compiled the library from source: # to use the octave bindings just add /octave to the octave path, # to use the matlab bindings just add /mex to the matlab path. -set(IDYNTREE_INSTALL_MATLAB_LIBDIR "mex" CACHE STRING "Location (relative to the install prefix) in which the Matlab mex libraries are installed.") +set(IDYNTREE_INSTALL_MATLAB_LIBDIR "mex" CACHE + STRING "Location (relative to the install prefix) in which the Matlab mex libraries are installed.") +set(IDYNTREE_INSTALL_MATLAB_MFILESDIR "mex" CACHE + STRING "Location (relative to the install prefix) in which the Matlab .m files are installed.") +set(IDYNTREE_INSTALL_OCTAVE_LIBDIR "octave" CACHE + STRING "Location (relative to the install prefix) in which the Octave mex libraries are installed.") +set(IDYNTREE_INSTALL_OCTAVE_MFILESDIR "octave" CACHE + STRING "Location (relative to the install prefix) in which the Octave .m files are installed.") + +# Mark the cached options as advanced mark_as_advanced(IDYNTREE_INSTALL_MATLAB_LIBDIR) -set(IDYNTREE_INSTALL_MATLAB_MFILESDIR "mex" CACHE STRING "Location (relative to the install prefix) in which the Matlab .m files are installed.") mark_as_advanced(IDYNTREE_INSTALL_MATLAB_MFILESDIR) -set(IDYNTREE_INSTALL_OCTAVE_LIBDIR "octave" CACHE STRING "Location (relative to the install prefix) in which the Octave mex libraries are installed.") mark_as_advanced(IDYNTREE_INSTALL_OCTAVE_LIBDIR) -set(IDYNTREE_INSTALL_OCTAVE_MFILESDIR "octave" CACHE STRING "Location (relative to the install prefix) in which the Octave .m files are installed.") mark_as_advanced(IDYNTREE_INSTALL_OCTAVE_MFILESDIR) # The name of the generated source named is @@ -58,7 +36,7 @@ set(sourcename iDynTreeMATLAB_wrap) # The name of the generated source should instead match the one # used by SWIG when generating the .m file. # See https://github.com/jaeandersson/swig/issues/44 for more details -set(mexname iDynTreeMEX) +set(mexname iDynTreeMEX) # Directory in which the bindings are generated set(MEX_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/autogenerated) @@ -67,97 +45,157 @@ set(MEX_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/autogenerated) set(HIGH_LEVEL_WRAPPERS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/+iDynTreeWrappers) set(MATLAB_WRAPPERS_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -# Generate SWIG wrapper -if(IDYNTREE_GENERATE_MATLAB) - # generate the wrapper - set(swig_generated_sources) - set_source_files_properties(../iDynTree.i PROPERTIES CPLUSPLUS ON) - # generate files in the source directory, so we can commit it - set(CMAKE_SWIG_OUTDIR ${MEX_BINDINGS_SOURCE_DIR}) - #set(CMAKE_SWIG_FLAGS "-redirectoutput") - set(SWIG_MODULE_${mexname}_EXTRA_DEPS ${IDYNTREE_SWIG_DEPENDS_I_FILES}) - swig_generate_module(${mexname} matlab ../iDynTree.i) - set_source_files_properties(${MEX_BINDINGS_SOURCE_DIR}/${sourcename}.cxx PROPERTIES GENERATED 1) -endif() - # use previously generated files set(swig_generated_sources ${MEX_BINDINGS_SOURCE_DIR}/${sourcename}.cxx) set(swig_other_sources) -# Set the generated mex name to be iDynTreeMEX, as it is the default one used by SWIG while generating bindings +# Set the .i files to generate the bindings +set(iDynTree_SWIG_I_FILE ../iDynTree.i) +set(iDynTree_SWIG_I_OTHER + ../ignore.i + ../joints.i + ../sensors.i + matlab.i + matlab_mat4x4vec.i + matlab_matvec.i + matlab_spatialvec.i) + +# Generate SWIG wrapper +macro(GET_LIBRARY_FROM_SWIG_WRAPPER i_main_file i_other_files target_name generate outputdir) + + set_property(SOURCE ${i_main_file} PROPERTY CPLUSPLUS ON) + set(CMAKE_SWIG_OUTDIR ${outputdir}) + + if(${generate} AND NOT bindings_have_been_generated) + find_package(SWIG) + set(bindings_have_been_generated TRUE) + swig_add_library(${target_name} LANGUAGE matlab SOURCES ${i_main_file}) + # Add the dependency to other .i files + set_property( + TARGET ${target_name} + PROPERTY SWIG_DEPENDS ${i_other_files}) + else() + add_library(${target_name} MODULE ${swig_generated_sources}) + set_target_properties(${target_name} PROPERTIES DEBUG_POSTFIX "") + set_source_files_properties(${swig_generated_sources} PROPERTIES GENERATED 1) + endif() + +endmacro() + +# ============== +# COMPILE MATLAB +# ============== + if(IDYNTREE_USES_MATLAB) find_package(Matlab REQUIRED MX_LIBRARY MAIN_PROGRAM) - swig_compile_module_mex(${mexname} matlab) - swig_link_libraries(${mexname} ${Matlab_LIBRARIES} ${IDYNTREE_LIBRARIES} idyntree-core) - target_include_directories(${mexname} PUBLIC ${Matlab_INCLUDE_DIRS}) + set(target_name ${mexname}) + + get_library_from_swig_wrapper( + ${iDynTree_SWIG_I_FILE} + "${iDynTree_SWIG_I_OTHER}" + ${target_name} + ${IDYNTREE_GENERATE_MATLAB} + ${MEX_BINDINGS_SOURCE_DIR}) + + set_target_properties(${target_name} + PROPERTIES OUTPUT_NAME ${mexname} + PREFIX "" + SUFFIX .mex) + + target_link_libraries(${target_name} ${IDYNTREE_LIBRARIES} idyntree-core) + target_include_directories(${target_name} PUBLIC ${Matlab_INCLUDE_DIRS}) + set_target_properties(${target_name} PROPERTIES PREFIX "" SUFFIX .${Matlab_MEX_EXTENSION}) - set_target_properties(${mexname} PROPERTIES PREFIX "" SUFFIX .${Matlab_MEX_EXTENSION}) # entry point in the mex file + taking care of visibility and symbol clashes. if(WIN32) - set_target_properties(${mexname} + set_target_properties(${target_name} PROPERTIES DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") endif() # Install the generated front-end to ${CMAKE_INSTALL_PREFIX}/mex - install(DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) - install(TARGETS ${mexname} DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_LIBDIR}) + install( + DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) + install( + FILES + ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m + ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m + ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m + DESTINATION + ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) + install( + TARGETS ${target_name} + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_LIBDIR}) # Install the high-level-matlab-wrappers - install(DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR} DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) + install( + DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR} + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) # Install the matlab-visualization-external-functions - install(FILES ${IDYNTREE_INTERNAL_MESH2TRI_PATH}/mesh2tri.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) - - #On new versions of Clang, MATLAB requires C++11. - #I enable it on all Clangs - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - if (${CMAKE_GENERATOR} MATCHES "Xcode") - #this should set explictly the option in xcode. Unfortunately it does not work. - set(XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "C++11") - endif(${CMAKE_GENERATOR} MATCHES "Xcode") - endif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + install( + FILES ${IDYNTREE_INTERNAL_MESH2TRI_PATH}/mesh2tri.m + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) + endif() +# ============== +# COMPILE OCTAVE +# ============== + if(IDYNTREE_USES_OCTAVE) - find_package(Octave REQUIRED) - if ("${OCTAVE_VERSION_STRING}" VERSION_LESS 4.0) - message(FATAL_ERROR "Octave mex-based bindings required at least Octave version 4.0 or greater.") - endif () - - # Compile MEX file - add_library(idyntreeOctaveMex MODULE ${swig_generated_sources} ${swig_other_sources}) - target_include_directories(idyntreeOctaveMex PUBLIC ${OCTAVE_INCLUDE_DIRS}) + find_package(Octave 4.0 REQUIRED) + + set(target_name idyntreeOctaveMex) + + # Get the target + get_library_from_swig_wrapper( + ${iDynTree_SWIG_I_FILE} + "${iDynTree_SWIG_I_OTHER}" + ${target_name} + ${IDYNTREE_GENERATE_MATLAB} + ${MEX_BINDINGS_SOURCE_DIR}) + + target_include_directories(${target_name} PUBLIC ${OCTAVE_INCLUDE_DIRS}) + if(APPLE) - target_link_libraries(idyntreeOctaveMex ${iDynTree_LIBRARIES}) - set_target_properties(idyntreeOctaveMex PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + target_link_libraries(${target_name} ${iDynTree_LIBRARIES}) + set_target_properties(${target_name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") else() - target_link_libraries(idyntreeOctaveMex ${OCTAVE_LIBRARIES} ${iDynTree_LIBRARIES}) + target_link_libraries(${target_name} ${OCTAVE_LIBRARIES} ${iDynTree_LIBRARIES}) endif() - set_target_properties(idyntreeOctaveMex - PROPERTIES OUTPUT_NAME "iDynTreeMEX" + + set_target_properties(${target_name} + PROPERTIES OUTPUT_NAME ${mexname} PREFIX "" SUFFIX .mex) - install(TARGETS idyntreeOctaveMex DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_LIBDIR}) - # Install the generated front-end to ${CMAKE_INSTALL_PREFIX}/mex - install(DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) - install(FILES ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) + # Install the target + install( + TARGETS ${target_name} + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_LIBDIR}) + + # Install the generated front-end to ${CMAKE_INSTALL_PREFIX}/octave + install( + DIRECTORY ${MEX_BINDINGS_SOURCE_DIR}/+iDynTree + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) + install( + FILES + ${MEX_BINDINGS_SOURCE_DIR}/SwigGet.m + ${MEX_BINDINGS_SOURCE_DIR}/SwigRef.m + ${MEX_BINDINGS_SOURCE_DIR}/SwigMem.m + DESTINATION + ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_OCTAVE_MFILESDIR}) # Install the high-level-matlab-wrappers - install(DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR} DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) + install( + DIRECTORY ${HIGH_LEVEL_WRAPPERS_SOURCE_DIR} + DESTINATION ${CMAKE_INSTALL_PREFIX}/${IDYNTREE_INSTALL_MATLAB_MFILESDIR}) endif() # if compile tests compile also matlab/octave tests