# CMake module used to find the location of R's # dll and header files. # # Borrows heavily from xgboost's R package: # # * https://github.com/dmlc/xgboost/blob/master/cmake/modules/FindLibR.cmake # # Defines the following: # LIBR_FOUND # LIBR_HOME # LIBR_EXECUTABLE # LIBR_MSVC_CORE_LIBRARY # LIBR_INCLUDE_DIRS # LIBR_CORE_LIBRARY # and a CMake function to create R.lib for MSVC if(NOT R_ARCH) if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") set(R_ARCH "i386") else() set(R_ARCH "x64") endif() endif() if(NOT ("${R_ARCH}" STREQUAL "x64")) message(FATAL_ERROR "LightGBM's R package currently only supports 64-bit operating systems") endif() # Creates R.lib and R.def in the build directory for linking with MSVC # https://docs.microsoft.com/en-us/cpp/build/reference/link-input-files?redirectedfrom=MSDN&view=vs-2019 function(create_rlib_for_msvc) message(STATUS "Creating R.lib and R.def") # various checks and warnings if(NOT WIN32 OR NOT MSVC) message(FATAL_ERROR "create_rlib_for_msvc() can only be used with MSVC") endif() if(NOT EXISTS "${LIBR_CORE_LIBRARY}") message(FATAL_ERROR "LIBR_CORE_LIBRARY, '${LIBR_CORE_LIBRARY}', not found") endif() find_program(DLLTOOL_EXE dlltool) if(NOT DLLTOOL_EXE) message(FATAL_ERROR "dlltool.exe not found!\nDo you have Rtools installed with its MinGW's bin/ in PATH?") endif() set(LIBR_MSVC_CORE_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/R.lib" CACHE PATH "R.lib filepath") get_filename_component( LIBR_RSCRIPT_EXECUTABLE_DIR ${LIBR_EXECUTABLE} DIRECTORY ) set(LIBR_RSCRIPT_EXECUTABLE "${LIBR_RSCRIPT_EXECUTABLE_DIR}/Rscript") execute_process( COMMAND ${LIBR_RSCRIPT_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/make-r-def.R" "${LIBR_CORE_LIBRARY}" "${CMAKE_CURRENT_BINARY_DIR}/R.def" ) execute_process( COMMAND ${DLLTOOL_EXE} "--input-def" "${CMAKE_CURRENT_BINARY_DIR}/R.def" "--output-lib" "${LIBR_MSVC_CORE_LIBRARY}" ) endfunction() # R version information is used to search for R's libraries in # the registry on Windows. Since this code is orchestrated by # an R script (src/install.libs.R), that script uses R's built-ins to # find the version of R and pass it through as a CMake variable if(CMAKE_R_VERSION) message(STATUS "R version passed into FindLibR.cmake: ${CMAKE_R_VERSION}") elseif(WIN32) message( FATAL_ERROR "Expected CMAKE_R_VERSION to be passed in on Windows but none was provided. Check src/install.libs.R" ) endif() if(NOT LIBR_EXECUTABLE) find_program( LIBR_EXECUTABLE NAMES R R.exe ) # CRAN may run RD CMD CHECK instead of R CMD CHECK, # which can lead to this infamous error: # 'R' should not be used without a path -- see par. 1.6 of the manual if(LIBR_EXECUTABLE MATCHES ".*\\.Rcheck.*") unset(LIBR_EXECUTABLE CACHE) endif() # ignore the R bundled with R.app on Mac, since that is GUI-only if(LIBR_EXECUTABLE MATCHES ".+R\\.app.*") unset(LIBR_EXECUTABLE CACHE) endif() endif() # Find R executable unless it has been provided directly or already found if(NOT LIBR_EXECUTABLE) if(APPLE) find_library(LIBR_LIBRARIES R) if(LIBR_LIBRARIES MATCHES ".*\\.framework") set(LIBR_HOME "${LIBR_LIBRARIES}/Resources") set(LIBR_EXECUTABLE "${LIBR_HOME}/R") else() get_filename_component(_LIBR_LIBRARIES "${LIBR_LIBRARIES}" REALPATH) get_filename_component(_LIBR_LIBRARIES_DIR "${_LIBR_LIBRARIES}" DIRECTORY) set(LIBR_EXECUTABLE "${_LIBR_LIBRARIES_DIR}/../bin/R") endif() elseif(UNIX) # attempt to find R executable if(NOT LIBR_EXECUTABLE) find_program( LIBR_EXECUTABLE NO_DEFAULT_PATH HINTS "${CMAKE_CURRENT_BINARY_DIR}" "/usr/bin" "/usr/lib/" "/usr/local/bin/" NAMES R ) endif() # Windows else() # if R executable not available, query R_HOME path from registry if(NOT LIBR_HOME) # Try to find R's location in the registry # ref: https://cran.r-project.org/bin/windows/base/rw-FAQ.html#Does-R-use-the-Registry_003f get_filename_component( LIBR_HOME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\R-core\\R\\${CMAKE_R_VERSION};InstallPath]" ABSOLUTE ) endif() if(NOT LIBR_HOME) get_filename_component( LIBR_HOME "[HKEY_CURRENT_USER\\SOFTWARE\\R-core\\R\\${CMAKE_R_VERSION};InstallPath]" ABSOLUTE ) endif() if(NOT LIBR_HOME) message( FATAL_ERROR "Unable to locate R executable.\ \nEither add its location to PATH or provide it through the LIBR_EXECUTABLE CMake variable" ) endif() # set exe location based on R_ARCH set(LIBR_EXECUTABLE "${LIBR_HOME}/bin/${R_ARCH}/R.exe") endif() if(NOT LIBR_EXECUTABLE) message( FATAL_ERROR "Unable to locate R executable.\ \nEither add its location to PATH or provide it through the LIBR_EXECUTABLE CMake variable" ) endif() endif() # ask R for the home path execute_process( COMMAND ${LIBR_EXECUTABLE} "--slave" "--vanilla" "-e" "cat(normalizePath(R.home(), winslash='/'))" OUTPUT_VARIABLE LIBR_HOME ) # ask R for the include dir execute_process( COMMAND ${LIBR_EXECUTABLE} "--slave" "--vanilla" "-e" "cat(normalizePath(R.home('include'), winslash='/'))" OUTPUT_VARIABLE LIBR_INCLUDE_DIRS ) set(LIBR_HOME ${LIBR_HOME} CACHE PATH "R home directory") set(LIBR_EXECUTABLE ${LIBR_EXECUTABLE} CACHE PATH "R executable") set(LIBR_INCLUDE_DIRS ${LIBR_INCLUDE_DIRS} CACHE PATH "R include directory") # where is R.so / R.dll / libR.so likely to be found? set( LIBR_PATH_HINTS "${CMAKE_CURRENT_BINARY_DIR}" "${LIBR_HOME}/lib" "${LIBR_HOME}/bin/${R_ARCH}" "${LIBR_HOME}/bin" "${LIBR_LIBRARIES}" ) # look for the core R library find_library( LIBR_CORE_LIBRARY NAMES R R.dll HINTS ${LIBR_PATH_HINTS} ) # starting from CMake 3.17, find_library() will not find .dll files by default # https://cmake.org/cmake/help/v3.17/release/3.17.html#other-changes if(WIN32 AND NOT LIBR_CORE_LIBRARY) find_file( LIBR_CORE_LIBRARY NAME R.dll HINTS ${LIBR_PATH_HINTS} ) endif() set(LIBR_CORE_LIBRARY ${LIBR_CORE_LIBRARY} CACHE PATH "R core shared library") if(WIN32 AND MSVC) # create a local R.lib import library for R.dll if it doesn't exist if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/R.lib") create_rlib_for_msvc() endif() endif() # define find requirements include(FindPackageHandleStandardArgs) if(WIN32 AND MSVC) find_package_handle_standard_args( LibR DEFAULT_MSG LIBR_HOME LIBR_EXECUTABLE LIBR_INCLUDE_DIRS LIBR_CORE_LIBRARY LIBR_MSVC_CORE_LIBRARY ) else() find_package_handle_standard_args( LibR DEFAULT_MSG LIBR_HOME LIBR_EXECUTABLE LIBR_INCLUDE_DIRS LIBR_CORE_LIBRARY ) endif()