Skip to content

Commit

Permalink
Changes to install process for easier update management
Browse files Browse the repository at this point in the history
  • Loading branch information
sjmgarnier committed Dec 20, 2023
1 parent 85a94ef commit 8cbe7fd
Show file tree
Hide file tree
Showing 14 changed files with 515 additions and 481 deletions.
6 changes: 3 additions & 3 deletions CRAN-SUBMISSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Version: 4.80.0
Date: 2023-07-20 12:13:05 UTC
SHA: a5d4e9111377647a4ecd4acf0f4e6e4c1749851f
Version: 4.80.1
Date: 2023-10-31 20:16:13 UTC
SHA: a232d31f9896a90915891173e4d284ac9f8f7892
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: ROpenCVLite
Type: Package
Title: Helper Package for Installing OpenCV with R
Version: 4.80.1
Date: 2023-10-31
Version: 4.80.2
Date: 2023-12-31
Authors@R: c(
person("Simon", "Garnier", email = "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-3886-3974")),
Expand Down
14 changes: 13 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# ROpenCVLite 4.80.0
# ROpenCVLite 4.80.2

## New features

* Overhaul of the installation functions for easier update management.

## Minor improvements and fixes

* Add compilation flags required to avoid errors on Windows 11.

---

# ROpenCVLite 4.80.1

## New features

Expand Down
266 changes: 266 additions & 0 deletions R/install.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
#' @title Default Install Location of OpenCV
#'
#' @description This function returns the location at which OpenCV should be
#' installed by default.
#'
#' @return A character string.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @examples
#' \dontrun{
#' defaultOpenCVPath()
#' }
#'
#' @export
defaultOpenCVPath <- function() {
pkgPath <- find.package("ROpenCVLite")
paste0(gsub("ROpenCVLite", "", pkgPath), "ROpenCV")
}


.configure <- function(install_path = defaultOpenCVPath(), version) {
config <- list()

config$install_path <- normalizePath(install_path, mustWork = FALSE)
config$pkg_path <- find.package("ROpenCVLite")

config$arch <- unname(Sys.info()["machine"])
if (!grepl("64", config$arch))
stop("Unsupported CPU architecture.")

config$os_type <- .Platform$OS.type

if (config$os_type == "windows") {
config$os <- gsub("\r", "", gsub("Caption=", "", system('wmic os get Caption,CSDVersion /value', intern = TRUE)[3]))
config$core <- paste0("https://github.com/opencv/opencv/archive/", version, ".tar.gz")
config$contrib <- paste0("https://github.com/opencv/opencv_contrib/archive/", version, ".tar.gz")
config$rtools_path <- pkgbuild::rtools_path()

if (is.null(config$rtools_path))
stop("Rtools is not installed.")

config$rtools_version <- as.numeric(
regmatches(config$rtools_path,
regexec("rtools\\s*(.*?)\\s*/",
config$rtools_path,
ignore.case = TRUE))[[1]][2]
)

if (is.na(config$rtools_version)) {
config$rtools_path <- gsub("(Rtools/).*", "\\1", config$rtools_path)
config$cmake_path <- system("where cmake.exe", intern = TRUE)
config$gcc_path <- paste0(config$rtools_path, "/mingw_64/bin/gcc.exe")
config$gpp_path <- paste0(config$rtools_path, "/mingw_64/bin/g++.exe")
config$windres_path <- paste0(config$rtools_path, "/mingw_64/bin/windres.exe")
config$make_path <- paste0(config$rtools_path, "/mingw_64/bin/mingw32-make.exe")
} else {
config$rtools_path <- gsub(paste0("(rtools", config$rtools_version, "/).*"), "\\1", config$rtools_path)

if (config$rtools_version == 40) {
config$cmake_path <- system("where cmake.exe", intern = TRUE)
config$gcc_path <- paste0(config$rtools_path, "/mingw64/bin/gcc.exe")
config$gpp_path <- paste0(config$rtools_path, "/mingw64/bin/g++.exe")
config$windres_path <- paste0(config$rtools_path, "/mingw64/bin/windres.exe")
config$make_path <- paste0(config$rtools_path, "/usr/bin/make.exe")
} else {
config$cmake_path <- paste0(config$rtools_path, "/x86_64-w64-mingw32.static.posix", "/bin/cmake.exe")
config$gcc_path <- paste0(config$rtools_path, "/x86_64-w64-mingw32.static.posix", "/bin/gcc.exe")
config$gpp_path <- paste0(config$rtools_path, "/x86_64-w64-mingw32.static.posix", "/bin/g++.exe")
config$windres_path <- paste0(config$rtools_path, "/x86_64-w64-mingw32.static.posix", "/bin/windres.exe")
config$make_path <- paste0(config$rtools_path, "/usr/bin/make.exe")
}
}
} else if (config$os_type == "unix") {
config$os <- unname(Sys.info()["sysname"])
config$core <- paste0("https://github.com/opencv/opencv/archive/", version, ".zip")
config$contrib <- paste0("https://github.com/opencv/opencv_contrib/archive/", version, ".zip")
config$cmake_path <- system("which cmake", intern = TRUE)
config$gcc_path <- system("which gcc", intern = TRUE)
config$gpp_path <- system("which g++", intern = TRUE)
config$make_path <- system("which make", intern = TRUE)
} else {
stop("Unsupported OS type.")
}

config$tmp_dir <- gsub("\\\\", "/", base::tempdir())
config$source_dir <- paste0(config$tmp_dir, "/opencv-", version, "/")
config$contrib_dir <- paste0(config$tmp_dir, "/opencv_contrib-", version, "/modules")
config$build_dir <- paste0(config$source_dir, "build")

config
}


.cmake <- function(config) {
paste0(
config$cmake_path,
' -G "Unix Makefiles"',
' -DCMAKE_C_COMPILER=', config$gcc_path,
switch(config$os_type,
windows = paste0(' -DCMAKE_RC_COMPILER=', config$windres_path,
' -DOpenCV_ARCH=x64',
' -DOpenCV_RUNTIME=mingw',
' -DBUILD_SHARED_LIBS=ON',
if (grepl("11", config$os)) ' -DCPU_DISPATCH=SSE4_1,SSE4_2,FP16,AV')
),
' -DCMAKE_MAKE_PROGRAM=', config$make_path,
' -DENABLE_PRECOMPILED_HEADERS=OFF',
' -DOPENCV_EXTRA_MODULES_PATH=', config$contrib_dir,
' -DBUILD_LIST=calib3d,core,dnn,features2d,flann,gapi,highgui,imgcodecs,imgproc,ml,objdetect,photo,stitching,video,videoio,ximgproc',
' -DBUILD_opencv_world=OFF',
' -DBUILD_opencv_contrib_world=OFF',
' -DBUILD_PERF_TESTS=OFF',
' -DBUILD_TESTS=OFF',
' -DCMAKE_C_FLAGS_RELEASE="-fstack-protector-strong"',
' -DCMAKE_CXX_FLAGS_RELEASE="-fstack-protector-strong"',
' -DINSTALL_CREATE_DISTRIB=ON',
' -DCMAKE_BUILD_TYPE=RELEASE',
' -DCMAKE_INSTALL_PREFIX=', config$install_path,
' -B', config$build_dir,
' -H', config$source_dir
)
}


#' @title Install OpenCV
#'
#' @description This function attempts to download, compile and install OpenCV
#' on the system. This process will take several minutes.
#'
#' @param install_path A character string indicating the location at which
#' OpenCV should be installed. By default, it is the value returned by
#' \code{\link{defaultOpenCVPath}}.
#'
#' @param batch A boolean indicating whether to skip (\code{TRUE}) or not
#' (\code{FALSE}, the default) the interactive installation dialog. This is
#' useful when OpenCV needs to be installed in a non-interactive environment
#' (e.g., during a batch installation on a server).
#'
#' @return A boolean.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @examples
#' \dontrun{
#' installOpenCV()
#' }
#'
#' @export
installOpenCV <- function(install_path = defaultOpenCVPath(), batch = FALSE) {
install <- 0
pkg_version <- paste0(
strsplit(as.character(utils::packageVersion("ROpenCVLite")), "")[[1]][c(1, 3, 4)],
collapse = ".")

if (interactive()) {
if (isOpenCVInstalled()) {
cv_version <- gsub("Version ", "", opencvVersion())

if (pkg_version == cv_version) {
install <- utils::menu(c("yes", "no"), title = "OpenCV is already installed on this system. Would you like to reinstall it now? This will take several minutes.")
} else {
install <- utils::menu(c("yes", "no"), title = "A new version of OpenCV is available. Would you like to install it now? This will take several minutes.")
}
} else {
install <- utils::menu(c("yes", "no"), title = "OpenCV is not installed on this system. Would you like to install it now? This will take several minutes.")
}
} else {
if (batch) {
packageStartupMessage("OpenCV being installed in non-interactive mode!")
install <- 1
} else {
packageStartupMessage("OpenCV can only be installed in interactive mode. To override this in a non-interactive context, use installOpenCV(batch = TRUE).")
}
}

if (!isCmakeInstalled())
install <- 0

if (install == 1) {
config <- .configure(normalizePath(install_path, mustWork = FALSE), pkg_version)
message(paste0("OpenCV will be installed in ", config$install_path))
old <- try(OpenCVPath(), silent = TRUE)

if (dir.exists(config$install_path)) {
message("Clearing install path.")
unlink(config$install_path, recursive = TRUE)
}

if (inherits(config$install_path, "try-error")) {
if (dir.exists(old)) {
message("Removing old OpenCV installation.")
unlink(old, recursive = TRUE)
}
}

dir.create(config$install_path, showWarnings = FALSE)
dir.create(config$tmp_dir, showWarnings = FALSE)

if (config$os_type == "windows") {
utils::download.file(config$core, paste0(config$tmp_dir, "/opencv.tar.gz"))
utils::untar(paste0(config$tmp_dir, "/opencv.tar.gz"), exdir = config$tmp_dir)
utils::download.file(config$contrib, paste0(config$tmp_dir, "/opencv_contrib.tar.gz"))
utils::untar(paste0(config$tmp_dir, "/opencv_contrib.tar.gz"), exdir = config$tmp_dir)
} else {
utils::download.file(config$core, paste0(config$tmp_dir, "/opencv.zip"))
utils::unzip(paste0(config$tmp_dir, "/opencv.zip"), exdir = config$tmp_dir)
utils::download.file(config$contrib, paste0(config$tmp_dir, "/opencv_contrib.zip"))
utils::unzip(paste0(config$tmp_dir, "/opencv_contrib.zip"), exdir = config$tmp_dir)

tmp <- readLines(paste0(config$source_dir, "cmake/OpenCVModule.cmake"))
ix <- which(grepl("# adds dependencies to OpenCV module", tmp)) - 1
insert <- c(
'# set CMAKE_INSTALL_NAME_DIR if CMAKE_INSTALL_PREFIX isn\'t default value of "/usr/local"',
'if(UNIX AND NOT ${CMAKE_INSTALL_PREFIX} STREQUAL "/usr/local")',
' set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib)',
'# message ("setting CMAKE_INSTALL_NAME_DIR: ${CMAKE_INSTALL_NAME_DIR}")',
'endif()',
''
)
writeLines(c(tmp[1:ix], insert, tmp[(ix + 1):length(tmp)]),
paste0(config$source_dir, "cmake/OpenCVModule.cmake"))
}

system(.cmake(config))
system(paste0(config$make_path, " -j", parallel::detectCores(), " -C ", config$build_dir))
system(paste0(config$make_path, " -C", config$build_dir, " install"))
writeLines(config$install_path, con = paste0(config$pkg_path, "/path"))
} else {
packageStartupMessage("OpenCV was not installed at this time. You can install it at any time by using the installOpenCV() function.")
}

isOpenCVInstalled()
}


#' @title Remove OpenCV
#'
#' @description This function removes OpenCV from the system.
#'
#' @return A boolean.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @examples
#' \dontrun{
#' installOpenCV()
#' }
#'
#' @export
removeOpenCV <- function() {
if (isOpenCVInstalled()) {
uninstall <- utils::menu(c("yes", "no"), title = "Would you like to completely remove OpenCV from your R installation? You can reinstall it at any time by using the installOpenCV() function.")
print(uninstall)

if (uninstall == 1) {
unlink(OpenCVPath(), recursive = TRUE)
!isOpenCVInstalled()
} else {
!isOpenCVInstalled()
}
} else {
message("OpenCV is not installed on this system. Nothing to be done.")
!isOpenCVInstalled()
}
}
Loading

0 comments on commit 8cbe7fd

Please sign in to comment.