Browse Source

fix mosek to work with 9.2; fix mosek dynamic link via cmake

Alec Jacobson 5 years ago
parent
commit
b35d97472d

+ 1 - 0
cmake/FindMOSEK.cmake

@@ -12,6 +12,7 @@ set(SEARCH_PATHS
   ${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/ 
   ${CMAKE_SOURCE_DIR}/mosek/9.2/tools/platform/osx64x86/ 
   /usr/local/mosek/7/tools/platform/osx64x86/
   /usr/local/mosek/7/tools/platform/osx64x86/
   /usr/local/mosek/8/tools/platform/osx64x86/
   /usr/local/mosek/8/tools/platform/osx64x86/
+  /usr/local/mosek/9.2/tools/platform/osx64x86/
   /opt/mosek/7/tools/platform/linux64x86/
   /opt/mosek/7/tools/platform/linux64x86/
 )
 )
 
 

+ 151 - 0
cmake/OSXFixDylibReferences.cmake

@@ -0,0 +1,151 @@
+# OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending
+# on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the
+# library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of
+# FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes
+# the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This
+# helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries.
+#
+# Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute
+# name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one
+# in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the
+# program (not recommended).
+#
+# Author: Siddhartha Chaudhuri, 2009.
+#
+
+# Set the minimum required CMake version
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+# See cmake --help-policy CMP0011 for details on this one
+IF(POLICY CMP0011)
+  CMAKE_POLICY(SET CMP0011 NEW)
+ENDIF(POLICY CMP0011)
+
+# See cmake --help-policy CMP0026 for details on this one
+IF(POLICY CMP0026)
+  CMAKE_POLICY(SET CMP0026 NEW)
+ENDIF(POLICY CMP0026)
+
+# See cmake --help-policy CMP0045 for details on this one
+IF(POLICY CMP0045)
+  CMAKE_POLICY(SET CMP0045 NEW)
+ENDIF(POLICY CMP0045)
+
+MACRO(OSX_FIX_DYLIB_REFERENCES target libraries)
+
+  IF(APPLE)
+    SET(OFIN_${target}_RPATHS )
+
+    FOREACH(OFIN_${target}_Library ${libraries})
+      IF(${OFIN_${target}_Library} MATCHES "[.]dylib$"
+         OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+")
+
+        # Resolve symlinks and get absolute location
+        GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE)
+
+        # Get the baked install name of the library
+        EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute}
+                        OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput
+                        OUTPUT_STRIP_TRAILING_WHITESPACE)
+        STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput})
+        SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput)
+        LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName)
+
+        IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/")
+
+          # Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left
+          # will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g.
+          # "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one
+          # is correct.
+
+          # Typically, the rpath to a library within a framework looks like this:
+          # @rpath/A.framework/Versions/5/libFoo.dylib
+          #
+          # Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for
+          # it in the library's actual path. Everything before this location will be put in the rpath.
+          SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName})
+          SET(OFIN_${target}_RpathFirstChild )
+          WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
+            GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild  ${OFIN_${target}_PathPrefix} NAME)
+            GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix       ${OFIN_${target}_PathPrefix} PATH)
+
+            IF(NOT OFIN_${target}_PathPrefix)  # should never happen but just in case
+              BREAK()
+            ENDIF(NOT OFIN_${target}_PathPrefix)
+
+            IF(OFIN_${target}_PathPrefix STREQUAL "/")  # should never happen but just in case
+              BREAK()
+            ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
+          ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
+
+          IF(OFIN_${target}_RpathFirstChild)
+            SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute})
+            SET(OFIN_${target}_PathUnit )
+            WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
+              GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit    ${OFIN_${target}_PathPrefix} NAME)
+              GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix  ${OFIN_${target}_PathPrefix} PATH)
+
+              IF(NOT OFIN_${target}_PathPrefix)
+                BREAK()
+              ENDIF(NOT OFIN_${target}_PathPrefix)
+
+              IF(OFIN_${target}_PathPrefix STREQUAL "/")
+                BREAK()
+              ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
+            ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
+
+            IF(OFIN_${target}_PathPrefix)
+              SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}")
+            ENDIF(OFIN_${target}_PathPrefix)
+          ENDIF(OFIN_${target}_RpathFirstChild)
+
+          # Add the directory containing the library
+          GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH)
+          SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}")
+
+          # Add paths specified as library search prefixes
+          FOREACH(prefix ${CMAKE_PREFIX_PATH})
+            SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}")
+            SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib")
+          ENDFOREACH()
+
+        ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]")  # just a relative path
+
+          # Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or
+          # by editing the rpath
+
+          # -- handle the case when the actual filename is baked in
+          GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME)
+          ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                             COMMAND install_name_tool
+                             ARGS -change
+                                  ${OFIN_${target}_LibraryFilename}
+                                  ${OFIN_${target}_LibraryAbsolute}
+                                  $<TARGET_FILE:${target}>)
+
+          # -- handle the case when the install name is baked in
+          ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                             COMMAND install_name_tool
+                             ARGS -change
+                                  ${OFIN_${target}_LibraryInstallName}
+                                  ${OFIN_${target}_LibraryAbsolute}
+                                  $<TARGET_FILE:${target}>)
+        ENDIF()
+
+      ENDIF()
+    ENDFOREACH(OFIN_${target}_Library)
+
+    # Add the collected rpaths
+    IF(OFIN_${target}_RPATHS)
+      LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS)
+
+      FOREACH(rpath ${OFIN_${target}_RPATHS})
+        ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
+                           COMMAND bash
+                           ARGS -c "install_name_tool -add_rpath '${rpath}' '$<TARGET_FILE:${target}>' > /dev/null 2>&1 || true"
+                           VERBATIM)
+      ENDFOREACH()
+    ENDIF()
+  ENDIF()
+
+ENDMACRO(OSX_FIX_DYLIB_REFERENCES)

+ 4 - 0
include/igl/mosek/mosek_linprog.cpp

@@ -140,7 +140,9 @@ IGL_INLINE bool igl::mosek::mosek_linprog(
   switch(solsta)
   switch(solsta)
   {
   {
     case MSK_SOL_STA_OPTIMAL:   
     case MSK_SOL_STA_OPTIMAL:   
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_OPTIMAL:
     case MSK_SOL_STA_NEAR_OPTIMAL:
+#endif
       x.resize(n);
       x.resize(n);
       /* Request the basic solution. */ 
       /* Request the basic solution. */ 
       MSK_getxx(task,MSK_SOL_BAS,x.data()); 
       MSK_getxx(task,MSK_SOL_BAS,x.data()); 
@@ -148,8 +150,10 @@ IGL_INLINE bool igl::mosek::mosek_linprog(
       break;
       break;
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
+#endif
       //printf("Primal or dual infeasibility certificate found.\n");
       //printf("Primal or dual infeasibility certificate found.\n");
       break;
       break;
     case MSK_SOL_STA_UNKNOWN:
     case MSK_SOL_STA_UNKNOWN:

+ 18 - 17
include/igl/mosek/mosek_quadprog.cpp

@@ -164,34 +164,27 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
     // Set constant bounds on variable j
     // Set constant bounds on variable j
     if(lx[j] == ux[j])
     if(lx[j] == ux[j])
     {
     {
+#if MSK_VERSION_MAJOR <=8
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_FX,lx[j],ux[j]));
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_FX,lx[j],ux[j]));
+#else
+      mosek_guarded(MSK_putvarbound(task,j,MSK_BK_FX,lx[j],ux[j]));
+#endif
     }else
     }else
     {
     {
+#if MSK_VERSION_MAJOR <=8
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_RA,lx[j],ux[j]));
       mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_RA,lx[j],ux[j]));
+#else
+      mosek_guarded(MSK_putvarbound(task,j,MSK_BK_RA,lx[j],ux[j]));
+#endif
     }
     }
 
 
     if(m>0)
     if(m>0)
     {
     {
       // Input column j of A
       // Input column j of A
 #if MSK_VERSION_MAJOR >= 7
 #if MSK_VERSION_MAJOR >= 7
-      mosek_guarded(
-        MSK_putacol(
-          task,
-          j,
-          Acp[j+1]-Acp[j],
-          &Ari[Acp[j]],
-          &Av[Acp[j]])
-        );
+      mosek_guarded( MSK_putacol( task, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]]));
 #elif MSK_VERSION_MAJOR == 6
 #elif MSK_VERSION_MAJOR == 6
-      mosek_guarded(
-        MSK_putavec(
-          task,
-          MSK_ACC_VAR,
-          j,
-          Acp[j+1]-Acp[j],
-          &Ari[Acp[j]],
-          &Av[Acp[j]])
-        );
+      mosek_guarded( MSK_putavec( task, MSK_ACC_VAR, j, Acp[j+1]-Acp[j], &Ari[Acp[j]], &Av[Acp[j]]));
 #endif
 #endif
     }
     }
   }
   }
@@ -200,7 +193,11 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
   for(int i = 0;i<m;i++)
   for(int i = 0;i<m;i++)
   {
   {
     // put bounds  on constraints
     // put bounds  on constraints
+#if MSK_VERSION_MAJOR <=8
     mosek_guarded(MSK_putbound(task,MSK_ACC_CON,i,MSK_BK_RA,lc[i],uc[i]));
     mosek_guarded(MSK_putbound(task,MSK_ACC_CON,i,MSK_BK_RA,lc[i],uc[i]));
+#else
+    mosek_guarded(MSK_putconbound(task,i,MSK_BK_RA,lc[i],uc[i]));
+#endif
   }
   }
 
 
   // Input Q for the objective (REMEMBER Q SHOULD ONLY BE LOWER TRIANGLE)
   // Input Q for the objective (REMEMBER Q SHOULD ONLY BE LOWER TRIANGLE)
@@ -243,7 +240,9 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
   switch(solsta)
   switch(solsta)
   {
   {
     case MSK_SOL_STA_OPTIMAL:   
     case MSK_SOL_STA_OPTIMAL:   
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_OPTIMAL:
     case MSK_SOL_STA_NEAR_OPTIMAL:
+#endif
       MSK_getsolutionslice(task,MSK_SOL_ITR,MSK_SOL_ITEM_XX,0,n,&x[0]);
       MSK_getsolutionslice(task,MSK_SOL_ITR,MSK_SOL_ITEM_XX,0,n,&x[0]);
       //printf("Optimal primal solution\n");
       //printf("Optimal primal solution\n");
       //for(size_t j=0; j<n; ++j)
       //for(size_t j=0; j<n; ++j)
@@ -254,8 +253,10 @@ IGL_INLINE bool igl::mosek::mosek_quadprog(
       break;
       break;
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_DUAL_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
     case MSK_SOL_STA_PRIM_INFEAS_CER:
+#if MSK_VERSION_MAJOR <= 8
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
     case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
+#endif
       //printf("Primal or dual infeasibility certificate found.\n");
       //printf("Primal or dual infeasibility certificate found.\n");
       break;
       break;
     case MSK_SOL_STA_UNKNOWN:
     case MSK_SOL_STA_UNKNOWN:

+ 5 - 0
tests/CMakeLists.txt

@@ -52,6 +52,11 @@ if(LIBIGL_WITH_MOSEK)
   target_sources(libigl_tests PRIVATE ${TEST_SRC_FILES} ${TEST_INC_FILES})
   target_sources(libigl_tests PRIVATE ${TEST_SRC_FILES} ${TEST_INC_FILES})
 
 
   target_link_libraries(libigl_tests PUBLIC igl::mosek)
   target_link_libraries(libigl_tests PUBLIC igl::mosek)
+  # fix mosek
+  IF(APPLE)
+    INCLUDE(../cmake/OSXFixDylibReferences.cmake)
+    OSX_FIX_DYLIB_REFERENCES(libigl_tests "${MOSEK_LIBRARIES}")
+  ENDIF()
 endif()
 endif()
 
 
 if(LIBIGL_WITH_CGAL)
 if(LIBIGL_WITH_CGAL)