From 22341aeec756240e5cbbc571e17360c617f606b1 Mon Sep 17 00:00:00 2001 From: vandenman Date: Tue, 15 Aug 2023 17:01:19 +0200 Subject: [PATCH] use new module installation mechanism very basic functionality works start on making hashes work seems more or less functional now started rewriting cmake, stuff compiles but crashes at runtime everything seems functional on Linux windows fixes, stuff compiles but weird runtime error building on windows works from a clean build, but more testing is needed more tweaks, update to renv 1.0.2 updates for fallback without lockfile start unifying stuff across OSes autogenerated lockfiles seem to be work okay but need more testing reorganize file + pkgdepends fallback bump jaspModuleInstaller spaces -> tabs bump jaspModuleInstaller spaces -> tabs moved getModuleDependencies to jaspModuleInstaller call setupRenv in setup_renv_rcpp_rinside_jaspModuleInstaller.R.in remove custom Matrix installation make configuration work on macos compilation still fails though... do follow symlinks otherwise it patches nothing move searching for fortran outside of the "does framework not exist if()f" jaspModuleInstaller and fixing of r pkgs needs jaspEngine so change the order in which things are installed add R_LIBS for windows and macos make windows start --- .gitmodules | 3 + Desktop/modules/dynamicmodule.cpp | 2 +- Desktop/utilities/processhelper.cpp | 15 +- Engine/engine.cpp | 5 +- Engine/jaspModuleInstaller | 1 + Modules/Rcpp_RInside.lock | 23 ++ Modules/install-RInside.R.in | 9 - Modules/install-jaspBase.R.in | 64 ----- Modules/install-jaspModuleInstaller.R.in | 93 +++++++ Modules/install-module.R.in | 68 +++--- Modules/pkgdepends.lock | 243 +++++++++++++++++++ Modules/setup_renv_rcpp_rinside.R.in | 65 +++++ R-Interface/CMakeLists.txt | 17 +- R-Interface/jasprcpp.cpp | 56 +++-- R-Interface/jasprcpp_interface.h | 1 + Tools/CMake/Modules.cmake | 49 ++-- Tools/CMake/Patch.cmake | 8 +- Tools/CMake/R.cmake | 293 +++++++---------------- Tools/find_package_path.R | 25 ++ 19 files changed, 664 insertions(+), 376 deletions(-) create mode 160000 Engine/jaspModuleInstaller create mode 100644 Modules/Rcpp_RInside.lock delete mode 100644 Modules/install-RInside.R.in delete mode 100644 Modules/install-jaspBase.R.in create mode 100644 Modules/install-jaspModuleInstaller.R.in create mode 100644 Modules/pkgdepends.lock create mode 100644 Modules/setup_renv_rcpp_rinside.R.in create mode 100755 Tools/find_package_path.R diff --git a/.gitmodules b/.gitmodules index 0c7de41f8a6..20a91f2af00 100644 --- a/.gitmodules +++ b/.gitmodules @@ -139,3 +139,6 @@ [submodule "Modules/jaspProcess"] path = Modules/jaspProcess url = https://github.com/jasp-stats/jaspProcess +[submodule "Engine/jaspModuleInstaller"] + path = Engine/jaspModuleInstaller + url = https://github.com/vandenman/jaspModuleInstaller.git diff --git a/Desktop/modules/dynamicmodule.cpp b/Desktop/modules/dynamicmodule.cpp index 4b5145a21ac..553192c2dc2 100644 --- a/Desktop/modules/dynamicmodule.cpp +++ b/Desktop/modules/dynamicmodule.cpp @@ -399,7 +399,7 @@ Json::Value DynamicModule::requestJsonForPackageLoadingRequest() std::string DynamicModule::getLibPathsToUse() const { - return "c('" + AppDirs::rHome().toStdString() + "/library', '" + shortenWinPaths(moduleRLibrary()).toStdString() + "')"; + return "c('" + shortenWinPaths(moduleRLibrary()).toStdString() + "', '" + AppDirs::rHome().toStdString() + "/library')"; } ///It would probably be better to move all of this code to jasp-r-pkg or something, but for now this works fine. diff --git a/Desktop/utilities/processhelper.cpp b/Desktop/utilities/processhelper.cpp index 0c437c3f27a..6adecc7edbd 100644 --- a/Desktop/utilities/processhelper.cpp +++ b/Desktop/utilities/processhelper.cpp @@ -54,7 +54,7 @@ QProcessEnvironment ProcessHelper::getProcessEnvironmentForJaspEngine() #undef ARCH_SUBPATH - env.insert("R_LIBS", R_HOME + "/library"); + env.insert("R_LIBS", programDir.absoluteFilePath(R_HOME + "/R_cpp_includes_library") + ";" + R_HOME + "/library"); env.insert("R_ENVIRON", "something-which-doesn't-exist"); env.insert("R_PROFILE", "something-which-doesn't-exist"); @@ -72,7 +72,7 @@ QProcessEnvironment ProcessHelper::getProcessEnvironmentForJaspEngine() env.insert("R_HOME", rHome.absolutePath()); env.insert("RHOME", rHome.absolutePath()); //For Rscript env.insert("JASP_R_HOME", rHome.absolutePath()); //Used by the modified R script in jasp-required-files/Framework/etc/bin to make sure we use the actual R of JASP! (https://github.com/jasp-stats/INTERNAL-jasp/issues/452) - env.insert("R_LIBS", rHome.absoluteFilePath("library") + ":" + programDir.absoluteFilePath("R/library")); + env.insert("R_LIBS", programDir.absoluteFilePath("../R/R_cpp_includes_library") + ":" + rHome.absoluteFilePath("library") + ":" + programDir.absoluteFilePath("R/library") + custom_R_library); env.insert("JAGS_HOME", rHome.absolutePath() + "/opt/jags/lib/JAGS/"); // env.insert("JAGS_LIBDIR", rHome.absolutePath() + "/opt/jags/lib/"); @@ -85,9 +85,11 @@ QProcessEnvironment ProcessHelper::getProcessEnvironmentForJaspEngine() env.insert("TZDIR", TZDIR); #else // linux - env.insert("LD_LIBRARY_PATH", rHome.absoluteFilePath("lib") + ":" + rHome.absoluteFilePath("library/RInside/lib") + ":" + rHome.absoluteFilePath("library/Rcpp/lib") + ":" + rHome.absoluteFilePath("site-library/RInside/lib") + ":" + rHome.absoluteFilePath("site-library/Rcpp/lib") + ":/app/lib/:/app/lib64/"); +// env.insert("LD_LIBRARY_PATH", rHome.absoluteFilePath("lib") + ":" + rHome.absoluteFilePath("library/RInside/lib") + ":" + rHome.absoluteFilePath("library/Rcpp/lib") + ":" + rHome.absoluteFilePath("site-library/RInside/lib") + ":" + rHome.absoluteFilePath("site-library/Rcpp/lib") + ":/app/lib/:/app/lib64/"); env.insert("R_HOME", rHome.absolutePath()); - env.insert("R_LIBS", programDir.absoluteFilePath("R/library") + custom_R_library + ":" + rHome.absoluteFilePath("library") + ":" + rHome.absoluteFilePath("site-library")); +// env.insert("R_LIBS", programDir.absoluteFilePath("R/library") + custom_R_library + ":" + rHome.absoluteFilePath("library") + ":" + rHome.absoluteFilePath("site-library") + ":" + programDir.absoluteFilePath("../R/R_cpp_includes_library")); + // TODO: the last one should be the sandbox, not the actual library! + env.insert("R_LIBS", programDir.absoluteFilePath("../R/R_cpp_includes_library") + ":" + programDir.absoluteFilePath("R/library") + custom_R_library); #endif env.insert("R_LIBS_SITE", ""); @@ -98,5 +100,10 @@ QProcessEnvironment ProcessHelper::getProcessEnvironmentForJaspEngine() env.insert("R_LIBS_USER", (AppDirs::programDir().absolutePath().toStdString() + "/../R/library").c_str()); #endif + Log::log() << "R_LIBS:" << env.value("R_LIBS") << "\n" << + "R_LIBS_USER:" << env.value("R_LIBS_USER") << "\n" << + "LD_LIBRARY_PATH:" << env.value("LD_LIBRARY_PATH") << "\n" << + std::endl; + return(env); } diff --git a/Engine/engine.cpp b/Engine/engine.cpp index 5e8078efd31..c584572839b 100644 --- a/Engine/engine.cpp +++ b/Engine/engine.cpp @@ -490,13 +490,16 @@ void Engine::receiveModuleRequestMessage(const Json::Value & jsonRequest) std::string moduleCode = jsonRequest["moduleCode"].asString(); std::string moduleName = jsonRequest["moduleName"].asString(); - Log::log() << "About to run module request for module '" << moduleName << "' and code to run:\n'" << moduleCode << "'" << std::endl; + Log::log() << "About to run module request for module '" << moduleName << "' and code to run:\n'" << moduleCode << "'" << std::endl; std::string result = jaspRCPP_evalRCode(moduleCode.c_str(), false); bool succes = result == "succes!"; //Defined in DynamicModule::succesResultString() Log::log() << "Was " << (succes ? "succesful" : "a failure") << ", now crafting answer." << std::endl; + if(moduleStatusFromString((moduleRequest)) == moduleStatus::loading) + jaspRCPP_init_jaspBase(); + Json::Value jsonAnswer = Json::objectValue; jsonAnswer["moduleRequest"] = moduleRequest; diff --git a/Engine/jaspModuleInstaller b/Engine/jaspModuleInstaller new file mode 160000 index 00000000000..89ee61df92b --- /dev/null +++ b/Engine/jaspModuleInstaller @@ -0,0 +1 @@ +Subproject commit 89ee61df92b76a85b5d5f237674b185cee63e0b7 diff --git a/Modules/Rcpp_RInside.lock b/Modules/Rcpp_RInside.lock new file mode 100644 index 00000000000..640b13c42ea --- /dev/null +++ b/Modules/Rcpp_RInside.lock @@ -0,0 +1,23 @@ +{ + "R": { + "Version": "4.3.1", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cran.rstudio.com" + } + ] + }, + "Packages": { + "RInside": { + "Package": "RInside", + "Version": "0.2.18", + "Source": "Repository" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.0.11", + "Source": "Repository" + } + } +} diff --git a/Modules/install-RInside.R.in b/Modules/install-RInside.R.in deleted file mode 100644 index db0ed374804..00000000000 --- a/Modules/install-RInside.R.in +++ /dev/null @@ -1,9 +0,0 @@ -# Generated from install-RInside.R.in -# -# Installs `RInside` and `Rcpp`. While `Rcpp` is a dependency of the `RInside`, -# I've ran into situation where installing `RInside` doesn't install the `Rcpp`. -# - -.libPaths(c("@R_LIBRARY_PATH@")) -#We need building from source on linux in any case and on windows because otherwise lots of CRAN env-vars get baked into RInside... -install.packages(c('RInside', 'Rcpp'), type = ifelse(Sys.info()["sysname"] == "Darwin", "binary", "source"), lib='@R_LIBRARY_PATH@', repos='@R_REPOSITORY@', INSTALL_opts='--no-multiarch --no-docs --no-test-load') \ No newline at end of file diff --git a/Modules/install-jaspBase.R.in b/Modules/install-jaspBase.R.in deleted file mode 100644 index ae167fa5a21..00000000000 --- a/Modules/install-jaspBase.R.in +++ /dev/null @@ -1,64 +0,0 @@ -# Generated from install-jaspBase.R.in -# -Sys.setenv(GITHUB_PAT="@GITHUB_PAT@") -Sys.setenv(RENV_PATHS_ROOT="@MODULES_RENV_ROOT_PATH@") -Sys.setenv(RENV_PATHS_CACHE="@MODULES_RENV_CACHE_PATH@") -Sys.setenv(JASPENGINE_LOCATION="@JASP_ENGINE_PATH@/JASPEngine") - -#Load the post-install fixes from jaspBase. Think Baron von Munchausen ;) -source("@PROJECT_SOURCE_DIR@/Engine/jaspBase/R/utility.R") -source("@PROJECT_SOURCE_DIR@/Engine/jaspBase/R/checkSums.R") -source("@PROJECT_SOURCE_DIR@/Engine/jaspBase/R/assignFunctionInPackage.R") -source("@PROJECT_SOURCE_DIR@/Engine/jaspBase/R/moduleInstall.R") - -# The R_LIBRARY_PATH might already be there, but depending on the configuration -# of the CMake, we might be installing in a different location, so, I just add -# it anyway! It gets to if-y. - -if (@IS_FLATPAK_USED@) { - source("/app/lib64/Rprofile.R") - options(repos = "@R_REPOSITORY@") -} - -.libPaths(c("@R_LIBRARY_PATH@")) - -modulePkg <- "@PROJECT_SOURCE_DIR@/Engine/jaspBase" -moduleLibrary <- "@R_LIBRARY_PATH@" -prompt <- FALSE - -if (md5SumsChanged(modulePkg, moduleLibrary)) { - options( - renv.cache.linkable = FALSE, - configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/Common'") - ) - - Sys.setenv(JASP_R_INTERFACE_LIBRARY="Oh yes indeed") - setupRenv("@R_LIBRARY_PATH@", modulePkg) - - renv::hydrate(library = moduleLibrary, project = modulePkg, sources=moduleLibrary) - options(renv.config.install.verbose = TRUE) - renv::install(package = modulePkg, project = modulePkg, library = moduleLibrary, prompt = prompt) - - correctlyInstalled <- installModulePkg(modulePkg, moduleLibrary, prompt, cacheAble=TRUE) - - if (correctlyInstalled) - writeMd5Sums(modulePkg, moduleLibrary) - - -#This is necessary because of conflicts with Matrix dep of base R lib. -#Can be removed when a new version of R updates its Matrix - if (!@IS_FLATPAK_USED@) { - - if (Sys.info()["sysname"] == "Darwin") - options(pkgType = "source") - - renv::install("Matrix", library = moduleLibrary, prompt = prompt) - } -} - -# Converting the absolute symlinks to relative symlinks on macOS -# Todo, I can do this using CMake like I do on Windows -if (Sys.info()["sysname"] == "Darwin") { - source('@MODULES_BINARY_PATH@/symlinkTools.R') - convertAbsoluteSymlinksToRelative('@R_LIBRARY_PATH@', '@MODULES_RENV_CACHE_PATH@') -} diff --git a/Modules/install-jaspModuleInstaller.R.in b/Modules/install-jaspModuleInstaller.R.in new file mode 100644 index 00000000000..7c6b214e07e --- /dev/null +++ b/Modules/install-jaspModuleInstaller.R.in @@ -0,0 +1,93 @@ +# Generated from install-jaspBase.R.in +# +Sys.setenv(GITHUB_PAT = "@GITHUB_PAT@") +Sys.setenv(RENV_PATHS_ROOT = "@MODULES_RENV_ROOT_PATH@") +Sys.setenv(RENV_PATHS_CACHE = "@MODULES_RENV_CACHE_PATH@") +Sys.setenv(RENV_PATHS_SANDBOX = "@RENV_SANDBOX@") +Sys.setenv(JASPENGINE_LOCATION = "@JASP_ENGINE_PATH@/JASPEngine") + +#Load the post-install fixes from jaspBase. Think Baron von Munchhausen ;) +source("@PROJECT_SOURCE_DIR@/Engine/jaspModuleInstaller/R/renvOverrides.R") +source("@PROJECT_SOURCE_DIR@/Engine/jaspModuleInstaller/R/checksums.R") +source("@PROJECT_SOURCE_DIR@/Engine/jaspModuleInstaller/R/utils.R") +source("@PROJECT_SOURCE_DIR@/Engine/jaspModuleInstaller/R/installModule.R") + +# The R_LIBRARY_PATH might already be there, but depending on the configuration +# of the CMake, we might be installing in a different location, so, I just add +# it anyway! It gets to if-y. + +if (@IS_FLATPAK_USED@) { + source("/app/lib64/Rprofile.R") + options(repos = "@R_REPOSITORY@") +} + +.libPaths("@RENV_LIBRARY@") +sandboxPaths <- renv:::renv_sandbox_activate() + +JASPMODULEINSTALLER_LIBRARY <- "@JASPMODULEINSTALLER_LIBRARY@" +PKGDEPENDS_LIBRARY <- "@PKGDEPENDS_LIBRARY@" +RENV_LIBRARY <- "@RENV_LIBRARY@" +R_CPP_INCLUDES_LIBRARY <- "@R_CPP_INCLUDES_LIBRARY@" + +ENGINE <- file.path("@PROJECT_SOURCE_DIR@", "Engine") +MODULES <- file.path("@PROJECT_SOURCE_DIR@", "Modules") +TOOLS <- file.path("@PROJECT_SOURCE_DIR@", "Tools") + + +modulePkg <- file.path("@PROJECT_SOURCE_DIR@", "Engine", "jaspModuleInstaller") + +cat("Restoring pkgdepends\n") +setupRenv(PKGDEPENDS_LIBRARY) +renv::restore( + library = PKGDEPENDS_LIBRARY, + lockfile = file.path(MODULES, "pkgdepends.lock"), + clean = TRUE +) + +cat("Restoring jaspModuleInstaller\n") +setupRenv(JASPMODULEINSTALLER_LIBRARY) +renv::restore( + library = JASPMODULEINSTALLER_LIBRARY, + lockfile = file.path(ENGINE, "jaspModuleInstaller", "renv.lock"), + exclude = "jaspModuleInstaller", # otherwise "clean" would remove jaspModuleInstaller + clean = TRUE +) + +print("Installing jaspModuleInstaller") +.libPaths(JASPMODULEINSTALLER_LIBRARY) +setupRenv("@R_LIBRARY_PATH@", modulePkg) + +record <- createLocalRecord(modulePkg, getModuleInfo(modulePkg), cacheAble = FALSE, addJaspToVersion = FALSE) +lf <- renv::lockfile_read(file.path(modulePkg, "renv.lock")) +lf <- renv::record(record, lockfile = lf) +cat(".libPaths()", .libPaths(), sep = "\n") + +# remove the package if it is installed, otherwise renv doesn't realize we want to reinstall it +pkgName <- basename(modulePkg) +if (dir.exists(file.path(.libPaths()[1L], pkgName))) + utils::remove.packages(pkgs = pkgName, lib = .libPaths()[1L]) + +renv::restore(lockfile = lf, library = .libPaths(), rebuild = pkgName) + + + +print("jaspModuleInstaller::writeModuleStatusObject(@PROJECT_SOURCE_DIR@") +jaspModuleInstaller::writeModuleStatusObject("@PROJECT_SOURCE_DIR@") + +#This is necessary because of conflicts with Matrix dep of base R lib. +#Can be removed when a new version of R updates its Matrix +if (!@IS_FLATPAK_USED@) { + + if (Sys.info()["sysname"] == "Darwin") { + options(pkgType = "source") + } + + renv::install("Matrix", library = JASPMODULEINSTALLER_LIBRARY, prompt = FALSE) +} + +# Converting the absolute symlinks to relative symlinks on macOS +# Todo, I can do this using CMake like I do on Windows +if (Sys.info()["sysname"] == "Darwin") { + source('@MODULES_BINARY_PATH@/symlinkTools.R') + convertAbsoluteSymlinksToRelative('@R_LIBRARY_PATH@', '@MODULES_RENV_CACHE_PATH@') +} diff --git a/Modules/install-module.R.in b/Modules/install-module.R.in index 4ebd0a092c5..4038b69fc3e 100644 --- a/Modules/install-module.R.in +++ b/Modules/install-module.R.in @@ -1,60 +1,54 @@ # Generated from install-module.R.in # -Sys.setenv(PATH=paste0("@R_HOME_PATH@/bin", .Platform$path.sep, Sys.getenv("PATH"))) #Make sure any Rscript calls use ours -Sys.setenv(RHOME="@R_HOME_PATH@") #Rscript looks for RHOME not R_HOME -Sys.setenv(GITHUB_PAT="@GITHUB_PAT@") -Sys.setenv(RENV_PATHS_ROOT="@MODULES_RENV_ROOT_PATH@") -Sys.setenv(RENV_PATHS_CACHE="@MODULES_RENV_CACHE_PATH@") -Sys.setenv(JASPENGINE_LOCATION="@JASP_ENGINE_PATH@/JASPEngine") -Sys.setenv(JAGS_PREFIX="@jags_HOME@") -Sys.setenv(JAGS_INCLUDEDIR="@jags_INCLUDE_DIRS@") -Sys.setenv(JAGS_LIBDIR="@jags_LIBRARY_DIRS@") -Sys.setenv(JASP_R_INTERFACE_LIBRARY="Yes, do it") +Sys.setenv(PATH=paste0(file.path("@R_HOME_PATH@", "bin"), .Platform$path.sep, Sys.getenv("PATH"))) #Make sure any Rscript calls use ours +Sys.setenv(RHOME = "@R_HOME_PATH@") #Rscript looks for RHOME not R_HOME +Sys.setenv(GITHUB_PAT = "@GITHUB_PAT@") +Sys.setenv(RENV_PATHS_ROOT = "@MODULES_RENV_ROOT_PATH@") +Sys.setenv(RENV_PATHS_CACHE = "@MODULES_RENV_CACHE_PATH@") +Sys.setenv(RENV_PATHS_SANDBOX = "@RENV_SANDBOX@") +Sys.setenv(JASPENGINE_LOCATION = "@JASP_ENGINE_PATH@/JASPEngine") +Sys.setenv(JAGS_PREFIX = "@jags_HOME@") +Sys.setenv(JAGS_INCLUDEDIR = "@jags_INCLUDE_DIRS@") +Sys.setenv(JAGS_LIBDIR = "@jags_LIBRARY_DIRS@") +Sys.setenv(JASP_R_INTERFACE_LIBRARY = "Yes, do it") options(renv.config.install.verbose = TRUE) if (@IS_LINUX_LOCAL_BUILD@) { - # Only set when building using LINUX_LOCAL_BUILD. This is to help jags finds its libraries - Sys.setenv(LD_LIBRARY_PATH="@jags_LIBRARY_DIRS@") + # Only set when building using LINUX_LOCAL_BUILD. This is to help jags finds its libraries + Sys.setenv(LD_LIBRARY_PATH="@jags_LIBRARY_DIRS@") } if (@IS_FLATPAK_USED@) { - source('/app/lib64/Rprofile.R'); + source('/app/lib64/Rprofile.R'); } -# The R_LIBRARY_PATH might already be there, but depending on the configuration -# of the CMake, we might be installing in a different location, so, I just add -# it anyway! It gets to if-y. -.libPaths(c("@R_LIBRARY_PATH@")) +.libPaths("@JASPMODULEINSTALLER_LIBRARY@") +sandboxPaths <- renv:::renv_sandbox_activate() options( - configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/Common'") #Needed for flatpak build as it keeps recompiling jaspBase (which it shouldnt of course but I dont know why) and this is an easy fix to get it to work now + configure.vars = c(jaspBase = "INCLUDE_DIR='@PROJECT_SOURCE_DIR@/Common'"), #Needed for flatpak build as it keeps recompiling jaspBase (which it shouldnt of course but I dont know why) and this is an easy fix to get it to work now + PKGDEPENDS_LIBRARY = "@PKGDEPENDS_LIBRARY@" ) -if (jaspBase::getOS() == "osx") { - options(pkgType = "mac.binary") -} else if (jaspBase::getOS() == "windows") { - options(pkgType = "win.binary") -} - -# Related to the comment above, there is variable here called, -# `libPathsToUse` but it is not connected to anything. If this works, -# then, I don't need to set the libPaths() anymore perhaps. -result <- jaspBase::installJaspModule("@MODULES_SOURCE_PATH@/@MODULE@", - repos="@R_REPOSITORY@", - moduleLibrary="@MODULES_BINARY_PATH@/@MODULE@", - onlyModPkg=FALSE, - libPathsToUse='', - frameworkLibrary="@R_LIBRARY_PATH@") +options(error = recover) +jaspModuleInstaller::installJaspModule( + modulePkg = "@MODULES_SOURCE_PATH@/@MODULE@", + repos = "@R_REPOSITORY@", + moduleLibrary = "@MODULES_BINARY_PATH@/@MODULE@", + onlyModPkg = FALSE, + frameworkLibrary = "@R_LIBRARY_PATH@" +) +result <- "succes" if (result == "succes") { - cat(NULL, file="@MODULES_RENV_ROOT_PATH@/@MODULE@-installed-successfully.log") + cat(NULL, file="@MODULES_RENV_ROOT_PATH@/@MODULE@-installed-successfully.log") } # Converting the absolute symlinks to relative symlinks on macOS # Todo, I can do this using CMake like I do on Windows -if (Sys.info()["sysname"] == "Darwin") { - source('@MODULES_BINARY_PATH@/symlinkTools.R') - convertAbsoluteSymlinksToRelative('@MODULES_BINARY_PATH@', '@MODULES_RENV_CACHE_PATH@') +if (Sys.info()["sysname"] == "Darwin") { + source('@MODULES_BINARY_PATH@/symlinkTools.R') + convertAbsoluteSymlinksToRelative('@MODULES_BINARY_PATH@', '@MODULES_RENV_CACHE_PATH@') } diff --git a/Modules/pkgdepends.lock b/Modules/pkgdepends.lock new file mode 100644 index 00000000000..0f36f47886a --- /dev/null +++ b/Modules/pkgdepends.lock @@ -0,0 +1,243 @@ +{ + "R": { + "Version": "4.3.1", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "R6": { + "Package": "R6", + "Version": "2.5.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "470851b6d5d0ac559e9d01bb352b4021" + }, + "callr": { + "Package": "callr", + "Version": "3.7.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "processx", + "utils" + ], + "Hash": "9b2191ede20fa29828139b9900922e51" + }, + "cli": { + "Package": "cli", + "Version": "3.6.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "89e6d8219950eac806ae0c489052048a" + }, + "crayon": { + "Package": "crayon", + "Version": "1.5.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "methods", + "utils" + ], + "Hash": "e8a1e41acf02548751f45c718d55aa6a" + }, + "curl": { + "Package": "curl", + "Version": "5.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "511bacbfa153a15251166b463b4da4f9" + }, + "desc": { + "Package": "desc", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "cli", + "rprojroot", + "utils" + ], + "Hash": "6b9602c7ebbe87101a9c8edb6e8b6d21" + }, + "filelock": { + "Package": "filelock", + "Version": "1.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "38ec653c2613bed60052ba3787bd8a2c" + }, + "glue": { + "Package": "glue", + "Version": "1.6.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "4f2596dfb05dac67b9dc558e5c6fba2e" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.8.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "methods" + ], + "Hash": "266a20443ca13c65688b2116d5220f76" + }, + "lpSolve": { + "Package": "lpSolve", + "Version": "5.6.18", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "12c7a918599d5700e4265dd8a21f684f" + }, + "pkgbuild": { + "Package": "pkgbuild", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "callr", + "cli", + "crayon", + "desc", + "prettyunits", + "processx", + "rprojroot" + ], + "Hash": "beb25b32a957a22a5c301a9e441190b3" + }, + "pkgcache": { + "Package": "pkgcache", + "Version": "2.2.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "callr", + "cli", + "curl", + "filelock", + "jsonlite", + "prettyunits", + "processx", + "rappdirs", + "tools", + "utils" + ], + "Hash": "2622106d5651a653c55430ee5f583978" + }, + "pkgdepends": { + "Package": "pkgdepends", + "Version": "0.6.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "callr", + "cli", + "curl", + "desc", + "filelock", + "glue", + "jsonlite", + "lpSolve", + "pkgbuild", + "pkgcache", + "prettyunits", + "processx", + "ps", + "rprojroot", + "stats", + "utils", + "zip" + ], + "Hash": "d0a9c1ca3fbc82d3db84e65f09b42720" + }, + "prettyunits": { + "Package": "prettyunits", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" + }, + "processx": { + "Package": "processx", + "Version": "3.8.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "ps", + "utils" + ], + "Hash": "3efbd8ac1be0296a46c55387aeace0f3" + }, + "ps": { + "Package": "ps", + "Version": "1.7.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "709d852d33178db54b17c722e5b1e594" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "1de7ab598047a87bba48434ba35d497d" + }, + "zip": { + "Package": "zip", + "Version": "2.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d98c94dacb7e0efcf83b0a133a705504" + } + } +} diff --git a/Modules/setup_renv_rcpp_rinside.R.in b/Modules/setup_renv_rcpp_rinside.R.in new file mode 100644 index 00000000000..720b8a002a4 --- /dev/null +++ b/Modules/setup_renv_rcpp_rinside.R.in @@ -0,0 +1,65 @@ +# Generated from Tools/setup_renv_rcpp_rinside_jaspModuleInstaller.R.in +# +Sys.setenv(GITHUB_PAT = "@GITHUB_PAT@") +Sys.setenv(RENV_PATHS_ROOT = "@MODULES_RENV_ROOT_PATH@") +Sys.setenv(RENV_PATHS_CACHE = "@MODULES_RENV_CACHE_PATH@") +Sys.setenv(RENV_PATHS_SANDBOX = "@RENV_SANDBOX@") +Sys.setenv(JASPENGINE_LOCATION = "@JASP_ENGINE_PATH@/JASPEngine") + + +RENV_LIBRARY <- "@RENV_LIBRARY@" +R_CPP_INCLUDES_LIBRARY <- "@R_CPP_INCLUDES_LIBRARY@" +JASPMODULEINSTALLER_LIBRARY <- "@JASPMODULEINSTALLER_LIBRARY@" +PKGDEPENDS_LIBRARY <- "@PKGDEPENDS_LIBRARY@" + +ENGINE <- file.path("@PROJECT_SOURCE_DIR@", "Engine") +MODULES <- file.path("@PROJECT_SOURCE_DIR@", "Modules") +TOOLS <- file.path("@PROJECT_SOURCE_DIR@", "Tools") + +# defines assignFunctionInRenv, getOS, and setupRenv +source(file.path(ENGINE, "jaspModuleInstaller", "R", "renvOverrides.R")) + +mkdir <- function(paths) { + for (path in paths) + if (!dir.exists(path)) + dir.create(path, recursive = TRUE) +} + +mkdir(c(RENV_LIBRARY, R_CPP_INCLUDES_LIBRARY, JASPMODULEINSTALLER_LIBRARY)) + +repos <- "https://packagemanager.posit.co/cran/latest" +# alternative to 'http://cloud.r-project.org' + +if (!dir.exists(file.path(RENV_LIBRARY, "renv"))) { + cat("Installing renv from CRAN\n") + install.packages( + pkgs = "renv", + lib = RENV_LIBRARY, + repos ='http://cloud.r-project.org', + INSTALL_opts ='--no-multiarch --no-docs --no-test-load') # --no-test-load is dubious here +} else { + cat("renv already installed, not reinstalling\n") +} + +# used by renv +options( + install.opts = "--no-multiarch --no-docs --no-test-load", + # these two could be added to setupRenv + renv.config.install.verbose = TRUE, + renv.config.ppm.default = TRUE +) + +.libPaths(RENV_LIBRARY) +sandboxPaths <- renv:::renv_sandbox_activate() + +cat("Using sandbox paths:\n") +for (path in sandboxPaths) + cat(" ", path, "\n", sep = "") + +cat("Restoring Rcpp & RInside\n") +setupRenv(R_CPP_INCLUDES_LIBRARY) +renv::restore( + library = R_CPP_INCLUDES_LIBRARY, + lockfile = file.path(MODULES, "Rcpp_RInside.lock"), + clean = TRUE +) \ No newline at end of file diff --git a/R-Interface/CMakeLists.txt b/R-Interface/CMakeLists.txt index 1f48a60fe0a..e5c1196f8ff 100644 --- a/R-Interface/CMakeLists.txt +++ b/R-Interface/CMakeLists.txt @@ -85,11 +85,22 @@ if(WIN32) set(R_LIBRARY_PATH "${R_HOME_PATH}/library") set(R_OPT_PATH "${R_HOME_PATH}/opt") set(R_EXECUTABLE "${R_HOME_PATH}/bin/R") + set(RSCRIPT_EXECUTABLE "${R_HOME_PATH}/bin/Rscript") set(R_INCLUDE_PATH "${R_HOME_PATH}/include") - set(RCPP_PATH "${R_LIBRARY_PATH}/Rcpp") - set(RINSIDE_PATH "${R_LIBRARY_PATH}/RInside") - set(RENV_PATH "${R_LIBRARY_PATH}/renv") + set(RENV_PATH "${JASP_BINARY_DIR}/_cache/R/renv_library/renv") + + set(R_CPP_INCLUDES_LIBRARY "${JASP_BINARY_DIR}/R/R_cpp_includes_library") + set(FIND_PACKAGE_PATH_SCRIPT "${CMAKE_SOURCE_DIR}/../Tools/find_package_path.R") + macro(find_package_path out libPath packageName) + execute_process(COMMAND ${RSCRIPT_EXECUTABLE} ${FIND_PACKAGE_PATH_SCRIPT} ${libPath} ${packageName} OUTPUT_VARIABLE ${out}) + endmacro() + find_package_path(RCPP_PATH ${R_CPP_INCLUDES_LIBRARY} "Rcpp") + find_package_path(RINSIDE_PATH ${R_CPP_INCLUDES_LIBRARY} "RInside") + + message(STATUS "RCPP_PATH = ${RCPP_PATH}") + message(STATUS "RINSIDE_PATH = ${RINSIDE_PATH}") + message(STATUS "RENV_PATH = ${RENV_PATH}") include(FetchContent) include(ExternalProject) diff --git a/R-Interface/jasprcpp.cpp b/R-Interface/jasprcpp.cpp index 8e3c4f7fe98..f3ade2ad93e 100644 --- a/R-Interface/jasprcpp.cpp +++ b/R-Interface/jasprcpp.cpp @@ -55,6 +55,7 @@ getColNames getAllColumnNames; static logFlushDef _logFlushFunction = nullptr; static logWriteDef _logWriteFunction = nullptr; static sendFuncDef _sendToDesktop = nullptr; +static pollMessagesFuncDef _pollMessagesFunction = nullptr; static systemDef _systemFunc = nullptr; static libraryFixerDef _libraryFixerFunc = nullptr; static std::string _R_HOME = ""; @@ -74,13 +75,13 @@ void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCa _logFlushFunction = logFlushFunction; _logWriteFunction = logWriteFunction; _sendToDesktop = sendToDesktopFunction; + _pollMessagesFunction = pollMessagesFunction; _systemFunc = systemFunc; _libraryFixerFunc = libraryFixerFunc; jaspRCPP_logString("Creating RInside.\n"); rinside = new RInside(); - R_TempDir = (char*)tempDir; RInside &rInside = rinside->instance(); @@ -153,12 +154,36 @@ void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCa Rcpp::RObject sinkObj = rInside[".outputSink"]; //jaspRCPP_logString(sinkObj.isNULL() ? "sink is null\n" : !sinkObj.isObject() ? " sink is not object\n" : sinkObj.isS4() ? "sink is s4\n" : "sink is obj but not s4\n"); + rInside.parseEvalQNT("sink(.outputSink); print(.libPaths()); sink();"); + + // initialize everything unrelated to jaspBase static const char *baseCitationFormat = "JASP Team (%s). JASP (Version %s) [Computer software]."; char baseCitation[200]; snprintf(baseCitation, 200, baseCitationFormat, buildYear, version); rInside[".baseCitation"] = baseCitation; rInside[".jaspVersion"] = version; + rInside[".baseCitation"] = baseCitation; + rInside[".numDecimals"] = 3; + rInside[".fixedDecimals"] = false; + rInside[".normalizedNotation"] = true; + rInside[".exactPValues"] = false; + rInside[".resultFont"] = "Arial"; + rInside[".imageBackground"] = "transparent"; + rInside[".ppi"] = 300; + + jaspRCPP_parseEvalQNT("library(methods)"); + + _R_HOME = jaspRCPP_parseEvalStringReturn("R.home('')"); + jaspRCPP_logString("R_HOME is: " + _R_HOME + "\n"); + +} + +void STDCALL jaspRCPP_init_jaspBase() +{ + + jaspRCPP_logString("Start initializing jaspBase\n"); + //XPtr doesnt like it if it can't run a finalizer so here are some dummy variables: static logFuncDef _logFuncDef = jaspRCPP_logString; static getColumnTypeFuncDef _getColumnTypeFuncDef = jaspRCPP_getColumnType; @@ -170,28 +195,20 @@ void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCa static setColumnDataFuncDef _setColumnDataAsNominal = jaspRCPP_setColumnDataAsNominal; static setColumnDataFuncDef _setColumnDataAsNominalText = jaspRCPP_setColumnDataAsNominalText; + RInside &rInside = rinside->instance(); + rInside[".logString"] = Rcpp::XPtr( & _logFuncDef); rInside[".createColumn"] = Rcpp::XPtr( & _createColumnFuncDef); rInside[".getColumnType"] = Rcpp::XPtr( & _getColumnTypeFuncDef); rInside[".getColumnExists"] = Rcpp::XPtr( & _getColumnExistsFuncDef); rInside[".getColumnAnalysisId"] = Rcpp::XPtr( & _getColumnAnIdFuncDef); - rInside[".sendToDesktopFunction"] = Rcpp::XPtr( & sendToDesktopFunction); - rInside[".pollMessagesFunction"] = Rcpp::XPtr( & pollMessagesFunction); + rInside[".sendToDesktopFunction"] = Rcpp::XPtr( & _sendToDesktop); + rInside[".pollMessagesFunction"] = Rcpp::XPtr( & _pollMessagesFunction); + rInside[".setColumnDataAsScalePtr"] = Rcpp::XPtr( & _setColumnDataAsScale); rInside[".setColumnDataAsOrdinalPtr"] = Rcpp::XPtr( & _setColumnDataAsOrdinal); rInside[".setColumnDataAsNominalPtr"] = Rcpp::XPtr( & _setColumnDataAsOrdinal); rInside[".setColumnDataAsNominalTextPtr"] = Rcpp::XPtr( & _setColumnDataAsNominalText); - rInside[".baseCitation"] = baseCitation; - rInside[".numDecimals"] = 3; - rInside[".fixedDecimals"] = false; - rInside[".normalizedNotation"] = true; - rInside[".exactPValues"] = false; - rInside[".resultFont"] = "Arial"; - rInside[".imageBackground"] = "transparent"; - rInside[".ppi"] = 300; - - - //jaspRCPP_parseEvalQNT("options(encoding = 'UTF-8')"); //Pass a whole bunch of pointers to jaspBase jaspRCPP_parseEvalQNT("jaspBase:::setColumnFuncs( .setColumnDataAsScalePtr, .setColumnDataAsOrdinalPtr, .setColumnDataAsNominalPtr, .setColumnDataAsNominalTextPtr, .getColumnType, .getColumnAnalysisId, .createColumn, .getColumnExists)"); @@ -200,21 +217,21 @@ void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCa jaspRCPP_parseEvalQNT("jaspBase:::setPollMessagesFunc( .pollMessagesFunction)"); jaspRCPP_parseEvalQNT("jaspBase:::setBaseCitation( .baseCitation)"); jaspRCPP_parseEvalQNT("jaspBase:::setInsideJasp()"); + jaspRCPP_parseEvalQNT("jaspBase:::registerFonts()"); //Load it jaspRCPP_logString("Initializing jaspBase.\n"); - jaspRCPP_parseEvalQNT("library(methods)"); jaspRCPP_parseEvalQNT("library(jaspBase)"); // if we have a separate engine for each module then we should move these kind of hacks to the .onAttach() of each module (instead of loading BayesFactor when Descriptives is requested). // jaspRCPP_logString("initEnvironment().\n"); // jaspRCPP_parseEvalQNT("initEnvironment()"); - _R_HOME = jaspRCPP_parseEvalStringReturn("R.home('')"); - jaspRCPP_logString("R_HOME is: " + _R_HOME + "\n"); - jaspRCPP_logString("initializeDoNotRemoveList().\n"); jaspRCPP_parseEvalQNT("jaspBase:::.initializeDoNotRemoveList()"); + + jaspRCPP_logString("Finished initializing jaspBase.\n"); + } void STDCALL jaspRCPP_junctionHelper(bool collectNotRestore, const char * folder) @@ -276,7 +293,8 @@ void STDCALL jaspRCPP_setFontAndPlotSettings(const char * resultFont, const int rInside[".imageBackground"] = imageBackground; rInside[".ppi"] = ppi; - jaspRCPP_parseEvalQNT("jaspBase:::registerFonts()"); + // sometimes jaspBase is not available + jaspRCPP_parseEvalQNT("try(jaspBase:::registerFonts())"); } const char* STDCALL jaspRCPP_runModuleCall(const char* name, const char* title, const char* moduleCall, const char* dataKey, const char* options, diff --git a/R-Interface/jasprcpp_interface.h b/R-Interface/jasprcpp_interface.h index dafd2192d3e..f38668e00fa 100644 --- a/R-Interface/jasprcpp_interface.h +++ b/R-Interface/jasprcpp_interface.h @@ -127,6 +127,7 @@ typedef size_t (*logWriteDef) (const void * buf, size_t len); // Calls from rbridge to jaspRCPP RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_init(const char* buildYear, const char* version, RBridgeCallBacks *calbacks, sendFuncDef sendToDesktopFunction, pollMessagesFuncDef pollMessagesFunction, logFlushDef logFlushFunction, logWriteDef logWriteFunction, systemDef systemFunc, libraryFixerDef libraryFixerFunc, const char* resultFont, const char * tempDir); +RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_init_jaspBase(); RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_setDecimalSettings(int numDecimals, bool fixedDecimals, bool normalizedNotation, bool exactPValues); RBRIDGE_TO_JASP_INTERFACE void STDCALL jaspRCPP_setFontAndPlotSettings(const char * resultFont, const int ppi, const char* imageBackground); RBRIDGE_TO_JASP_INTERFACE const char* STDCALL jaspRCPP_runModuleCall(const char* name, const char* title, const char* moduleCall, const char* dataKey, const char* options, const char* stateKey, int analysisID, int analysisRevision, bool developerMode); diff --git a/Tools/CMake/Modules.cmake b/Tools/CMake/Modules.cmake index c11b04dd0bf..607a52babb2 100644 --- a/Tools/CMake/Modules.cmake +++ b/Tools/CMake/Modules.cmake @@ -155,37 +155,31 @@ execute_process( ${MODULES_BINARY_PATH}/) add_custom_target( - jaspBase + jaspModuleInstaller WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/R-Interface - DEPENDS ${MODULES_BINARY_PATH}/jaspBase/jaspBaseHash.rds) - -configure_file("${PROJECT_SOURCE_DIR}/Modules/install-jaspBase.R.in" - ${SCRIPT_DIRECTORY}/install-jaspBase.R @ONLY) - -# I'm using a custom_command here to make sure that jaspBase is installed once -# and only once before everything else. So, `install-jaspBase.R` creates an empty -# file, i.e., `jaspBase-installed-successfully.log` and all other Modules look for -# it. If they find it, they proceed, if not, they trigger this custom command. -# TODO: -# - [ ] The following commands can be turned into a function or a macro, but -# for now, I would like to keep a granular control over differnt steps + DEPENDS ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller) + +configure_file("${PROJECT_SOURCE_DIR}/Modules/install-jaspModuleInstaller.R.in" + ${SCRIPT_DIRECTORY}/install-jaspModuleInstaller.R @ONLY) + +# I'm using a custom_command here to make sure that jaspModuleInstaller is installed once if(APPLE) - add_dependencies(jaspBase JASPEngine) + add_dependencies(jaspModuleInstaller JASPEngine) add_custom_command( WORKING_DIRECTORY ${R_HOME_PATH} - OUTPUT ${MODULES_BINARY_PATH}/jaspBase/jaspBaseHash.rds - USES_TERMINAL - COMMAND ${CMAKE_COMMAND} -E env "JASP_R_HOME=${R_HOME_PATH}" ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-jaspBase.R - COMMENT "------ Installing 'jaspBase'") + OUTPUT ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller + USES_TERMINAL + COMMAND ${CMAKE_COMMAND} -E env "JASP_R_HOME=${R_HOME_PATH}" ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-jaspModuleInstaller.R + COMMENT "------ Installing 'jaspModuleInstaller'") else() add_custom_command( WORKING_DIRECTORY ${R_HOME_PATH} - OUTPUT ${R_HOME_PATH}/jaspBase_md5sums.rds + OUTPUT ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller USES_TERMINAL COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-jaspBase.R - COMMENT "------ Installing 'jaspBase'") + --file=${SCRIPT_DIRECTORY}/install-jaspModuleInstaller.R + COMMENT "------ Installing 'jaspModuleInstaller'") endif() @@ -219,7 +213,7 @@ if(APPLE) ${MODULE} USES_TERMINAL WORKING_DIRECTORY ${R_HOME_PATH} - DEPENDS ${MODULES_BINARY_PATH}/jaspBase/jaspBaseHash.rds + DEPENDS ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller COMMAND ${CMAKE_COMMAND} -E env "JASP_R_HOME=${R_HOME_PATH}" ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-${MODULE}.R # COMMAND # ${CMAKE_COMMAND} -D PATH=${MODULES_BINARY_PATH}/${MODULE} -D @@ -237,7 +231,7 @@ else() ${MODULE} USES_TERMINAL WORKING_DIRECTORY ${R_HOME_PATH} - DEPENDS ${R_HOME_PATH}/jaspBase_md5sums.rds + DEPENDS ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-${MODULE}.R BYPRODUCTS ${MODULES_BINARY_PATH}/${MODULE} @@ -271,9 +265,7 @@ if(APPLE) ${MODULE} USES_TERMINAL WORKING_DIRECTORY ${R_HOME_PATH} - DEPENDS - JASPEngine - ${MODULES_BINARY_PATH}/jaspBase/jaspBaseHash.rds + DEPENDS JASPEngine ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller $<$:${jags_VERSION_H_PATH}> $<$:${jags_VERSION_H_PATH}> COMMAND ${CMAKE_COMMAND} -E env "JASP_R_HOME=${R_HOME_PATH}" ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-${MODULE}.R @@ -291,10 +283,7 @@ else() ${MODULE} USES_TERMINAL WORKING_DIRECTORY ${R_HOME_PATH} - DEPENDS - ${R_HOME_PATH}/jaspBase_md5sums.rds - $<$:${jags_VERSION_H_PATH}> - $<$:${jags_VERSION_H_PATH}> + DEPENDS ${JASPMODULEINSTALLER_LIBRARY}/jaspModuleInstaller $<$:${jags_VERSION_H_PATH}> $<$:${jags_VERSION_H_PATH}> COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-${MODULE}.R diff --git a/Tools/CMake/Patch.cmake b/Tools/CMake/Patch.cmake index ecfc3c6470c..9cb3c67240c 100644 --- a/Tools/CMake/Patch.cmake +++ b/Tools/CMake/Patch.cmake @@ -42,7 +42,7 @@ else() file( GLOB_RECURSE LIBRARIES - #FOLLOW_SYMLINKS #Turned this off because it got infinitely regressed + FOLLOW_SYMLINKS #Don turned this off because it got infinitely regressed, but Joris turned it back on because we use symlinks to go to packages nowadays... "${PATH}/*.so" "${PATH}/*.dylib") list( @@ -69,6 +69,9 @@ else() ${LIBRARIES} ${BINARIES}) + + message(STATUS "* Patching got files: ${Files}") + set(NEW_ID "") set(FRAMEWORK_RESOURCES "@executable_path/../Frameworks/R.framework/Versions/${R_DIR_NAME}/Resources") @@ -77,6 +80,9 @@ else() get_filename_component(FILE_NAME ${FILE} NAME) get_filename_component(DIRECTORY_NAME ${FILE} DIRECTORY) + message(STATUS "** Patching in Dir '$DIRECTORY' the file '${FILE}'") + + string(LENGTH "${PATH}/" PATH_LENGTH) string( SUBSTRING "${FILE}" diff --git a/Tools/CMake/R.cmake b/Tools/CMake/R.cmake index 645143c9808..4e2ac42f35f 100644 --- a/Tools/CMake/R.cmake +++ b/Tools/CMake/R.cmake @@ -16,15 +16,15 @@ # on x86_64, it is using the Fortran 8. # # Notes: -# - Be aware that at some point, R will move to use a different Fortran, and +# - Be aware that at some point, R will move to use a different Fortran, and # when that happens, someone needs to make sure that the right Fortran is being -# download, unpacked, and placed in the right location. You can find the +# download, unpacked, and placed in the right location. You can find the # appropriate version in `etc/Makeconf` and the binary here, # https://github.com/fxcoudert/gfortran-for-macOS/releases # - On GitHub Action, # - You probably want to unpack the `https://static.jasp-stats.org/development/gfortran-8.2-Mojave.dmg` # into a `.tar.gz`. I think this might elimite some possible issues with the unpacking on -# their environment. If you have decided to do this, make sure that the structure of the +# their environment. If you have decided to do this, make sure that the structure of the # archive is similiar and things land where they are expected. # # Todos: @@ -147,18 +147,20 @@ if(APPLE) set(R_LIBRARY_PATH "${R_HOME_PATH}/library") set(R_OPT_PATH "${R_HOME_PATH}/opt") set(R_EXECUTABLE "${R_HOME_PATH}/bin/R") + set(RSCRIPT_EXECUTABLE "${R_HOME_PATH}/bin/Rscript") set(R_INCLUDE_PATH "${R_HOME_PATH}/include") set(RCPP_PATH "${R_LIBRARY_PATH}/Rcpp") set(RINSIDE_PATH "${R_LIBRARY_PATH}/RInside") set(RENV_PATH "${R_LIBRARY_PATH}/renv") set(ENV{JASP_R_HOME} ${R_HOME_PATH}) - set(ENV{R_HOME} ${R_HOME_PATH}) + #set(ENV{R_HOME} ${R_HOME_PATH}) #enabling this breaks the output from R because it will add a warning about: `WARNING: ignoring environment value of R_HOME` cmake_print_variables(R_FRAMEWORK_PATH) cmake_print_variables(R_HOME_PATH) cmake_print_variables(R_LIBRARY_PATH) cmake_print_variables(R_OPT_PATH) cmake_print_variables(R_EXECUTABLE) + cmake_print_variables(RSCRIPT_EXECUTABLE) cmake_print_variables(RCPP_PATH) cmake_print_variables(RINSIDE_PATH) cmake_print_variables(RENV_PATH) @@ -345,23 +347,6 @@ if(APPLE) message(CHECK_FAIL "failed.") endif() - message(CHECK_START "Locating the 'gfortran'") - - find_program( - FORTRAN_EXECUTABLE - NAMES gfortran - PATHS ${GFORTRAN_PATH} - NO_DEFAULT_PATH - DOC "'gfortran' is needed for building some of the R packages") - - if(NOT FORTRAN_EXECUTABLE) - message(CHECK_FAIL "not found") - message(FATAL_ERROR "Please install 'gfortran' before continuing.") - else() - message(CHECK_PASS "found") - message(STATUS " ${FORTRAN_EXECUTABLE}") - endif() - # -------------------------------------------------------- # Patching R.framework and everything related to it ------ # @@ -400,7 +385,7 @@ if(APPLE) message(CHECK_START "Patching /bin/exec/R") execute_process( #COMMAND_ECHO STDOUT - #ERROR_QUIET + #ERROR_QUIET OUTPUT_QUIET WORKING_DIRECTORY ${R_HOME_PATH} COMMAND @@ -417,9 +402,9 @@ if(APPLE) while((${SIGNING_RESULT} MATCHES "timeout") OR (${SIGNING_RESULT} STREQUAL "1")) if(RUNTIMEHARDENING) execute_process( - COMMAND_ECHO STDOUT + #COMMAND_ECHO STDOUT #ERROR_QUIET - #OUTPUT_QUIET + OUTPUT_QUIET TIMEOUT 30 WORKING_DIRECTORY ${R_HOME_PATH} COMMAND @@ -431,9 +416,9 @@ if(APPLE) ERROR_VARIABLE SIGNING_ERROR) else() execute_process( - COMMAND_ECHO STDOUT + #COMMAND_ECHO STDOUT #ERROR_QUIET - #OUTPUT_QUIET + OUTPUT_QUIET TIMEOUT 30 WORKING_DIRECTORY ${R_HOME_PATH} COMMAND @@ -467,6 +452,23 @@ if(APPLE) endif() + message(CHECK_START "Locating the 'gfortran'") + + find_program( + FORTRAN_EXECUTABLE + NAMES gfortran + PATHS ${GFORTRAN_PATH} + NO_DEFAULT_PATH + DOC "'gfortran' is needed for building some of the R packages") + + if(NOT FORTRAN_EXECUTABLE) + message(CHECK_FAIL "not found") + message(FATAL_ERROR "Please install 'gfortran' before continuing.") + else() + message(CHECK_PASS "found") + message(STATUS "FORTRAN_EXECUTABLE=${FORTRAN_EXECUTABLE}") + endif() + endif() # @@ -522,96 +524,6 @@ if(APPLE) message(CHECK_FAIL "not found in ${R_HOME_PATH}/lib") endif() - if(NOT EXISTS ${RINSIDE_PATH}) - message(STATUS "RInside is not installed!") - - message(CHECK_START "Installing the 'RInside' and 'Rcpp'") - - configure_file(${MODULES_SOURCE_PATH}/install-RInside.R.in - ${SCRIPT_DIRECTORY}/install-RInside.R @ONLY) - - execute_process( - COMMAND_ECHO STDOUT - #ERROR_QUIET OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-RInside.R) - - if(NOT EXISTS ${R_LIBRARY_PATH}/RInside) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'RInside' installation has failed!") - endif() - - message(CHECK_PASS "successful.") - - # Patching RInside and RCpp - message(CHECK_START "Patching Frameworks/.../library") - execute_process( - #COMMAND_ECHO STDOUT - #ERROR_QUIET - OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND - ${CMAKE_COMMAND} -D - NAME_TOOL_PREFIX_PATCHER=${PROJECT_SOURCE_DIR}/Tools/macOS/install_name_prefix_tool.sh - -D PATH=${R_HOME_PATH}/library -D R_HOME_PATH=${R_HOME_PATH} - -D R_DIR_NAME=${R_DIR_NAME} -D SIGNING_IDENTITY=${APPLE_CODESIGN_IDENTITY} - -D SIGNING=1 -D CODESIGN_TIMESTAMP_FLAG=${CODESIGN_TIMESTAMP_FLAG} -P - ${PROJECT_SOURCE_DIR}/Tools/CMake/Patch.cmake) - - endif() - - if(NOT EXISTS ${RENV_PATH}) - message(STATUS "renv is not installed!") - message(CHECK_START "Installing 'renv'") - - configure_file(${MODULES_SOURCE_PATH}/install-renv.R.in - ${SCRIPT_DIRECTORY}/install-renv.R @ONLY) - - set(ENV{JASP_R_HOME} ${R_HOME_PATH}) - - execute_process( - COMMAND_ECHO STDERR - #ERROR_QUIET OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/install-renv.R) - - if(NOT EXISTS ${R_LIBRARY_PATH}/renv) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'renv' installation has failed!") - endif() - - message(CHECK_PASS "successful.") - - message(CHECK_START "Patching Frameworks/.../library") - execute_process( - #COMMAND_ECHO STDOUT - #ERROR_QUIET - OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND - ${CMAKE_COMMAND} -D - NAME_TOOL_PREFIX_PATCHER=${PROJECT_SOURCE_DIR}/Tools/macOS/install_name_prefix_tool.sh - -D PATH=${R_HOME_PATH}/library -D R_HOME_PATH=${R_HOME_PATH} - -D R_DIR_NAME=${R_DIR_NAME} -D SIGNING_IDENTITY=${APPLE_CODESIGN_IDENTITY} - -D SIGNING=1 -D CODESIGN_TIMESTAMP_FLAG=${CODESIGN_TIMESTAMP_FLAG} -P - ${PROJECT_SOURCE_DIR}/Tools/CMake/Patch.cmake) - endif() - - message(CHECK_START "Checking for 'libRInside'") - find_library( - _LIB_RINSIDE - NAMES RInside - PATHS ${RINSIDE_PATH}/lib - NO_DEFAULT_PATH NO_CACHE REQUIRED) - - if(_LIB_RINSIDE) - message(CHECK_PASS "found.") - message(STATUS " ${_LIB_RINSIDE}") - else() - message(CHECK_FAIL "not found in ${RINSIDE_PATH}/lib") - endif() - elseif(WIN32) set(R_HOME_PATH "${CMAKE_BINARY_DIR}/R") @@ -620,11 +532,8 @@ elseif(WIN32) set(R_LIBRARY_PATH "${R_HOME_PATH}/library") set(R_OPT_PATH "${R_HOME_PATH}/opt") set(R_EXECUTABLE "${R_HOME_PATH}/bin/R") + set(RSCRIPT_EXECUTABLE "${R_HOME_PATH}/bin/Rscript") set(R_INCLUDE_PATH "${R_HOME_PATH}/include") - set(RCPP_PATH "${R_LIBRARY_PATH}/Rcpp") - set(RINSIDE_PATH "${R_LIBRARY_PATH}/RInside") - set(RENV_PATH "${R_LIBRARY_PATH}/renv") - # This will be added to the install.packages calls set(USE_LOCAL_R_LIBS_PATH ", lib='${R_LIBRARY_PATH}'") @@ -634,10 +543,7 @@ elseif(WIN32) cmake_print_variables(R_LIBRARY_PATH) cmake_print_variables(R_OPT_PATH) cmake_print_variables(R_EXECUTABLE) - - cmake_print_variables(RCPP_PATH) - cmake_print_variables(RINSIDE_PATH) - cmake_print_variables(RENV_PATH) + cmake_print_variables(RSCRIPT_EXECUTABLE) message(CHECK_START "Checking for R/") @@ -709,52 +615,6 @@ elseif(WIN32) endif() - if(NOT EXISTS ${RENV_PATH}) - message(STATUS "renv is not installed!") - message(CHECK_START "Installing 'renv'") - - configure_file(${MODULES_SOURCE_PATH}/install-renv.R.in - ${SCRIPT_DIRECTORY}/install-renv.R @ONLY) - - execute_process( - COMMAND_ECHO STDOUT - #ERROR_QUIET OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-renv.R) - - if(NOT EXISTS ${R_LIBRARY_PATH}/renv) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'renv' installation has failed!") - endif() - - message(CHECK_PASS "successful.") - endif() - - if(NOT EXISTS ${RINSIDE_PATH}) - message(STATUS "RInside is not installed!") - - message(CHECK_START "Installing the 'RInside' and 'Rcpp'") - - configure_file(${MODULES_SOURCE_PATH}/install-RInside.R.in - ${SCRIPT_DIRECTORY}/install-RInside.R @ONLY) - - execute_process( - COMMAND_ECHO STDOUT - #ERROR_QUIET OUTPUT_QUIET - WORKING_DIRECTORY ${R_BIN_PATH} - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-RInside.R) - - if(NOT EXISTS ${R_LIBRARY_PATH}/RInside) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'RInside' installation has failed!") - endif() - - message(CHECK_PASS "successful.") - - endif() - elseif(LINUX) message(CHECK_START "Looking for R") @@ -823,9 +683,6 @@ elseif(LINUX) set(R_EXECUTABLE "${R_HOME_PATH}/bin/R") set(RSCRIPT_EXECUTABLE "${R_HOME_PATH}/bin/Rscript") - set(RCPP_PATH "${R_LIBRARY_PATH}/Rcpp") - set(RINSIDE_PATH "${R_LIBRARY_PATH}/RInside") - set(RENV_PATH "${R_LIBRARY_PATH}/renv") set(USE_LOCAL_R_LIBS_PATH ", lib='${R_LIBRARY_PATH}'") @@ -874,50 +731,73 @@ elseif(LINUX) message(CHECK_FAIL "not found in ${R_HOME_PATH}/lib") endif() - if(NOT EXISTS ${RENV_PATH}) - message(STATUS "renv is not installed!") - message(CHECK_START "Installing 'renv'") +endif() - configure_file(${MODULES_SOURCE_PATH}/install-renv.R.in - ${SCRIPT_DIRECTORY}/install-renv.R @ONLY) +set(RENV_LIBRARY "${CMAKE_BINARY_DIR}/_cache/R/renv_library") +set(R_CPP_INCLUDES_LIBRARY "${CMAKE_BINARY_DIR}/R/R_cpp_includes_library") +set(JASPMODULEINSTALLER_LIBRARY "${CMAKE_BINARY_DIR}/R/jaspModuleInstaller_library") +set(PKGDEPENDS_LIBRARY "${CMAKE_BINARY_DIR}/R/pkgdepends_library") - execute_process( - COMMAND_ECHO STDOUT - #ERROR_QUIET OUTPUT_QUIET - WORKING_DIRECTORY ${R_HOME_PATH} - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-renv.R) +SET(RENV_SANDBOX "${CMAKE_BINARY_DIR}/_cache/R/renv_sandbox") +file(MAKE_DIRECTORY ${RENV_SANDBOX}) +# TODO: it could be nice to ship the sandbox so it can be used to install dynamic modules +# also, the sandbox paths may need to be adjusted on windows (they are symlinks) - if(NOT EXISTS ${R_LIBRARY_PATH}/renv) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'renv' installation has failed!") - endif() +message(STATUS "Setting up renv, Rcpp, RInside, and jaspModuleInstaller") +message(STATUS "RENV_LIBRARY = ${RENV_LIBRARY}") +message(STATUS "R_CPP_INCLUDES_LIBRARY = ${R_CPP_INCLUDES_LIBRARY}") - message(CHECK_PASS "successful.") - endif() +configure_file(${PROJECT_SOURCE_DIR}/Modules/setup_renv_rcpp_rinside.R.in + ${SCRIPT_DIRECTORY}/setup_renv_rcpp_rinside.R @ONLY) - if(NOT EXISTS ${RINSIDE_PATH}) - message(STATUS "RInside is not installed!") +execute_process( + COMMAND_ECHO STDOUT + #ERROR_QUIET OUTPUT_QUIET + WORKING_DIRECTORY ${R_HOME_PATH} + COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save --file=${SCRIPT_DIRECTORY}/setup_renv_rcpp_rinside.R) - message(CHECK_START "Installing the 'RInside' and 'Rcpp'") +if(APPLE) + # Patch RInside and RCpp + message(CHECK_START "Patching ${R_CPP_INCLUDES_LIBRARY}") + execute_process( + COMMAND_ECHO STDOUT + #ERROR_QUIET OUTPUT_QUIET + WORKING_DIRECTORY ${R_HOME_PATH} + COMMAND + ${CMAKE_COMMAND} -D + NAME_TOOL_PREFIX_PATCHER=${PROJECT_SOURCE_DIR}/Tools/macOS/install_name_prefix_tool.sh + -D PATH=${R_CPP_INCLUDES_LIBRARY} -D R_HOME_PATH=${R_HOME_PATH} -D + R_DIR_NAME=${R_DIR_NAME} -D SIGNING_IDENTITY=${APPLE_CODESIGN_IDENTITY} + -D SIGNING=1 -D CODESIGN_TIMESTAMP_FLAG=${CODESIGN_TIMESTAMP_FLAG} -P + ${PROJECT_SOURCE_DIR}/Tools/CMake/Patch.cmake + ) +endif() - configure_file(${MODULES_SOURCE_PATH}/install-RInside.R.in - ${SCRIPT_DIRECTORY}/install-RInside.R @ONLY) +# Locate the full paths (so those in the cache, not the symlinks) +set(FIND_PACKAGE_PATH_SCRIPT ${PROJECT_SOURCE_DIR}/Tools/find_package_path.R) +macro(find_package_path out libPath packageName) + execute_process(COMMAND ${RSCRIPT_EXECUTABLE} ${FIND_PACKAGE_PATH_SCRIPT} ${libPath} ${packageName} OUTPUT_VARIABLE ${out}) +endmacro() +find_package_path(RCPP_PATH ${R_CPP_INCLUDES_LIBRARY} "Rcpp") +find_package_path(RINSIDE_PATH ${R_CPP_INCLUDES_LIBRARY} "RInside") - execute_process( - COMMAND_ECHO STDOUT - COMMAND ${R_EXECUTABLE} --slave --no-restore --no-save - --file=${SCRIPT_DIRECTORY}/install-RInside.R) +set(RENV_PATH "${RENV_LIBRARY}/renv") - if(NOT EXISTS ${R_LIBRARY_PATH}/RInside) - message(CHECK_FAIL "unsuccessful.") - message(FATAL_ERROR "'RInside' installation has failed!") - endif() +message(STATUS "RENV_PATH = ${RENV_PATH}") +message(STATUS "RCPP_PATH = ${RCPP_PATH}") +message(STATUS "RINSIDE_PATH = ${RINSIDE_PATH}") - message(CHECK_PASS "successful.") - - endif() +if(NOT EXISTS ${RENV_PATH}) + message(FATAL_ERROR "'renv' installation has failed!") +endif() +if(NOT EXISTS ${RCPP_PATH}) + message(FATAL_ERROR "'Rcpp' installation has failed!") +endif() +if(NOT EXISTS ${RINSIDE_PATH}) + message(FATAL_ERROR "'RInside' installation has failed!") +endif() +if(APPLE OR LINUX) message(CHECK_START "Checking for 'libRInside'") find_library( _LIB_RINSIDE @@ -931,7 +811,6 @@ elseif(LINUX) else() message(CHECK_FAIL "not found in ${RINSIDE_PATH}/lib") endif() - endif() list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/Tools/find_package_path.R b/Tools/find_package_path.R new file mode 100755 index 00000000000..d579bb5c294 --- /dev/null +++ b/Tools/find_package_path.R @@ -0,0 +1,25 @@ +args <- commandArgs(trailingOnly = TRUE) +# print(args) + +# usage + +# R --file=renv_new_idea_find_package_path.R --args library packagename [subdir 1] [subdir 2] ... + +# throws if the package or directory does not exist. + + +# R-4.3.1 --file=renv_new_idea_find_package_path.R --args /home/don/R/x86_64-pc-linux-gnu-library/4.2 Rcpp +# R-4.3.1 --file=renv_new_idea_find_package_path.R --args /home/don/R/x86_64-pc-linux-gnu-library/4.2 Rcpp include +# args <- c( +# "/home/don/R/x86_64-pc-linux-gnu-library/4.2", +# "Rcpp" +# ) +result <- find.package(package = args[2L], lib.loc = args[1L]) + +if (length(args) > 2L) + result <- do.call(file.path, c(result, as.list(args[3:length(args)]))) + +if (!(dir.exists(result) || file.exists(result))) + stop("target file/ directory does not exist!") + +cat(normalizePath(result))