Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile R package by custom tool chain. #584

Merged
merged 11 commits into from
Jun 5, 2017
Merged

Compile R package by custom tool chain. #584

merged 11 commits into from
Jun 5, 2017

Conversation

guolinke
Copy link
Collaborator

@guolinke guolinke commented Jun 3, 2017

refer to #542 .

with this, we can get rid of MinGW in windows. And it is easier to build R-package in OSX as well.
Also, it is easier to build GPU version for R-package in windows.

@Laurae2 Any comment? Can you also help to test the new build?

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 3, 2017

@guolinke Installation seems correct, ran all examples successfully and without any apparent issue. Compiled with Visual Studio 2017.

I used devtools::install to install LightGBM, but it also works with R CMD build and R CMD install.

Do you think there is a way to fallback to the old compilation way (directly from R toolset) if the dll/lib file is not found?

Also, you can update/delete https://github.com/Microsoft/LightGBM/blob/master/docs/GPU-Windows.md doc, as it is now obsolete. For Visual Studio version in wiki, you can recommend VS 2017 with C++ tools because it is a lightweight installation (around 4GB) compared to 2015 or older (8GB or more).

BTW, do you think we can put a "default" DLL in this repository or is there any licensing issue? It would allow R users to install from repository. I could host it on my fork if it causes issues.

Install log:

> setwd("C:/xgboost/LightGBM/R-package")
> devtools::install()
Installing lightgbm
"C:/PROGRA~1/R/R-34~1.0/bin/x64/R" --no-site-file --no-environ --no-save --no-restore --quiet CMD INSTALL "C:/xgboost/LightGBM/R-package"  \
  --library="C:/Program Files/R/R-3.4.0/library" --install-tests 

* installing *source* package 'lightgbm' ...
** libs
installing via 'install.libs.R' to C:/Program Files/R/R-3.4.0/library/lightgbm
[1] "find library file: C:/xgboost/LightGBM/R-package/../windows/x64/DLL//lib_lightgbm.dll"
** R
** data
** demo
** tests
** preparing package for lazy loading
** help
*** installing help indices
  converting help for package 'lightgbm'
    finding HTML links ... done
    agaricus.test                           html  
    agaricus.train                          html  
    dim                                     html  
    dimnames.lgb.Dataset                    html  
    getinfo                                 html  
    lgb.Dataset                             html  
    lgb.Dataset.construct                   html  
    lgb.Dataset.create.valid                html  
    lgb.Dataset.save                        html  
    lgb.Dataset.set.categorical             html  
    lgb.Dataset.set.reference               html  
    lgb.dump                                html  
    lgb.get.eval.result                     html  
    lgb.importance                          html  
    lgb.interprete                          html  
    lgb.load                                html  
    lgb.model.dt.tree                       html  
    lgb.plot.importance                     html  
    lgb.plot.interpretation                 html  
    lgb.prepare                             html  
    lgb.prepare2                            html  
    lgb.prepare_rules                       html  
    lgb.prepare_rules2                      html  
    lgb.save                                html  
    lgb.train                               html  
    lgb.unloader                            html  
    predict.lgb.Booster                     html  
    readRDS.lgb.Booster                     html  
    saveRDS.lgb.Booster                     html  
    setinfo                                 html  
    slice                                   html  
** building package indices
** testing if installed package can be loaded
* DONE (lightgbm)

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 3, 2017

I can also test performance of b5e042d (MinGW based) vs c379a2f (VS based) on Bosch when I wake up tomorrow.

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 4, 2017

Thanks @Laurae2 .

Do you think there is a way to fallback to the old compilation way (directly from R toolset) if the dll/lib file is not found?

I think we can try to add some make command in install.libs.R. But I am not sure can it works or not.

The problem of putting "default" DLL is the cross-platform. We need to build many "DLLs" ([windows, linux, OSX] x [cpu, gpu] ).
I wonder are there any online services, that can auto (trigger by commit) build these R-packages (and python-package) in different platform with multi-settings.

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 4, 2017

@guolinke

The problem of putting "default" DLL is the cross-platform. We need to build many "DLLs" ([windows, linux, OSX] x [cpu, gpu] ).

Currently we can get rid of GPU for automated builds, it is too much GPU vendor dependent.

I wonder are there any online services, that can auto (trigger by commit) build these R-packages (and python-package) in different platform with multi-settings.

Objectives would be:

  • Setting up Travis for Mac (setup gcc, compile lib, compile R/Python package)
  • Setting up AppVeyor for Windows (download MinGW, compile lib, compile R/Python package)

I think we can try to add some make command in install.libs.R. But I am not sure can it works or not.

I have 5 ideas, but I have no idea if they are feasible (solution 5 is feasible 100% guaranteed):

Solution 1: how is a good question... I think with a system call this must be doable:

  • Windows: you can call mingw32-make.exe as it is mandatory to exist when Rtools is installed
  • Linux / Mac: you can call make directly

Solution 2: another way of installing it: using R source, like how biocLite is doing: https://bioconductor.org/biocLite.R (source("https://bioconductor.org/biocLite.R"))

Solution 3: create a secondary R package (easiest) with Makevars, but not easy to maintain

Solution 4: use Makevars if then else fi to check for dll/lib existence to choose if compilation is required or not. Example: https://stackoverflow.com/questions/27104508/portable-makevars-for-r-package-using-c-gsl-and-openmp-with-help-of-rcpp

Solution 5: identical to solution 2, except that script would handle both the fetching of the repository (git clone .........), compilation (system make ........), and installation (devtools::install). It would require git and make (or mingw32-make for Windows if "Visual Studio" is not found in PATH). User will have to setup Rscript PATH correctly to use it. See here for arguments to pass to an Rscript: https://stackoverflow.com/questions/14525580/how-to-pass-command-line-arguments-when-source-an-r-file By far the "stablest" solution I think.

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 4, 2017

@guolinke Do you know how to create DLL from Visual Studio compiler from command line? I am trying to allow compilation using VS make.

I can create a helper package to install LightGBM (we can put it in Microsoft/LightGBM or at Laurae2, up to you).

I managed to get compilation done using R script:

> lgb_git_dir <- tempdir()
> lgb_git_file <- file.path(lgb_git_dir, "temp.bat", fsep = "\\")
> unlink(paste0(lgb_git_dir, "\\LightGBM"), recursive = TRUE, force = TRUE)
> cat(paste0("cd ", lgb_git_dir, "\n"), file = lgb_git_file)
> cat(paste0("git clone --recursive https://github.com/Microsoft/LightGBM", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("cd LightGBM", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("git checkout r-withvs", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("mkdir build && cd build", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE)
> cat(paste0("mingw32-make.exe"), file = lgb_git_file, append = TRUE)
> system(lgb_git_file)

C:\Users\Laurae\Documents>cd C:\tmp\RtmpSa5Bdv 

C:\tmp\RtmpSa5Bdv>git clone --recursive https://github.com/Microsoft/LightGBM 
Cloning into 'LightGBM'...
Submodule 'include/boost/compute' (https://github.com/boostorg/compute) registered for path 'compute'
Cloning into 'compute'...
Submodule path 'compute': checked out '6de7f6448796f67958dde8de4569fb1ae649ee91'

C:\tmp\RtmpSa5Bdv>cd LightGBM 

C:\tmp\RtmpSa5Bdv\LightGBM>git checkout r-withvs 
Branch r-withvs set up to track remote branch r-withvs from origin.
Switched to a new branch 'r-withvs'

C:\tmp\RtmpSa5Bdv\LightGBM>mkdir build   && cd build 

C:\tmp\RtmpSa5Bdv\LightGBM\build>cmake -G "MinGW Makefiles" .. 
CMake Error at C:/Program Files/CMake/share/cmake-3.8/Modules/CMakeMinGWFindMake.cmake:12 (message):
  sh.exe was found in your PATH, here:

  C:/Rtools/bin/sh.exe

  For MinGW make to work correctly sh.exe must NOT be in your path.

  Run cmake from a shell that does not have sh.exe in your PATH.

  If you want to use a UNIX shell, then use MSYS Makefiles.

Call Stack (most recent call first):
  CMakeLists.txt:8 (PROJECT)


CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!

C:\tmp\RtmpSa5Bdv\LightGBM\build>cmake -G "MinGW Makefiles" .. 
-- The C compiler identification is GNU 7.1.0
-- The CXX compiler identification is GNU 7.1.0
-- Check for working C compiler: C:/Rtools/mingw_64/bin/gcc.exe
-- Check for working C compiler: C:/Rtools/mingw_64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Rtools/mingw_64/bin/g++.exe
-- Check for working CXX compiler: C:/Rtools/mingw_64/bin/g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Try OpenMP C flag = [-fopenmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Try OpenMP CXX flag = [-fopenmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Found OpenMP: -fopenmp  
-- Configuring done
-- Generating done
-- Build files have been written to: C:/tmp/RtmpSa5Bdv/LightGBM/build

C:\tmp\RtmpSa5Bdv\LightGBM\build>mingw32-make.exe
Scanning dependencies of target lightgbm
[  1%] Building CXX object CMakeFiles/lightgbm.dir/src/main.cpp.obj
[  3%] Building CXX object CMakeFiles/lightgbm.dir/src/application/application.cpp.obj
[  5%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/boosting.cpp.obj
[  7%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/gbdt.cpp.obj
[  9%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/gbdt_prediction.cpp.obj
[ 10%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/prediction_early_stop.cpp.obj
[ 12%] Building CXX object CMakeFiles/lightgbm.dir/src/io/bin.cpp.obj
[ 14%] Building CXX object CMakeFiles/lightgbm.dir/src/io/config.cpp.obj
[ 16%] Building CXX object CMakeFiles/lightgbm.dir/src/io/dataset.cpp.obj
[ 18%] Building CXX object CMakeFiles/lightgbm.dir/src/io/dataset_loader.cpp.obj
[ 20%] Building CXX object CMakeFiles/lightgbm.dir/src/io/metadata.cpp.obj
[ 21%] Building CXX object CMakeFiles/lightgbm.dir/src/io/parser.cpp.obj
[ 23%] Building CXX object CMakeFiles/lightgbm.dir/src/io/tree.cpp.obj
[ 25%] Building CXX object CMakeFiles/lightgbm.dir/src/metric/dcg_calculator.cpp.obj
[ 27%] Building CXX object CMakeFiles/lightgbm.dir/src/metric/metric.cpp.obj
[ 29%] Building CXX object CMakeFiles/lightgbm.dir/src/objective/objective_function.cpp.obj
[ 30%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linker_topo.cpp.obj
[ 32%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linkers_mpi.cpp.obj
[ 34%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linkers_socket.cpp.obj
[ 36%] Building CXX object CMakeFiles/lightgbm.dir/src/network/network.cpp.obj
[ 38%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/data_parallel_tree_learner.cpp.obj
[ 40%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/feature_parallel_tree_learner.cpp.obj
[ 41%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/gpu_tree_learner.cpp.obj
[ 43%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/serial_tree_learner.cpp.obj
[ 45%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/tree_learner.cpp.obj
[ 47%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/voting_parallel_tree_learner.cpp.obj
[ 49%] Linking CXX executable ..\lightgbm.exe
[ 49%] Built target lightgbm
Scanning dependencies of target _lightgbm
[ 50%] Building CXX object CMakeFiles/_lightgbm.dir/src/c_api.cpp.obj
[ 52%] Building CXX object CMakeFiles/_lightgbm.dir/src/lightgbm_R.cpp.obj
[ 54%] Building CXX object CMakeFiles/_lightgbm.dir/src/application/application.cpp.obj
[ 56%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/boosting.cpp.obj
[ 58%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/gbdt.cpp.obj
[ 60%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/gbdt_prediction.cpp.obj
[ 61%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/prediction_early_stop.cpp.obj
[ 63%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/bin.cpp.obj
[ 65%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/config.cpp.obj
[ 67%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/dataset.cpp.obj
[ 69%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/dataset_loader.cpp.obj
[ 70%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/metadata.cpp.obj
[ 72%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/parser.cpp.obj
[ 74%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/tree.cpp.obj
[ 76%] Building CXX object CMakeFiles/_lightgbm.dir/src/metric/dcg_calculator.cpp.obj
[ 78%] Building CXX object CMakeFiles/_lightgbm.dir/src/metric/metric.cpp.obj
[ 80%] Building CXX object CMakeFiles/_lightgbm.dir/src/objective/objective_function.cpp.obj
[ 81%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linker_topo.cpp.obj
[ 83%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linkers_mpi.cpp.obj
[ 85%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linkers_socket.cpp.obj
[ 87%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/network.cpp.obj
[ 89%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/data_parallel_tree_learner.cpp.obj
[ 90%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/feature_parallel_tree_learner.cpp.obj
[ 92%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/gpu_tree_learner.cpp.obj
[ 94%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/serial_tree_learner.cpp.obj
[ 96%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/tree_learner.cpp.obj
[ 98%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/voting_parallel_tree_learner.cpp.obj
[100%] Linking CXX shared library ..\lib_lightgbm.dll
[100%] Built target _lightgbm
> devtools::install(file.path(lgb_git_dir, "LightGBM", "R-package", fsep = "\\"))
Installing lightgbm
"C:/PROGRA~1/R/R-34~1.0/bin/x64/R" --no-site-file --no-environ --no-save --no-restore --quiet CMD INSTALL "C:/tmp/RtmpSa5Bdv/LightGBM/R-package"  \
  --library="C:/Program Files/R/R-3.4.0/library" --install-tests 

* installing *source* package 'lightgbm' ...
** libs
installing via 'install.libs.R' to C:/Program Files/R/R-3.4.0/library/lightgbm
[1] "find library file: C:/tmp/RtmpSa5Bdv/LightGBM/R-package/../lib_lightgbm.dll"
** R
** data
** demo
** tests
** preparing package for lazy loading
** help
*** installing help indices
  converting help for package 'lightgbm'
    finding HTML links ... done
    agaricus.test                           html  
    agaricus.train                          html  
    dim                                     html  
    dimnames.lgb.Dataset                    html  
    getinfo                                 html  
    lgb.Dataset                             html  
    lgb.Dataset.construct                   html  
    lgb.Dataset.create.valid                html  
    lgb.Dataset.save                        html  
    lgb.Dataset.set.categorical             html  
    lgb.Dataset.set.reference               html  
    lgb.dump                                html  
    lgb.get.eval.result                     html  
    lgb.importance                          html  
    lgb.interprete                          html  
    lgb.load                                html  
    lgb.model.dt.tree                       html  
    lgb.plot.importance                     html  
    lgb.plot.interpretation                 html  
    lgb.prepare                             html  
    lgb.prepare2                            html  
    lgb.prepare_rules                       html  
    lgb.prepare_rules2                      html  
    lgb.save                                html  
    lgb.train                               html  
    lgb.unloader                            html  
    predict.lgb.Booster                     html  
    readRDS.lgb.Booster                     html  
    saveRDS.lgb.Booster                     html  
    setinfo                                 html  
    slice                                   html  
** building package indices
** testing if installed package can be loaded
* DONE (lightgbm)
> unlink(paste0(lgb_git_dir, "\\LightGBM"), recursive = TRUE, force = TRUE)

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 4, 2017

This should do it, but Visual Studio compilation is not working properly:

# Known elements
lgb_git_commit <- "r-withvs" # Put "" if master branch
lgb_git_compiler <- "vs" # Windows only: ["gcc", "vs"]
lgb_git_lib <- "C:\\LightGBM\\windows\\x64\\DLL\\lib_lightgbm.dll" # Put "" if using no precompiled dll/lib
lgb_git_repo <- "https://github.com/Microsoft/LightGBM" # Set it to something else from GitHub for other repositories
lgb_git_cores <- 4 # Specify number of cores for compilation here, ignored for Visual Studio build

# Generates temporary dir
lgb_git_dir <- tempdir()

# Check if it is Windows, because it create most issues
if (.Platform$OS.type == "windows") {
  
  # Create temp file
  lgb_git_file <- file.path(lgb_git_dir, "temp.bat", fsep = "\\")
  
  # Delete (old) temp LightGBM folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM", fsep = "\\")), recursive = TRUE, force = TRUE)
  
  # Use git to fetch data from repository
  cat(paste0("cd ", lgb_git_dir, "\n"), file = lgb_git_file)
  cat(paste0("git clone --recursive ", lgb_git_repo, "\n"), file = lgb_git_file, append = TRUE)
  cat(paste0("cd LightGBM", "\n"), file = lgb_git_file, append = TRUE)
  
  # Checkout specific commit if needed
  if (lgb_git_commit != "") {
    cat(paste0("git checkout ", lgb_git_commit, "\n"), file = lgb_git_file, append = TRUE)
  }
  
  # If no lib is specified, force compilation
  if (lgb_git_lib == "") {
    cat(paste0("mkdir build && cd build", "\n"), file = lgb_git_file, append = TRUE)
    
    # Check if compilation must be done using MinGW/gcc (default) or Visual Studio
    if (lgb_git_compiler == "gcc") {
      cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE)
      cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
      cat(paste0("mingw32-make.exe -j", lgb_git_cores), file = lgb_git_file, append = TRUE)
    } else {
      cat(paste0("cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..", "\n"), file = lgb_git_file, append = TRUE)
      cat(paste0("cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
      cat(paste0("cmake --build . --target ALL_BUILD --config DLL"), file = lgb_git_file, append = TRUE)
    }
    
  } else {
    cat(paste0("cp ", lgb_git_lib, " ", file.path(lgb_git_dir, "LightGBM", fsep = "\\"), "\n"), file = lgb_git_file, append = TRUE) # Move dll/lib
  }
  
  # Do actions
  system(lgb_git_file)
  
  # Install package
  devtools::install(file.path(lgb_git_dir, "LightGBM", "R-package", fsep = "\\"))
  
  # Get rid of the created temporary folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM", fsep = "\\")), recursive = TRUE, force = TRUE)
  
} else {
  
  # Create temp file
  lgb_git_file <- file.path(lgb_git_dir, "temp.sh")
  
  # Delete (old) temp LightGBM folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM")), recursive = TRUE, force = TRUE)
  
  # Use git to fetch data from repository
  cat(paste0("cd ", lgb_git_dir, "\n"), file = lgb_git_file)
  cat(paste0("git clone --recursive ", lgb_git_repo, "\n"), file = lgb_git_file, append = TRUE)
  cat(paste0("cd LightGBM", "\n"), file = lgb_git_file, append = TRUE)
  
  # Checkout specific commit if needed
  if (lgb_git_commit != "") {
    cat(paste0("git checkout ", lgb_git_commit, "\n"), file = lgb_git_file, append = TRUE)
  }
  
  # If no lib is specified, force compilation
  if (lgb_git_lib == "") {
    cat(paste0("mkdir build && cd build", "\n"), file = lgb_git_file, append = TRUE)
    cat(paste0("cmake ..", "\n"), file = lgb_git_file, append = TRUE)
    cat(paste0("cmake ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
    cat(paste0("make -j", lgb_git_cores), file = lgb_git_file, append = TRUE)
  } else {
    cat(paste0("cp ", lgb_git_lib, " ", file.path(lgb_git_dir, "LightGBM", fsep = "\\"), "\n"), file = lgb_git_file, append = TRUE) # Move dll/lib
  }
  
  # Do actions
  system(lgb_git_file)
  
  # Install package
  devtools::install(file.path(lgb_git_dir, "LightGBM", "R-package"))
  
  # Get rid of the created temporary folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM")), recursive = TRUE, force = TRUE)
  
}

Gives weird VS error about 2010 when I don't use 2010:

C:\Users\Laurae\Documents>cd C:\tmp\RtmpSa5Bdv 

C:\tmp\RtmpSa5Bdv>git clone --recursive https://github.com/Microsoft/LightGBM 
Cloning into 'LightGBM'...
Submodule 'include/boost/compute' (https://github.com/boostorg/compute) registered for path 'compute'
Cloning into 'compute'...
Submodule path 'compute': checked out '6de7f6448796f67958dde8de4569fb1ae649ee91'

C:\tmp\RtmpSa5Bdv>cd LightGBM 

C:\tmp\RtmpSa5Bdv\LightGBM>git checkout r-withvs 
Branch r-withvs set up to track remote branch r-withvs from origin.
Switched to a new branch 'r-withvs'

C:\tmp\RtmpSa5Bdv\LightGBM>mkdir build   && cd build 

C:\tmp\RtmpSa5Bdv\LightGBM\build>cmake -DCMAKE_GENERATOR_PLATFORM=x64 .. 
-- Building for: Visual Studio 15 2017
-- The C compiler identification is MSVC 19.11.25303.0
-- The CXX compiler identification is MSVC 19.11.25303.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/Preview/Community/VC/Tools/MSVC/14.11.25301/bin/HostX86/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/Preview/Community/VC/Tools/MSVC/14.11.25301/bin/HostX86/x64/cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/Preview/Community/VC/Tools/MSVC/14.11.25301/bin/HostX86/x64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/Preview/Community/VC/Tools/MSVC/14.11.25301/bin/HostX86/x64/cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Try OpenMP C flag = [/openmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Try OpenMP CXX flag = [/openmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Found OpenMP: /openmp  
-- Configuring done
-- Generating done
-- Build files have been written to: C:/tmp/RtmpSa5Bdv/LightGBM/build

C:\tmp\RtmpSa5Bdv\LightGBM\build>cmake -DCMAKE_GENERATOR_PLATFORM=x64 .. 
-- Configuring done
-- Generating done
-- Build files have been written to: C:/tmp/RtmpSa5Bdv/LightGBM/build

C:\tmp\RtmpSa5Bdv\LightGBM\build>cmake --build . --target ALL_BUILD --config DLL 
Microsoft (R) Build Engine version 15.3.118.39484
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 04/06/2017 08:10:13 PM.
Project "C:\tmp\RtmpSa5Bdv\LightGBM\build\ALL_BUILD.vcxproj" on node 1 (default targets).
Project "C:\tmp\RtmpSa5Bdv\LightGBM\build\ALL_BUILD.vcxproj" (1) is building "C:\tmp\RtmpSa5Bdv\LightGBM\build\ZERO_CHECK.vcxproj" (2) on node 1 (default targets).
C:\Program Files (x86)\Microsoft Visual Studio\Preview\Community\Common7\IDE\VC\VCTargets\Microsoft.Cpp.Platform.targets(55,5): error MSB8020: The build tools for Visual Studio 2010 (Platform Toolset = 'v100') cannot be found. To build using the v100 build tools, please install Visual Studio 2010 build tools.  Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Retarget solution". [C:\tmp\RtmpSa5Bdv\LightGBM\build\ZERO_CHECK.vcxproj]
Done Building Project "C:\tmp\RtmpSa5Bdv\LightGBM\build\ZERO_CHECK.vcxproj" (default targets) -- FAILED.
Done Building Project "C:\tmp\RtmpSa5Bdv\LightGBM\build\ALL_BUILD.vcxproj" (default targets) -- FAILED.

Build FAILED.

"C:\tmp\RtmpSa5Bdv\LightGBM\build\ALL_BUILD.vcxproj" (default target) (1) ->
"C:\tmp\RtmpSa5Bdv\LightGBM\build\ZERO_CHECK.vcxproj" (default target) (2) ->
(PlatformPrepareForBuild target) -> 
  C:\Program Files (x86)\Microsoft Visual Studio\Preview\Community\Common7\IDE\VC\VCTargets\Microsoft.Cpp.Platform.targets(55,5): error MSB8020: The build tools for Visual Studio 2010 (Platform Toolset = 'v100') cannot be found. To build using the v100 build tools, please install Visual Studio 2010 build tools.  Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Retarget solution". [C:\tmp\RtmpSa5Bdv\LightGBM\build\ZERO_CHECK.vcxproj]

    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.25

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 4, 2017

After many attempts, it eventually works with Visual Studio although user has to put path to devenv and msbuild:

# Known elements
lgb_git_commit <- "r-withvs" # Put "" if master branch
lgb_git_compiler <- "vs" # Windows only: ["gcc", "vs"] (MinGW or Visual Studio)
lgb_git_upgrade <- "C:\\Program Files (x86)\\Microsoft Visual Studio\\Preview\\Community\\Common7\\IDE" # For VS compilation: path to devenv of the appropriate Visual Studio compiler
lgb_git_msbuild <- "C:\\Program Files (x86)\\Microsoft Visual Studio\\Preview\\Community\\MSBuild\\15.0\\Bin" # For VS compilation: path to msbuild
lgb_git_lib <- "C:\\LightGBM\\windows\\x64\\DLL\\lib_lightgbm.dll" # Put "" if using no precompiled dll/lib
lgb_git_repo <- "https://github.com/Microsoft/LightGBM" # Set it to something else from GitHub for other repositories
lgb_git_cores <- 4 # Specify number of cores for compilation here, ignored for Visual Studio build

# Generates temporary dir
lgb_git_dir <- tempdir()

# Check if it is Windows, because it create most issues
if (.Platform$OS.type == "windows") {
  
  # Create temp file
  lgb_git_file <- file.path(lgb_git_dir, "temp.bat", fsep = "\\")
  
  # Delete (old) temp LightGBM folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM", fsep = "\\")), recursive = TRUE, force = TRUE)
  
  # Use git to fetch data from repository
  cat(paste0("cd ", lgb_git_dir, "\n"), file = lgb_git_file)
  cat(paste0("git clone --recursive ", lgb_git_repo, "\n"), file = lgb_git_file, append = TRUE)
  cat(paste0("cd LightGBM", "\n"), file = lgb_git_file, append = TRUE)
  
  # Checkout specific commit if needed
  if (lgb_git_commit != "") {
    cat(paste0("git checkout ", lgb_git_commit, "\n"), file = lgb_git_file, append = TRUE)
  }
  
  # If no lib is specified, force compilation
  if (lgb_git_lib == "") {
    
    # Check if compilation must be done using MinGW/gcc (default) or Visual Studio
    if (lgb_git_compiler == "gcc") {
      
      cat(paste0("mkdir build && cd build", "\n"), file = lgb_git_file, append = TRUE)
      cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE)
      cat(paste0("cmake -G \"MinGW Makefiles\" ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
      cat(paste0("mingw32-make.exe -j", lgb_git_cores), file = lgb_git_file, append = TRUE)
      
    } else {
      
      cat(paste0("\"", file.path(lgb_git_upgrade, "devenv", fsep = "\\"), "\" ./windows/LightGBM.sln /Upgrade", "\n"), file = lgb_git_file, append = TRUE)
      cat(paste0("\"", file.path(lgb_git_msbuild, "msbuild", fsep = "\\"), "\" ./windows/LightGBM.vcxproj /p:configuration=DLL /p:platform=x64", "\n"), file = lgb_git_file, append = TRUE)
      #cat(paste0("cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..", "\n"), file = lgb_git_file, append = TRUE)
      #cat(paste0("cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
      #cat(paste0("cmake --build . --target ALL_BUILD --config DLL"), file = lgb_git_file, append = TRUE)
      
    }
    
  } else {
    
    cat(paste0("cp ", lgb_git_lib, " ", file.path(lgb_git_dir, "LightGBM", fsep = "\\"), "\n"), file = lgb_git_file, append = TRUE) # Move dll/lib
    
  }
  
  # Do actions
  system(lgb_git_file)
  
  # Install package
  devtools::install(file.path(lgb_git_dir, "LightGBM", "R-package", fsep = "\\"))
  
  # Get rid of the created temporary folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM", fsep = "\\")), recursive = TRUE, force = TRUE)
  
} else {
  
  # Create temp file
  lgb_git_file <- file.path(lgb_git_dir, "temp.sh")
  
  # Delete (old) temp LightGBM folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM")), recursive = TRUE, force = TRUE)
  
  # Use git to fetch data from repository
  cat(paste0("cd ", lgb_git_dir, "\n"), file = lgb_git_file)
  cat(paste0("git clone --recursive ", lgb_git_repo, "\n"), file = lgb_git_file, append = TRUE)
  cat(paste0("cd LightGBM", "\n"), file = lgb_git_file, append = TRUE)
  
  # Checkout specific commit if needed
  if (lgb_git_commit != "") {
    cat(paste0("git checkout ", lgb_git_commit, "\n"), file = lgb_git_file, append = TRUE)
  }
  
  # If no lib is specified, force compilation
  if (lgb_git_lib == "") {
    cat(paste0("mkdir build && cd build", "\n"), file = lgb_git_file, append = TRUE)
    cat(paste0("cmake ..", "\n"), file = lgb_git_file, append = TRUE)
    cat(paste0("cmake ..", "\n"), file = lgb_git_file, append = TRUE) # Failsafe
    cat(paste0("make -j", lgb_git_cores), file = lgb_git_file, append = TRUE)
  } else {
    cat(paste0("cp ", lgb_git_lib, " ", file.path(lgb_git_dir, "LightGBM"), "\n"), file = lgb_git_file, append = TRUE) # Move dll/lib
  }
  
  # Do actions
  system(lgb_git_file)
  
  # Install package
  devtools::install(file.path(lgb_git_dir, "LightGBM", "R-package"))
  
  # Get rid of the created temporary folder
  unlink(paste0(file.path(lgb_git_dir, "LightGBM")), recursive = TRUE, force = TRUE)
  
}

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2 Thanks, I move these build command to install.libs.R . I think is is easier to build now.
I will fix the build from github now.

@guolinke guolinke changed the title Use pre-compiled dynamic library for R package. Compile R package by custom tool chain. Jun 5, 2017
@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 5, 2017

@guolinke Can you add a check for dll/lib existence to avoid running compilation? It seems we cannot install R package from local without recompiling from scratch now.

Also, I tested devtools::install_github installation, works perfectly (uses my Visual Studio first).

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2
I think using R CMD INSTALL --build . will auto skip the compiled files.

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 5, 2017

@guolinke It does indeed skip the compiled files.

Which way should we use to use precompiled Visual Studio DLL so the user do not have to download and install Visual Studio?

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2
Actually, it only need the http://landinghub.visualstudio.com/visual-cpp-build-tools (without visual studio IDE) to build the c++ code in windows.

BTW, I try this on ubuntu 14.04. However, the install.libs.R seems not be called. Is this a standard R feature ?

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 5, 2017

@guolinke The compilation setup is missing instructions for non Windows OS:

if (WINDOWS) {
  if(use_mingw){
    cmake_cmd <- paste0(cmake_cmd, " -G \"MinGW Makefiles\" ")
    build_cmd <- "mingw32-make.exe -j"
  } else{
    cmake_cmd <- paste0(cmake_cmd, " -DCMAKE_GENERATOR_PLATFORM=x64 ")
    build_cmd <- "cmake --build . --target _lightgbm  --config Release"
    lib_folder <- paste0(R_PACKAGE_SOURCE, '/src/Release')
  }
}

This is weird also if it is not called at all, because there are CRAN packages using install.libs.R apparently (and they do not seem to malfunction in unix environments).

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 5, 2017

@guolinke I think you can revert your edits to commit c379a2f.

I created a very simple package to install LightGBM from repository:

lgb.dl(commit = "c379a2f",
       #libdll = "C:\\xgboost\\LightGBM\\windows\\x64\\DLL\\lib_lightgbm.dll",
       compiler = "vs")

It will install LightGBM correctly, while using the DLL you provide if you provide one (otherwise, it will build LightGBM from scratch).

Use this to install my package installer: devtools::install("Laurae2/lgbdl") if you want to test. On my lubuntu box it works out of the box.

https://github.com/Laurae2/lgbdl (if users do not want to install my package, they can copy the function to run it).

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2 The command of linux is set here:
https://github.com/Microsoft/LightGBM/blob/92ebb67331be3ec5d91a724f0bfd278e307dc938/R-package/src/install.libs.R#L27-L28

After add the empty Makevars, the build in linux is success.

BTW, why need to revert that commit ?
I think it is easier in oxs build now.

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@Laurae2
I think this PR is ready now.
Do you have any comments ?

@bushmanov
Copy link

Successfully built with this instructions

[LightGBM] [Info] This is the GPU trainer!!
[LightGBM] [Info] Total Bins 137
[LightGBM] [Info] Number of data: 5211, number of used features: 116
[LightGBM] [Info] Using GPU Device: GeForce GTX 1080 Ti, Vendor: NVIDIA Corporation
[LightGBM] [Info] Compiling OpenCL Kernel with 16 bins...

but crashed at the last line (even though as I said there are no problem with standard build instructions and Python interface). Any suggestions are greatly appreciated!

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@bushmanov
can you provide the build logs ?

@Laurae2
Copy link
Contributor

Laurae2 commented Jun 5, 2017

@guolinke Seems OK for me. I can work later on a script which will allow to customize installation so we can install more easily from source while using custom flags. You can merge, I tested on all boxes (Win/Mac/Linux), compiles and installs without error.

@guolinke guolinke merged commit f98d75f into master Jun 5, 2017
@bushmanov
Copy link

@guolinke

-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Try OpenMP C flag = [-fopenmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Try OpenMP CXX flag = [-fopenmp]
-- Performing Test OpenMP_FLAG_DETECTED
-- Performing Test OpenMP_FLAG_DETECTED - Success
-- Found OpenMP: -fopenmp  
-- Looking for CL_VERSION_2_0
-- Looking for CL_VERSION_2_0 - found
-- Found OpenCL: /usr/lib/x86_64-linux-gnu/libOpenCL.so (found version "2.0") 
-- OpenCL include directory:/usr/include
-- Boost version: 1.58.0
-- Found the following Boost libraries:
--   filesystem
--   system
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/RtmpvhTUsg/R.INSTALLc1468977022/lightgbm/src/build
Scanning dependencies of target lightgbm
Scanning dependencies of target _lightgbm
[  1%] Building CXX object CMakeFiles/lightgbm.dir/src/application/application.cpp.o
[  3%] Building CXX object CMakeFiles/lightgbm.dir/src/main.cpp.o
[  5%] Building CXX object CMakeFiles/lightgbm.dir/src/io/dataset.cpp.o
[  7%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/prediction_early_stop.cpp.o
[  9%] Building CXX object CMakeFiles/lightgbm.dir/src/io/bin.cpp.o
[ 10%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/tree.cpp.o
[ 12%] Building CXX object CMakeFiles/lightgbm.dir/src/io/tree.cpp.o
[ 14%] Building CXX object CMakeFiles/_lightgbm.dir/src/application/application.cpp.o
[ 16%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/data_parallel_tree_learner.cpp.o
[ 18%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/gbdt_prediction.cpp.o
[ 20%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/config.cpp.o
[ 21%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/gbdt_prediction.cpp.o
[ 23%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/dataset_loader.cpp.o
[ 25%] Building CXX object CMakeFiles/_lightgbm.dir/src/c_api.cpp.o
[ 29%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/boosting.cpp.o
[ 30%] Building CXX object CMakeFiles/lightgbm.dir/src/metric/dcg_calculator.cpp.o
[ 32%] Building CXX object CMakeFiles/_lightgbm.dir/src/metric/dcg_calculator.cpp.o
[ 34%] Building CXX object CMakeFiles/lightgbm.dir/src/boosting/gbdt.cpp.o
[ 36%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linkers_mpi.cpp.o
[ 38%] Building CXX object CMakeFiles/lightgbm.dir/src/io/parser.cpp.o
[ 40%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/boosting.cpp.o
[ 41%] Building CXX object CMakeFiles/lightgbm.dir/src/io/metadata.cpp.o
[ 43%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/network.cpp.o
[ 45%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/gpu_tree_learner.cpp.o
[ 47%] Building CXX object CMakeFiles/lightgbm.dir/src/io/dataset_loader.cpp.o
[ 49%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linker_topo.cpp.o
[ 50%] Building CXX object CMakeFiles/lightgbm.dir/src/io/config.cpp.o
[ 52%] Building CXX object CMakeFiles/lightgbm.dir/src/network/network.cpp.o
[ 54%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/metadata.cpp.o
[ 56%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/serial_tree_learner.cpp.o
[ 58%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/dataset.cpp.o
[ 60%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/gbdt.cpp.o
[ 61%] Building CXX object CMakeFiles/_lightgbm.dir/src/boosting/prediction_early_stop.cpp.o
[ 63%] Building CXX object CMakeFiles/_lightgbm.dir/src/metric/metric.cpp.o
[ 65%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linkers_socket.cpp.o
[ 67%] Building CXX object CMakeFiles/lightgbm.dir/src/network/linkers_mpi.cpp.o
[ 69%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linkers_socket.cpp.o
[ 70%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/parser.cpp.o
[ 72%] Building CXX object CMakeFiles/_lightgbm.dir/src/io/bin.cpp.o
[ 74%] Building CXX object CMakeFiles/_lightgbm.dir/src/objective/objective_function.cpp.o
[ 76%] Building CXX object CMakeFiles/_lightgbm.dir/src/network/linker_topo.cpp.o
[ 78%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/tree_learner.cpp.o
[ 80%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/gpu_tree_learner.cpp.o
[ 81%] Building CXX object CMakeFiles/lightgbm.dir/src/objective/objective_function.cpp.o
[ 81%] Building CXX object CMakeFiles/_lightgbm.dir/src/lightgbm_R.cpp.o
[ 83%] Building CXX object CMakeFiles/lightgbm.dir/src/metric/metric.cpp.o
[ 85%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/voting_parallel_tree_learner.cpp.o
[ 87%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/data_parallel_tree_learner.cpp.o
[ 89%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/voting_parallel_tree_learner.cpp.o
[ 90%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/feature_parallel_tree_learner.cpp.o
[ 92%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/tree_learner.cpp.o
[ 94%] Building CXX object CMakeFiles/lightgbm.dir/src/treelearner/feature_parallel_tree_learner.cpp.o
[ 96%] Building CXX object CMakeFiles/_lightgbm.dir/src/treelearner/serial_tree_learner.cpp.o
[ 98%] Linking CXX executable ../lightgbm
[100%] Linking CXX shared library ../lib_lightgbm.so
[100%] Built target _lightgbm
[100%] Built target lightgbm
[1] "find library file: /tmp/RtmpvhTUsg/R.INSTALLc1468977022/lightgbm/src/lib_lightgbm.so"
** R
** data
** demo
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (lightgbm)

@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@bushmanov From the log, the build with GPU is fine. I am not sure why it freezes.
@huanzhang12 Do you have any ideas ?

@guolinke guolinke deleted the r-withvs branch June 5, 2017 12:19
@guolinke
Copy link
Collaborator Author

guolinke commented Jun 5, 2017

@bushmanov Can you also provide the log of your successful python build (include the build log and python output log) .

@bushmanov
Copy link

The issue has been resolved after restarting RStudio

guolinke added a commit that referenced this pull request Oct 9, 2017
* add R's library file to vs project and cmake.

* support using dll built by vs.

* better search for the library file.

* remove mingw related doc .

* update document.

* Let R handle the library compile.

* try fix build from github.

* Update README.md

* cleaner build.

* fix the install problem in linux.

* Update README.md
@lock lock bot locked as resolved and limited conversation to collaborators Mar 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants