astamm / riot

riot: R Inputs/Outputs for Tractography
https://astamm.github.io/riot/
Other
4 stars 1 forks source link

Detect existing vtk installation #6

Open Enchufa2 opened 2 years ago

Enchufa2 commented 2 years ago

Compiling vtk is a huge undertaking, but there are Linux distributions that already have it in their official repos (e.g., Fedora). Would it be possible to detect an existing installation and avoid the compilation altogether?

astamm commented 2 years ago

Thanks for reaching out. I agree with you although I only compile a minimalistic version of VTK to get readers and writers for vtk and VTP formats. I'll give it some more thoughts for future versions.

astamm commented 1 year ago

Would pkgconfig auto detect an already existing VTK build up on those Linux systems?

Enchufa2 commented 1 year ago

I don't think that VTK ships any pc files. cmake does have a module to find VTK. Or you could just check for the necessary files in standard locations. Which libraries and headers does riot need?

astamm commented 1 year ago

riot needs to be able to link to the following:

-lvtkIOXML -lvtkIOXMLParser -lvtkIOCore -lvtkIOLegacy \
    -lvtkCommonExecutionModel -lvtkCommonDataModel -lvtkCommonTransforms \
    -lvtkCommonMath -lvtkCommonMisc -lvtkCommonSystem -lvtkCommonCore \
    -lvtkdoubleconversion -lvtkexpat -lvtklz4 -lvtklzma \
    -lvtkpugixml -lvtksys -lvtkzlib
Enchufa2 commented 1 year ago

I see that you already require cmake for building VTK, so you could use it for finding VTK. According to this, find_package(VTK) does the heavy lifting. And here there are examples of finding specific components.

Enchufa2 commented 1 year ago

BTW, TinyXML2 is also part of Fedora. So another find_package(TinyXML2) should detect it too.

astamm commented 1 year ago

Thanks! I use cmake for building VTK. I have no CMakeLists.txt anywhere. Where would you suggest I add find_package(VTK) then?

Enchufa2 commented 1 year ago

The idea would be to add a src/CMakeLists.txt file, then call cmake from configure or src/Makevars. There seems to be some packages using this approach. One example here.

astamm commented 1 year ago

It might be a good idea. Otherwise it boils down to looking into usr/local/, doesn't it?

Enchufa2 commented 1 year ago

Nope, it's not that easy, because each Linux distribution has a preferred path for libraries. Fedora puts everything under /usr/lib64. But e.g. Ubuntu has a very different path (something like /usr/lib/x86_64-...). So if cmake does this for you, it's much much easier.

astamm commented 1 year ago

I have a first draft of the CMakeLists.txt but when running the R CMD INSTALL, it fails to find the VTK headers. Are you familiar with this? Can you help please?

cmake_minimum_required(VERSION 3.12)
project(riot)
set(CMAKE_MODULE_PATH
  ${CMAKE_SOURCE_DIR}/cmake
  ${CMAKE_MODULE_PATH}
  )
message(STATUS ${CMAKE_MODULE_PATH})
message(STATUS ${CMAKE_SOURCE_DIR})
find_package(LibR)
if(${LIBR_FOUND})
else()
  message(FATAL_ERROR "No R...")
endif()
message(STATUS ${CMAKE_SOURCE_DIR})
execute_process(
    COMMAND ${LIBR_EXECUTABLE} "--slave" "-e" "stopifnot(require('Rcpp'));cat(Rcpp:::Rcpp.system.file('include'))"
    OUTPUT_VARIABLE LIBRCPP_INCLUDE_DIRS
    )
include_directories(BEFORE ${LIBR_INCLUDE_DIRS})
message(STATUS ${LIBR_INCLUDE_DIRS})
include_directories(BEFORE ${LIBRCPP_INCLUDE_DIRS})
message(STATUS ${LIBRCPP_INCLUDE_DIRS})

find_package(VTK COMPONENTS CommonCore QUIET)
if (NOT VTK_FOUND)
  find_package(VTK COMPONENTS vtkCommonCore QUIET)
  if (NOT VTK_FOUND)
    message("NO_EXISTING_VTK")
    return ()
  endif()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")

find_package(VTK COMPONENTS
  CommonCore
  CommonDataModel
  CommonExecutionModel
  CommonMath
  CommonMisc
  CommonSystem
  CommonTransforms
  IOCore
  IOLegacy
  IOXML
  IOXMLParser
  doubleconversion
  expat
  lz4
  lzma
  pugixml
  vtksys
  zlib
)

if (NOT VTK_FOUND)
  message("Skipping ${PROJECT_NAME}: ${VTK_NOT_FOUND_MESSAGE}")
  return ()
endif()

add_library(vtk INTERFACE)
target_link_libraries(vtk INTERFACE ${VTK_LIBRARIES})

add_custom_target(riot ALL
    COMMAND find ${CMAKE_SOURCE_DIR} -name "*.o" -exec rm "{}" "\;"
    COMMAND find ${CMAKE_SOURCE_DIR} -name "*.so" -exec rm "{}" "\;"
    COMMAND ${LIBR_EXECUTABLE} "--slave" "-e" "\"stopifnot(require(roxygen2));roxygenize('${CMAKE_SOURCE_DIR}',roclets=c('rd','collate','namespace'))\""
    COMMAND ${LIBR_EXECUTABLE} CMD INSTALL "${CMAKE_SOURCE_DIR}"
)

add_dependencies(riot vtk)

with the following FindLibR.cmake file listed under cmake/:

#
# FindLibR.cmake
#
# Copyright (C) 2009-11 by RStudio, Inc.
#
# This program is licensed to you under the terms of version 3 of the
# GNU Affero General Public License. This program is distributed WITHOUT
# ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
# AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
#
#

# LIBR_FOUND
# LIBR_HOME
# LIBR_INCLUDE_DIRS
# LIBR_DOC_DIR
# LIBR_LIBRARIES

# detection for OSX (look for R framework)
if(APPLE)

   find_library(LIBR_LIBRARIES R)
   if(LIBR_LIBRARIES)
      set(LIBR_HOME "${LIBR_LIBRARIES}/Resources" CACHE PATH "R home directory")
      set(LIBR_INCLUDE_DIRS "${LIBR_HOME}/include" CACHE PATH "R include directory")
      set(LIBR_DOC_DIR "${LIBR_HOME}/doc" CACHE PATH "R doc directory")
      set(LIBR_EXECUTABLE "${LIBR_HOME}/R" CACHE PATH "R executable")
   endif()

# detection for UNIX & Win32
else()

   # Find R executable and paths (UNIX)
   if(UNIX)

      # find executable
      find_program(LIBR_EXECUTABLE R)
      if(LIBR_EXECUTABLE-NOTFOUND)
         message(STATUS "Unable to locate R executable")
      endif()

      # ask R for the home path
      if(NOT LIBR_HOME)
         execute_process(
            COMMAND ${LIBR_EXECUTABLE} "--slave" "--no-save" "-e" "cat(R.home())"
                      OUTPUT_VARIABLE LIBR_HOME
         )
         if(LIBR_HOME)
           set(LIBR_HOME ${LIBR_HOME} CACHE PATH "R home directory")
         endif()
      endif()

      # ask R for the include dir
      if(NOT LIBR_INCLUDE_DIRS)
         execute_process(
            COMMAND ${LIBR_EXECUTABLE} "--slave" "--no-save" "-e" "cat(R.home('include'))"
            OUTPUT_VARIABLE LIBR_INCLUDE_DIRS
         )
         if(LIBR_INCLUDE_DIRS)
           set(LIBR_INCLUDE_DIRS ${LIBR_INCLUDE_DIRS} CACHE PATH "R include directory")
         endif()
      endif()

      # ask R for the doc dir
      if(NOT LIBR_DOC_DIR)
         execute_process(
            COMMAND ${LIBR_EXECUTABLE} "--slave" "--no-save" "-e" "cat(R.home('doc'))"
            OUTPUT_VARIABLE LIBR_DOC_DIR
         )
         if(LIBR_DOC_DIR)
           set(LIBR_DOC_DIR ${LIBR_DOC_DIR} CACHE PATH "R doc directory")
         endif()
      endif()

      # ask R for the lib dir
      if(NOT LIBR_LIB_DIR)
         execute_process(
            COMMAND ${LIBR_EXECUTABLE} "--slave" "--no-save" "-e" "cat(R.home('lib'))"
            OUTPUT_VARIABLE LIBR_LIB_DIR
         )
      endif()

   # Find R executable and paths (Win32)
   else()

      # find the home path
      if(NOT LIBR_HOME)

         # read home from the registry
         get_filename_component(LIBR_HOME
            "[HKEY_LOCAL_MACHINE\\SOFTWARE\\R-core\\R;InstallPath]"
            ABSOLUTE CACHE)

         # print message if not found
         if(NOT LIBR_HOME)
            message(STATUS "Unable to locate R home (not written to registry)")
         endif()

      endif()

      # set other R paths based on home path
      set(LIBR_INCLUDE_DIRS "${LIBR_HOME}/include" CACHE PATH "R include directory")
      set(LIBR_DOC_DIR "${LIBR_HOME}/doc" CACHE PATH "R doc directory")

      # set library hint path based on whether  we are doing a special session 64 build
      if(LIBR_FIND_WINDOWS_64BIT)
         set(LIBRARY_ARCH_HINT_PATH "${LIBR_HOME}/bin/x64")
      else()
         set(LIBRARY_ARCH_HINT_PATH "${LIBR_HOME}/bin/i386")
      endif()

   endif()

   # look for the R executable
   find_program(LIBR_EXECUTABLE R
                HINTS ${LIBRARY_ARCH_HINT_PATH} ${LIBR_HOME}/bin)
   if(LIBR_EXECUTABLE-NOTFOUND)
      message(STATUS "Unable to locate R executable")
   endif()

   # look for the core R library
   find_library(LIBR_CORE_LIBRARY NAMES R
                HINTS ${LIBR_LIB_DIR} ${LIBRARY_ARCH_HINT_PATH} ${LIBR_HOME}/bin)
   if(LIBR_CORE_LIBRARY)
      set(LIBR_LIBRARIES ${LIBR_CORE_LIBRARY})
   else()
      message(STATUS "Could not find libR shared library.")
   endif()

   # look for lapack
   find_library(LIBR_LAPACK_LIBRARY NAMES Rlapack
                HINTS ${LIBR_LIB_DIR} ${LIBRARY_ARCH_HINT_PATH} ${LIBR_HOME}/bin)
   if(LIBR_LAPACK_LIBRARY)
      set(LIBR_LIBRARIES ${LIBR_LIBRARIES} ${LIBR_LAPACK_LIBRARY})
      if(UNIX)
         set(LIBR_LIBRARIES ${LIBR_LIBRARIES} gfortran)
      endif()
   endif()

   # look for blas
   find_library(LIBR_BLAS_LIBRARY NAMES Rblas
                HINTS ${LIBR_LIB_DIR} ${LIBRARY_ARCH_HINT_PATH} ${LIBR_HOME}/bin)
   if(LIBR_BLAS_LIBRARY)
      set(LIBR_LIBRARIES ${LIBR_LIBRARIES} ${LIBR_BLAS_LIBRARY})
   endif()

   # look for rgraphapp on win32
   if(WIN32)
      find_library(LIBR_GRAPHAPP_LIBRARY NAMES Rgraphapp
                   HINTS ${LIBR_LIB_DIR} ${LIBRARY_ARCH_HINT_PATH} ${LIBR_HOME}/bin)
      if(LIBR_GRAPHAPP_LIBRARY)
         set(LIBR_LIBRARIES ${LIBR_LIBRARIES} ${LIBR_GRAPHAPP_LIBRARY})
      endif()
   endif()

   # cache LIBR_LIBRARIES
   if(LIBR_LIBRARIES)
      set(LIBR_LIBRARIES ${LIBR_LIBRARIES} CACHE PATH "R runtime libraries")
   endif()

endif()

# define find requirements
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibR DEFAULT_MSG
   LIBR_HOME
   LIBR_EXECUTABLE
   LIBR_INCLUDE_DIRS
   LIBR_LIBRARIES
   LIBR_DOC_DIR
)

if(LIBR_FOUND)
   message(STATUS "Found R: ${LIBR_HOME}")
endif()

# mark low-level variables from FIND_* calls as advanced
mark_as_advanced(
   LIBR_CORE_LIBRARY
   LIBR_LAPACK_LIBRARY
   LIBR_BLAS_LIBRARY
)
Enchufa2 commented 1 year ago

It works for me in Fedora with vtk-devel installed:

$ ls .
cmake  CMakeLists.txt
$ cmake -B build
-- /home/user/tmp/cmake
-- /home/user/tmp
-- Found R: /usr/lib64/R
-- /home/user/tmp
Loading required package: Rcpp
-- /usr/include/R
-- /usr/local/lib/R/library/Rcpp/include
-- VTK_VERSION: 9.1.0
-- Found Threads: TRUE  
-- Found ZLIB: /usr/lib64/libz.so (found version "1.2.12") 
-- Found EXPAT: /usr/lib64/libexpat.so (found version "2.5.0") 
-- Found double-conversion: /usr/lib64/libdouble-conversion.so  
-- Found LZ4: /usr/lib64/liblz4.so (found version "1.9.3") 
-- Found LZMA: /usr/lib64/liblzma.so (found version "5.2.5") 
-- Found utf8cpp: /usr/include/utf8cpp  
-- Configuring done
-- Generating done
-- Build files have been written to: /home/user/tmp/build

Could you please put everything together in a separate branch here for testing?

astamm commented 1 year ago

Yes i will do that. But the Cmake command run you show also works on my Mac. It's the subsequent make command that throws errors.

Enchufa2 commented 1 year ago

I cannot test your setup without the changes required to the configure file, that's why I am asking for a new branch with this stuff, so that I can directly clone, checkout the branch and run R CMD INSTALL there. :)

astamm commented 1 year ago

It is taking me too much time at the moment. I think I will release without this feature unless you think you can contribute. Thanks for your time anyway and happy new year!

Enchufa2 commented 1 year ago

Not at this moment, sorry! :)

astamm commented 1 year ago

I will probably close this issue. Detecting an existing VTK build

Hence, I prefer to have control over the compilation. There is already no compilation happening on Windows. On macOS and Linux, I now ship a shrunk version of latest stable VTK source files which weighs 3.6MB and builds from that with cmake.

Enchufa2 commented 1 year ago

You mean that you bundle it? But this is not on CRAN yet, right? Bundling is fine. The issue is with downloading things at build time.

astamm commented 1 year ago

Exactly. Not yet on CRAN, submitted but I have not heard from them yet. If all goes well, I'll close this issue when v1.1.1 reaches CRAN.