diff --git a/.appveyor.yml b/.appveyor.yml index f8cd85f17dcb..20807e36e6f5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,6 +7,8 @@ configuration: # a trick to construct a build matrix with multiple Python versi environment: matrix: + - COMPILER: MINGW + TASK: r-package - COMPILER: MSVC TASK: python - COMPILER: MINGW diff --git a/.ci/test_r_package_windows.ps1 b/.ci/test_r_package_windows.ps1 new file mode 100644 index 000000000000..5bd65d28408b --- /dev/null +++ b/.ci/test_r_package_windows.ps1 @@ -0,0 +1,108 @@ +# Download a file and retry upon failure. This looks like +# an infinite loop but CI-level timeouts will kill it +function Download-File-With-Retries { + param( + [string]$url, + [string]$destfile + ) + do { + Write-Output "Downloading ${url}" + sleep 5; + (New-Object System.Net.WebClient).DownloadFile($url, $destfile) + } while(!$?); +} + +$env:R_WINDOWS_VERSION = "3.6.3" +$env:R_LIB_PATH = "$env:BUILD_SOURCESDIRECTORY/RLibrary" -replace '[\\]', '/' +$env:PATH = "$env:R_LIB_PATH/Rtools/bin;" + "$env:R_LIB_PATH/R/bin/x64;" + "$env:R_LIB_PATH/miktex/texmfs/install/miktex/bin/x64;" + $env:PATH +$env:CRAN_MIRROR = "https://cloud.r-project.org/" +$env:CTAN_MIRROR = "https://ctan.math.illinois.edu/systems/win32/miktex/tm/packages/" + +if ($env:COMPILER -eq "MINGW") { + $env:CXX = "$env:R_LIB_PATH/Rtools/mingw_64/bin/g++.exe" + $env:CC = "$env:R_LIB_PATH/Rtools/mingw_64/bin/gcc.exe" +} + +cd $env:BUILD_SOURCESDIRECTORY +tzutil /s "GMT Standard Time" +[Void][System.IO.Directory]::CreateDirectory($env:R_LIB_PATH) + +if ($env:COMPILER -eq "MINGW") { + Write-Output "Telling R to use MinGW" + $install_libs = "$env:BUILD_SOURCESDIRECTORY/R-package/src/install.libs.R" + ((Get-Content -path $install_libs -Raw) -replace 'use_mingw <- FALSE','use_mingw <- TRUE') | Set-Content -Path $install_libs +} + +# download R and RTools +Write-Output "Downloading R and Rtools" +Download-File-With-Retries -url "https://cloud.r-project.org/bin/windows/base/old/$env:R_WINDOWS_VERSION/R-$env:R_WINDOWS_VERSION-win.exe" -destfile "R-win.exe" +Download-File-With-Retries -url "https://cloud.r-project.org/bin/windows/Rtools/Rtools35.exe" -destfile "Rtools.exe" + +# Install R +Write-Output "Installing R" +Start-Process -FilePath R-win.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /DIR=$env:R_LIB_PATH/R /COMPONENTS=main,x64" ; Check-Output $? +Write-Output "Done installing R" + +Write-Output "Installing Rtools" +Start-Process -FilePath Rtools.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /DIR=$env:R_LIB_PATH/Rtools" ; Check-Output $? +Write-Output "Done installing Rtools" + +# MiKTeX and pandoc can be skipped on non-MINGW builds, since we don't +# build the package documentation for those +if ($env:COMPILER -eq "MINGW") { + Write-Output "Downloading MiKTeX" + Download-File-With-Retries -url "https://miktex.org/download/win/miktexsetup-x64.zip" -destfile "miktexsetup-x64.zip" + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory("miktexsetup-x64.zip", "miktex") + Write-Output "Setting up MiKTeX" + .\miktex\miktexsetup.exe --remote-package-repository="$env:CTAN_MIRROR" --local-package-repository=./miktex/download --package-set=essential --quiet download ; Check-Output $? + Write-Output "Installing MiKTeX" + .\miktex\download\miktexsetup.exe --remote-package-repository="$env:CTAN_MIRROR" --portable="$env:R_LIB_PATH/miktex" --quiet install ; Check-Output $? + Write-Output "Done installing MiKTeX" + + initexmf --set-config-value [MPM]AutoInstall=1 + conda install -q -y --no-deps pandoc +} + +Add-Content .Renviron "R_LIBS=$env:R_LIB_PATH" + +Write-Output "Installing dependencies" +$packages = "c('data.table', 'jsonlite', 'Matrix', 'R6', 'testthat'), dependencies = c('Imports', 'Depends', 'LinkingTo')" +Rscript --vanilla -e "options(install.packages.check.source = 'no'); install.packages($packages, repos = '$env:CRAN_MIRROR', type = 'binary', lib = '$env:R_LIB_PATH')" ; Check-Output $? + +Write-Output "Building R package" +Rscript build_r.R --skip-install ; Check-Output $? + +$PKG_FILE_NAME = Get-Item *.tar.gz +$LOG_FILE_NAME = "lightgbm.Rcheck/00check.log" + +$env:_R_CHECK_FORCE_SUGGESTS_ = 0 +if ($env:COMPILER -ne "MINGW") { + Write-Output "Running R CMD check without checking documentation" + R.exe CMD check --no-multiarch --no-examples --no-manual --ignore-vignettes ${PKG_FILE_NAME} ; $check_succeeded = $? +} else { + Write-Output "Running R CMD check as CRAN" + R.exe CMD check --no-multiarch --as-cran ${PKG_FILE_NAME} ; $check_succeeded = $? +} + +Write-Output "R CMD check build logs:" +Get-Content -Path $env:BUILD_SOURCESDIRECTORY\lightgbm.Rcheck\00install.out + +Check-Output $check_succeeded + +Write-Output "Looking for issues with R CMD check results" +if (Get-Content "$LOG_FILE_NAME" | Select-String -Pattern "WARNING" -Quiet) { + echo "WARNINGS have been found by R CMD check!" + Check-Output $False +} + +$note_str = Get-Content "${LOG_FILE_NAME}" | Select-String -Pattern ' NOTE' | Out-String ; Check-Output $? +$relevant_line = $note_str -match '.*Status: (\d+) NOTE.*' +$NUM_CHECK_NOTES = $matches[1] +$ALLOWED_CHECK_NOTES = 3 +if ([int]$NUM_CHECK_NOTES -gt $ALLOWED_CHECK_NOTES) { + Write-Output "Found ${NUM_CHECK_NOTES} NOTEs from R CMD check. Only ${ALLOWED_CHECK_NOTES} are allowed" + Check-Output $False +} + +Write-Output "No issues were found checking the R package" diff --git a/.ci/test_windows.ps1 b/.ci/test_windows.ps1 index 82849577152d..fd0e9f95a5e4 100644 --- a/.ci/test_windows.ps1 +++ b/.ci/test_windows.ps1 @@ -12,6 +12,11 @@ if (Test-Path env:APPVEYOR) { $env:BUILD_SOURCESDIRECTORY = $env:APPVEYOR_BUILD_FOLDER } +if ($env:TASK -eq "r-package") { + & $env:BUILD_SOURCESDIRECTORY\.ci\test_r_package_windows.ps1 ; Check-Output $? + Exit 0 +} + # setup for Python conda init powershell conda activate diff --git a/.vsts-ci.yml b/.vsts-ci.yml index a39dbc0e105b..a533ab1659e4 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -22,7 +22,7 @@ jobs: vmImage: 'ubuntu-latest' container: ubuntu1404 strategy: - maxParallel: 6 + maxParallel: 7 matrix: regular: TASK: regular @@ -76,7 +76,7 @@ jobs: pool: vmImage: 'macOS-10.14' strategy: - maxParallel: 3 + maxParallel: 4 matrix: regular: TASK: regular @@ -117,8 +117,11 @@ jobs: pool: vmImage: 'vs2017-win2016' strategy: - maxParallel: 3 + maxParallel: 4 matrix: + r_package: + TASK: r-package + COMPILER: MINGW regular: TASK: regular PYTHON_VERSION: 3.6 diff --git a/R-package/NAMESPACE b/R-package/NAMESPACE index 7aef39a1f6de..14db7ba98d6c 100644 --- a/R-package/NAMESPACE +++ b/R-package/NAMESPACE @@ -36,6 +36,7 @@ export(saveRDS.lgb.Booster) export(setinfo) export(slice) import(methods) +importFrom(Matrix,Matrix) importFrom(R6,R6Class) importFrom(data.table,":=") importFrom(data.table,as.data.table) diff --git a/R-package/R/lightgbm.R b/R-package/R/lightgbm.R index 9459ccc4d5c4..12640ecfb0af 100644 --- a/R-package/R/lightgbm.R +++ b/R-package/R/lightgbm.R @@ -178,6 +178,7 @@ NULL # Various imports #' @import methods +#' @importFrom Matrix Matrix #' @importFrom R6 R6Class #' @useDynLib lib_lightgbm , .registration = TRUE NULL diff --git a/R-package/src/cmake/modules/FindLibR.cmake b/R-package/src/cmake/modules/FindLibR.cmake index 20c0a974e1ff..ad26f06dfeef 100644 --- a/R-package/src/cmake/modules/FindLibR.cmake +++ b/R-package/src/cmake/modules/FindLibR.cmake @@ -174,17 +174,31 @@ execute_process( OUTPUT_VARIABLE LIBR_LIB_DIR ) +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") + +# where is R.so / R.dll / libR.so likely to be found? +set(LIBR_PATH_HINTS "${CMAKE_CURRENT_BINARY_DIR}" "${LIBR_LIB_DIR}" "${LIBR_HOME}/bin/${R_ARCH}" "${LIBR_HOME}/bin" "${LIBR_LIBRARIES}") + # 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}" + NAMES R R.dll + HINTS ${LIBR_PATH_HINTS} ) -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") +# 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) diff --git a/R-package/src/install.libs.R b/R-package/src/install.libs.R index a79c93d846b7..339e8417ee70 100644 --- a/R-package/src/install.libs.R +++ b/R-package/src/install.libs.R @@ -67,6 +67,7 @@ if (!use_precompile) { # Check if Windows installation (for gcc vs Visual Studio) if (WINDOWS) { if (use_mingw) { + print("Trying to build with MinGW") cmake_cmd <- paste0(cmake_cmd, " -G \"MinGW Makefiles\" ") build_cmd <- "mingw32-make.exe _lightgbm" system(paste0(cmake_cmd, " ..")) # Must build twice for Windows due sh.exe in Rtools