build_r.R 3.88 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)
}

James Lamb's avatar
James Lamb committed
118
119
120
# 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
121
.run_shell_command("R", c("CMD", "build", TEMP_R_DIR, "--keep-empty-dirs"))
James Lamb's avatar
James Lamb committed
122
123
124

# Install the package
version <- gsub(
125
126
127
  "Version: ",
  "",
  grep(
128
    "Version: "
129
    , readLines(con = file.path(TEMP_R_DIR, "DESCRIPTION"))
130
    , value = TRUE
131
  )
James Lamb's avatar
James Lamb committed
132
133
134
)
tarball <- file.path(getwd(), sprintf("lightgbm_%s.tar.gz", version))

135
136
install_cmd <- "R"
install_args <- c("CMD", "INSTALL", "--no-multiarch", "--with-keep.source", tarball)
137
if (INSTALL_AFTER_BUILD) {
138
  .run_shell_command(install_cmd, install_args)
139
} else {
140
  cmd <- paste0(install_cmd, " ", paste0(install_args, collapse = " "))
141
142
  print(sprintf("Skipping installation. Install the package with command '%s'", cmd))
}