build_r.R 4.04 KB
Newer Older
1
# For macOS users who have decided to use gcc
2
# (replace 8 with version of gcc installed on your machine)
James Lamb's avatar
James Lamb committed
3
4
5
6
7
# NOTE: your gcc / g++ from Homebrew is probably in /usr/local/bin
#export CXX=/usr/local/bin/g++-8 CC=/usr/local/bin/gcc-8
# Sys.setenv("CXX" = "/usr/local/bin/g++-8")
# Sys.setenv("CC" = "/usr/local/bin/gcc-8")

8
9
args <- commandArgs(trailingOnly = TRUE)
INSTALL_AFTER_BUILD <- !("--skip-install" %in% args)
10
11
TEMP_R_DIR <- file.path(getwd(), "lightgbm_r")
TEMP_SOURCE_DIR <- file.path(TEMP_R_DIR, "src")
12

James Lamb's avatar
James Lamb committed
13
14
# R returns FALSE (not a non-zero exit code) if a file copy operation
# breaks. Let's fix that
15
16
17
18
.handle_result <- function(res) {
  if (!res) {
    stop("Copying files failed!")
  }
James Lamb's avatar
James Lamb committed
19
20
}

21
# system() will not raise an R exception if the process called
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
# 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
      })
    })
    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)) {
55
56
        stop(paste0("Command failed with exit code: ", exit_code))
    }
57
    return(invisible(exit_code))
58
59
}

James Lamb's avatar
James Lamb committed
60
# Make a new temporary folder to work in
61
62
unlink(x = TEMP_R_DIR, recursive = TRUE)
dir.create(TEMP_R_DIR)
James Lamb's avatar
James Lamb committed
63
64

# copy in the relevant files
65
66
result <- file.copy(
  from = "R-package/./"
67
  , to = sprintf("%s/", TEMP_R_DIR)
68
69
70
  , recursive = TRUE
  , overwrite = TRUE
)
James Lamb's avatar
James Lamb committed
71
72
.handle_result(result)

73
74
result <- file.copy(
  from = "include/"
75
  , to =  sprintf("%s/", TEMP_SOURCE_DIR)
76
77
78
  , recursive = TRUE
  , overwrite = TRUE
)
James Lamb's avatar
James Lamb committed
79
80
.handle_result(result)

81
82
result <- file.copy(
  from = "src/"
83
  , to = sprintf("%s/", TEMP_SOURCE_DIR)
84
85
86
  , recursive = TRUE
  , overwrite = TRUE
)
Gao Tao's avatar
Gao Tao committed
87
88
.handle_result(result)

89
90
result <- file.copy(
  from = "compute/"
91
  , to = sprintf("%s/", TEMP_SOURCE_DIR)
92
93
94
  , recursive = TRUE
  , overwrite = TRUE
)
James Lamb's avatar
James Lamb committed
95
96
.handle_result(result)

97
98
result <- file.copy(
  from = "CMakeLists.txt"
99
  , to = file.path(TEMP_R_DIR, "inst", "bin/")
100
101
  , overwrite = TRUE
)
James Lamb's avatar
James Lamb committed
102
103
.handle_result(result)

104
105
106
107
108
109
110
111
112
113
114
115
116
117
# copy files into the place CMake expects
for (src_file in c("lightgbm_R.cpp", "lightgbm_R.h", "R_object_helper.h")) {
  result <- file.copy(
    from = file.path(TEMP_SOURCE_DIR, src_file)
    , to = file.path(TEMP_SOURCE_DIR, "src", src_file)
    , overwrite = TRUE
  )
  .handle_result(result)
  result <- file.remove(
    file.path(TEMP_SOURCE_DIR, src_file)
  )
  .handle_result(result)
}

118
119
120
121
122
123
124
result <- file.copy(
  from = file.path("R-package", "inst", "make-r-def.R")
  , to = file.path(TEMP_R_DIR, "inst", "bin/")
  , overwrite = TRUE
)
.handle_result(result)

James Lamb's avatar
James Lamb committed
125
126
127
# NOTE: --keep-empty-dirs is necessary to keep the deep paths expected
#       by CMake while also meeting the CRAN req to create object files
#       on demand
128
.run_shell_command("R", c("CMD", "build", TEMP_R_DIR, "--keep-empty-dirs"))
James Lamb's avatar
James Lamb committed
129
130
131

# Install the package
version <- gsub(
132
133
134
  "Version: ",
  "",
  grep(
135
    "Version: "
136
    , readLines(con = file.path(TEMP_R_DIR, "DESCRIPTION"))
137
    , value = TRUE
138
  )
James Lamb's avatar
James Lamb committed
139
140
141
)
tarball <- file.path(getwd(), sprintf("lightgbm_%s.tar.gz", version))

142
143
install_cmd <- "R"
install_args <- c("CMD", "INSTALL", "--no-multiarch", "--with-keep.source", tarball)
144
if (INSTALL_AFTER_BUILD) {
145
  .run_shell_command(install_cmd, install_args)
146
} else {
147
  cmd <- paste0(install_cmd, " ", paste0(install_args, collapse = " "))
148
149
  print(sprintf("Skipping installation. Install the package with command '%s'", cmd))
}