зеркало из https://github.com/microsoft/LightGBM.git
* [R-package] started cutting over from custom R-to-C interface to R.h * replaced LGBM_SE with SEXP * fixed error about ocnflicting definitions of length * got linking working * more stuff * eliminated R CMD CHECK note about printing * switched from hard-coded include dir to the one from FindLibR.cmake * cleaned up formatting in FindLibR.cmake * commented-out everything in CI that does not touch R * more changes * trying to get better logs * tried ignoring * added error message to confirm a suspicion * still trying to find R during R CMD CHECK * restore full CI * fixed comment * Update R-package/src/cmake/modules/FindLibR.cmake * changed strategy for finding LIBR_HOME on Windows * Removed 32-bit Windows stuff in FindLibR.cmake * Update R-package/src/cmake/modules/FindLibR.cmake * Update CMakeLists.txt Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update CMakeLists.txt Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * removed some duplication in cmake scripts * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * added LIBR_CORE_LIBRARY back * small fixes to CMakeLists * simplified FindLibR.cmake * some fixes for windows * Apply suggestions from code review Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * allowed for directly passing LIBR_EXECUTABLE to FindLibR.cmake * reorganized FindLibR.cmake to catch more cases * clean up inconsistencies in R calls in FindLibR.cmake * Update R-package/src/cmake/modules/FindLibR.cmake Co-Authored-By: Nikita Titov <nekit94-08@mail.ru> * removed unnecessary log messages * removed unnecessary unset() call Co-authored-by: Nikita Titov <nekit94-08@mail.ru>
This commit is contained in:
Родитель
a8c1e0a11a
Коммит
0341906c45
|
@ -72,6 +72,12 @@ if(USE_R35)
|
||||||
endif(USE_R35)
|
endif(USE_R35)
|
||||||
|
|
||||||
if(BUILD_FOR_R)
|
if(BUILD_FOR_R)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
|
||||||
|
find_package(LibR REQUIRED)
|
||||||
|
message(STATUS "LIBR_EXECUTABLE: ${LIBR_EXECUTABLE}")
|
||||||
|
message(STATUS "LIBR_INCLUDE_DIRS: ${LIBR_INCLUDE_DIRS}")
|
||||||
|
message(STATUS "LIBR_CORE_LIBRARY: ${LIBR_CORE_LIBRARY}")
|
||||||
|
include_directories(${LIBR_INCLUDE_DIRS})
|
||||||
ADD_DEFINITIONS(-DLGB_R_BUILD)
|
ADD_DEFINITIONS(-DLGB_R_BUILD)
|
||||||
endif(BUILD_FOR_R)
|
endif(BUILD_FOR_R)
|
||||||
|
|
||||||
|
@ -301,6 +307,11 @@ if(WIN32 AND (MINGW OR CYGWIN))
|
||||||
TARGET_LINK_LIBRARIES(_lightgbm IPHLPAPI)
|
TARGET_LINK_LIBRARIES(_lightgbm IPHLPAPI)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_FOR_R)
|
||||||
|
TARGET_LINK_LIBRARIES(lightgbm ${LIBR_CORE_LIBRARY})
|
||||||
|
TARGET_LINK_LIBRARIES(_lightgbm ${LIBR_CORE_LIBRARY})
|
||||||
|
endif(BUILD_FOR_R)
|
||||||
|
|
||||||
install(TARGETS lightgbm _lightgbm
|
install(TARGETS lightgbm _lightgbm
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
|
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
|
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
# 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_INCLUDE_DIRS
|
||||||
|
# LIBR_LIB_DIR
|
||||||
|
# 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
|
||||||
|
function(create_rlib_for_msvc)
|
||||||
|
|
||||||
|
message("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_LIB_DIR}")
|
||||||
|
message(FATAL_ERROR "LIBR_LIB_DIR, '${LIBR_LIB_DIR}', not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_program(GENDEF_EXE gendef)
|
||||||
|
find_program(DLLTOOL_EXE dlltool)
|
||||||
|
|
||||||
|
if(NOT GENDEF_EXE OR NOT DLLTOOL_EXE)
|
||||||
|
message(FATAL_ERROR "Either gendef.exe or dlltool.exe not found!\
|
||||||
|
\nDo you have Rtools installed with its MinGW's bin/ in PATH?")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# extract symbols from R.dll into R.def and R.lib import library
|
||||||
|
execute_process(COMMAND ${GENDEF_EXE}
|
||||||
|
"-" "${LIBR_LIB_DIR}/R.dll"
|
||||||
|
OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/R.def"
|
||||||
|
)
|
||||||
|
execute_process(COMMAND ${DLLTOOL_EXE}
|
||||||
|
"--input-def" "${CMAKE_CURRENT_BINARY_DIR}/R.def"
|
||||||
|
"--output-lib" "${CMAKE_CURRENT_BINARY_DIR}/R.lib"
|
||||||
|
)
|
||||||
|
endfunction(create_rlib_for_msvc)
|
||||||
|
|
||||||
|
# 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("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
|
||||||
|
)
|
||||||
|
|
||||||
|
# ask R for the lib dir
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${LIBR_EXECUTABLE} "--slave" "--vanilla" "-e" "cat(normalizePath(R.home('lib'), winslash='/'))"
|
||||||
|
OUTPUT_VARIABLE LIBR_LIB_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
# look for the core R library
|
||||||
|
find_library(
|
||||||
|
LIBR_CORE_LIBRARY
|
||||||
|
NAMES R
|
||||||
|
HINTS "${CMAKE_CURRENT_BINARY_DIR}" "${LIBR_LIB_DIR}" "${LIBR_HOME}/bin" "${LIBR_LIBRARIES}"
|
||||||
|
)
|
||||||
|
|
||||||
|
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")
|
||||||
|
set(LIBR_LIB_DIR ${LIBR_LIB_DIR} CACHE PATH "R shared libraries directory")
|
||||||
|
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)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(LibR DEFAULT_MSG
|
||||||
|
LIBR_HOME
|
||||||
|
LIBR_EXECUTABLE
|
||||||
|
LIBR_INCLUDE_DIRS
|
||||||
|
LIBR_LIB_DIR
|
||||||
|
LIBR_CORE_LIBRARY
|
||||||
|
)
|
|
@ -53,6 +53,17 @@ if (!use_precompile) {
|
||||||
}
|
}
|
||||||
cmake_cmd <- paste0(cmake_cmd, " -DBUILD_FOR_R=ON ")
|
cmake_cmd <- paste0(cmake_cmd, " -DBUILD_FOR_R=ON ")
|
||||||
|
|
||||||
|
# Pass in R version, used to help find R executable for linking
|
||||||
|
R_version_string <- paste(
|
||||||
|
R.Version()[["major"]]
|
||||||
|
, R.Version()[["minor"]]
|
||||||
|
, sep = "."
|
||||||
|
)
|
||||||
|
cmake_cmd <- sprintf(
|
||||||
|
paste0(cmake_cmd, " -DCMAKE_R_VERSION='%s' ")
|
||||||
|
, R_version_string
|
||||||
|
)
|
||||||
|
|
||||||
# Check if Windows installation (for gcc vs Visual Studio)
|
# Check if Windows installation (for gcc vs Visual Studio)
|
||||||
if (WINDOWS) {
|
if (WINDOWS) {
|
||||||
if (use_mingw) {
|
if (use_mingw) {
|
||||||
|
|
|
@ -39,9 +39,9 @@
|
||||||
|
|
||||||
// 64bit pointer
|
// 64bit pointer
|
||||||
#if INTPTR_MAX == INT64_MAX
|
#if INTPTR_MAX == INT64_MAX
|
||||||
typedef int64_t R_xlen_t;
|
typedef int64_t xlen_t;
|
||||||
#else
|
#else
|
||||||
typedef int R_xlen_t;
|
typedef int xlen_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
unsigned int gccls : 3;
|
unsigned int gccls : 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int R_xlen_t;
|
typedef int xlen_t;
|
||||||
#endif // R_VER_ABOVE_35
|
#endif // R_VER_ABOVE_35
|
||||||
|
|
||||||
struct lgbm_primsxp {
|
struct lgbm_primsxp {
|
||||||
|
@ -110,8 +110,8 @@ typedef struct LGBM_SER {
|
||||||
} LGBM_SER, *LGBM_SE;
|
} LGBM_SER, *LGBM_SE;
|
||||||
|
|
||||||
struct lgbm_vecsxp {
|
struct lgbm_vecsxp {
|
||||||
R_xlen_t length;
|
xlen_t length;
|
||||||
R_xlen_t truelength;
|
xlen_t truelength;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VECTOR_SER {
|
typedef struct VECTOR_SER {
|
||||||
|
|
|
@ -14,6 +14,13 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#ifdef LGB_R_BUILD
|
||||||
|
#define R_NO_REMAP
|
||||||
|
#define R_USE_C99_IN_CXX
|
||||||
|
#include <R_ext/Error.h>
|
||||||
|
#include <R_ext/Print.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace LightGBM {
|
namespace LightGBM {
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
@ -57,7 +64,6 @@ namespace LightGBM {
|
||||||
if ((pointer) == nullptr) LightGBM::Log::Fatal(#pointer " Can't be NULL at %s, line %d .\n", __FILE__, __LINE__);
|
if ((pointer) == nullptr) LightGBM::Log::Fatal(#pointer " Can't be NULL at %s, line %d .\n", __FILE__, __LINE__);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum class LogLevel: int {
|
enum class LogLevel: int {
|
||||||
Fatal = -1,
|
Fatal = -1,
|
||||||
Warning = 0,
|
Warning = 0,
|
||||||
|
@ -65,7 +71,6 @@ enum class LogLevel: int {
|
||||||
Debug = 2,
|
Debug = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A static Log class
|
* \brief A static Log class
|
||||||
*/
|
*/
|
||||||
|
@ -107,19 +112,33 @@ class Log {
|
||||||
vsprintf(str_buf, format, val);
|
vsprintf(str_buf, format, val);
|
||||||
#endif
|
#endif
|
||||||
va_end(val);
|
va_end(val);
|
||||||
|
|
||||||
|
// R code should write back to R's error stream,
|
||||||
|
// otherwise to stderr
|
||||||
|
#ifndef LGB_R_BUILD
|
||||||
fprintf(stderr, "[LightGBM] [Fatal] %s\n", str_buf);
|
fprintf(stderr, "[LightGBM] [Fatal] %s\n", str_buf);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
throw std::runtime_error(std::string(str_buf));
|
throw std::runtime_error(std::string(str_buf));
|
||||||
|
#else
|
||||||
|
Rf_error("[LightGBM] [Fatal] %s\n", str_buf);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void Write(LogLevel level, const char* level_str, const char *format, va_list val) {
|
static void Write(LogLevel level, const char* level_str, const char *format, va_list val) {
|
||||||
if (level <= GetLevel()) { // omit the message with low level
|
if (level <= GetLevel()) { // omit the message with low level
|
||||||
// write to STDOUT
|
// R code should write back to R's output stream,
|
||||||
|
// otherwise to stdout
|
||||||
|
#ifndef LGB_R_BUILD
|
||||||
printf("[LightGBM] [%s] ", level_str);
|
printf("[LightGBM] [%s] ", level_str);
|
||||||
vprintf(format, val);
|
vprintf(format, val);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
#else
|
||||||
|
Rprintf("[LightGBM] [%s] ", level_str);
|
||||||
|
Rvprintf(format, val);
|
||||||
|
Rprintf("\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче