-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
install.libs.R
249 lines (223 loc) · 7.47 KB
/
install.libs.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# User options
use_gpu <- FALSE
make_args_from_build_script <- character(0L)
# For Windows, the package will be built with Visual Studio
# unless you set one of these to TRUE
use_mingw <- FALSE
use_msys2 <- FALSE
if (use_mingw && use_msys2) {
stop("Cannot use both MinGW and MSYS2. Please choose only one.")
}
if (.Machine$sizeof.pointer != 8L) {
stop("LightGBM only supports 64-bit R, please check the version of R and Rtools.")
}
R_ver <- as.double(R.Version()$major) + as.double(R.Version()$minor) / 10.0
# Get some paths
source_dir <- file.path(R_PACKAGE_SOURCE, "src", fsep = "/")
build_dir <- file.path(source_dir, "build", fsep = "/")
inst_dir <- file.path(R_PACKAGE_SOURCE, "inst", fsep = "/")
# system() will not raise an R exception if the process called
# fails. Wrapping it here to get that behavior.
#
# system() introduces a lot of overhead, at least on Windows,
# so trying processx if it is available
.run_shell_command <- function(cmd, args, strict = TRUE) {
on_windows <- .Platform$OS.type == "windows"
has_processx <- suppressMessages({
suppressWarnings({
require("processx") # nolint: undesirable_function
})
})
if (has_processx && on_windows) {
result <- processx::run(
command = cmd
, args = args
, windows_verbatim_args = TRUE
, error_on_status = FALSE
, echo = TRUE
)
exit_code <- result$status
} else {
if (on_windows) {
message(paste0(
"Using system() to run shell commands. Installing "
, "'processx' with install.packages('processx') might "
, "make this faster."
))
}
cmd <- paste0(cmd, " ", paste0(args, collapse = " "))
exit_code <- system(cmd)
}
if (exit_code != 0L && isTRUE(strict)) {
stop(paste0("Command failed with exit code: ", exit_code))
}
return(invisible(exit_code))
}
# try to generate Visual Studio build files
.generate_vs_makefiles <- function(cmake_args) {
vs_versions <- c(
"Visual Studio 17 2022"
, "Visual Studio 16 2019"
, "Visual Studio 15 2017"
, "Visual Studio 14 2015"
)
working_vs_version <- NULL
for (vs_version in vs_versions) {
message(sprintf("Trying '%s'", vs_version))
# if the build directory is not empty, clean it
if (file.exists("CMakeCache.txt")) {
file.remove("CMakeCache.txt")
}
vs_cmake_args <- c(
cmake_args
, "-G"
, shQuote(vs_version)
, "-A"
, "x64"
)
exit_code <- .run_shell_command("cmake", c(vs_cmake_args, ".."), strict = FALSE)
if (exit_code == 0L) {
message(sprintf("Successfully created build files for '%s'", vs_version))
return(invisible(TRUE))
}
}
return(invisible(FALSE))
}
# Move in CMakeLists.txt
write_succeeded <- file.copy(
file.path(inst_dir, "bin", "CMakeLists.txt")
, "CMakeLists.txt"
, overwrite = TRUE
)
if (!write_succeeded) {
stop("Copying CMakeLists.txt failed")
}
# Prepare building package
dir.create(
build_dir
, recursive = TRUE
, showWarnings = FALSE
)
setwd(build_dir)
use_visual_studio <- !(use_mingw || use_msys2)
# If using MSVC to build, pull in the script used
# to create R.def from R.dll
if (WINDOWS && use_visual_studio) {
write_succeeded <- file.copy(
file.path(inst_dir, "make-r-def.R")
, file.path(build_dir, "make-r-def.R")
, overwrite = TRUE
)
if (!write_succeeded) {
stop("Copying make-r-def.R failed")
}
}
# Prepare installation steps
cmake_args <- c(
"-D__BUILD_FOR_R=ON"
# pass in R version, to help FindLibR find the R library
, sprintf("-DCMAKE_R_VERSION='%s.%s'", R.Version()[["major"]], R.Version()[["minor"]])
# ensure CMake build respects how R is configured (`R CMD config SHLIB_EXT`)
, sprintf("-DCMAKE_SHARED_LIBRARY_SUFFIX_CXX='%s'", SHLIB_EXT)
)
build_cmd <- "make"
build_args <- c("_lightgbm", make_args_from_build_script)
lib_folder <- file.path(source_dir, fsep = "/")
# add in command-line arguments
# NOTE: build_r.R replaces the line below
command_line_args <- NULL
cmake_args <- c(cmake_args, command_line_args)
WINDOWS_BUILD_TOOLS <- list(
"MinGW" = c(
build_tool = "mingw32-make.exe"
, makefile_generator = "MinGW Makefiles"
)
, "MSYS2" = c(
build_tool = "make.exe"
, makefile_generator = "MSYS Makefiles"
)
)
if (use_mingw) {
windows_toolchain <- "MinGW"
} else if (use_msys2) {
windows_toolchain <- "MSYS2"
} else {
# Rtools 4.0 moved from MinGW to MSYS toolchain. If user tries
# Visual Studio install but that fails, fall back to the toolchain
# supported in Rtools
if (R_ver >= 4.0) {
windows_toolchain <- "MSYS2"
} else {
windows_toolchain <- "MinGW"
}
}
windows_build_tool <- WINDOWS_BUILD_TOOLS[[windows_toolchain]][["build_tool"]]
windows_makefile_generator <- WINDOWS_BUILD_TOOLS[[windows_toolchain]][["makefile_generator"]]
if (use_gpu) {
cmake_args <- c(cmake_args, "-DUSE_GPU=ON")
}
# the checks below might already run `cmake -G`. If they do, set this flag
# to TRUE to avoid re-running it later
makefiles_already_generated <- FALSE
# Check if Windows installation (for gcc vs Visual Studio)
if (WINDOWS) {
if (!use_visual_studio) {
message(sprintf("Trying to build with %s", windows_toolchain))
# Must build twice for Windows due sh.exe in Rtools
cmake_args <- c(cmake_args, "-G", shQuote(windows_makefile_generator))
.run_shell_command("cmake", c(cmake_args, ".."), strict = FALSE)
build_cmd <- windows_build_tool
build_args <- c("_lightgbm", make_args_from_build_script)
} else {
visual_studio_succeeded <- .generate_vs_makefiles(cmake_args)
if (!isTRUE(visual_studio_succeeded)) {
warning(sprintf("Building with Visual Studio failed. Attempting with %s", windows_toolchain))
# Must build twice for Windows due sh.exe in Rtools
cmake_args <- c(cmake_args, "-G", shQuote(windows_makefile_generator))
.run_shell_command("cmake", c(cmake_args, ".."), strict = FALSE)
build_cmd <- windows_build_tool
build_args <- c("_lightgbm", make_args_from_build_script)
} else {
build_cmd <- "cmake"
build_args <- c("--build", ".", "--target", "_lightgbm", "--config", "Release")
lib_folder <- file.path(source_dir, "Release", fsep = "/")
makefiles_already_generated <- TRUE
}
}
} else {
.run_shell_command("cmake", c(cmake_args, ".."))
makefiles_already_generated <- TRUE
}
# generate build files
if (!makefiles_already_generated) {
.run_shell_command("cmake", c(cmake_args, ".."))
}
# build the library
message(paste0("Building lightgbm", SHLIB_EXT))
.run_shell_command(build_cmd, build_args)
src <- file.path(lib_folder, paste0("lightgbm", SHLIB_EXT), fsep = "/")
# Packages with install.libs.R need to copy some artifacts into the
# expected places in the package structure.
# see https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#Package-subdirectories,
# especially the paragraph on install.libs.R
dest <- file.path(R_PACKAGE_DIR, paste0("libs", R_ARCH), fsep = "/")
dir.create(dest, recursive = TRUE, showWarnings = FALSE)
if (file.exists(src)) {
message(paste0("Found library file: ", src, " to move to ", dest))
file.copy(src, dest, overwrite = TRUE)
symbols_file <- file.path(source_dir, "symbols.rds")
if (file.exists(symbols_file)) {
file.copy(symbols_file, dest, overwrite = TRUE)
}
} else {
stop(paste0("Cannot find lightgbm", SHLIB_EXT))
}
# clean up the "build" directory
if (dir.exists(build_dir)) {
message("Removing 'build/' directory")
unlink(
x = build_dir
, recursive = TRUE
, force = TRUE
)
}