From 9e85139f02efacbac9b867568b8ca1f7d3195a43 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Tue, 28 Nov 2023 13:52:17 -0500 Subject: [PATCH 1/7] Remove `install-kernel.ts` exit --- extensions/positron-r/scripts/install-kernel.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extensions/positron-r/scripts/install-kernel.ts b/extensions/positron-r/scripts/install-kernel.ts index ccd21e0cdf1..53a5b71ea82 100644 --- a/extensions/positron-r/scripts/install-kernel.ts +++ b/extensions/positron-r/scripts/install-kernel.ts @@ -228,12 +228,7 @@ async function downloadAndReplaceArk(version: string, } async function main() { - - // Temporarily skip downloading ARK on Windows until we have a Windows build. - if (platform() === 'win32') { - console.warn('ARK is not yet supported on Windows. Skipping download.'); - return; - } + // TODO: Relying on locally build ark to exist for Windows // Before we do any work, check to see if there is a locally built copy of Amalthea in the // `amalthea / target` directory. If so, we'll assume that the user is a kernel developer From c353ed769beb3fe3915242e5313f63ddd079d994 Mon Sep 17 00:00:00 2001 From: DavisVaughan Date: Tue, 28 Nov 2023 15:53:24 -0500 Subject: [PATCH 2/7] Patch in minimal Windows R detection --- extensions/positron-r/src/kernel.ts | 11 +++-- extensions/positron-r/src/provider.ts | 38 ++++++++++------- extensions/positron-r/src/r-installation.ts | 45 ++++++++++++--------- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/extensions/positron-r/src/kernel.ts b/extensions/positron-r/src/kernel.ts index 5b6d717d61e..df1399bf043 100644 --- a/extensions/positron-r/src/kernel.ts +++ b/extensions/positron-r/src/kernel.ts @@ -2,6 +2,7 @@ * Copyright (C) 2023 Posit Software, PBC. All rights reserved. *--------------------------------------------------------------------------------------------*/ +import * as os from 'os'; import * as vscode from 'vscode'; /** @@ -25,11 +26,13 @@ export function getArkKernelPath(context: vscode.ExtensionContext): string | und return kernelPath; } + const kernelName = os.platform() === 'win32' ? 'ark.exe' : 'ark'; + // No kernel path specified; try the default (embedded) kernel. This is where the kernel // is placed in release builds. const path = require('path'); const fs = require('fs'); - const embeddedKernel = path.join(context.extensionPath, 'dist', 'bin', 'ark'); + const embeddedKernel = path.join(context.extensionPath, 'dist', 'bin', kernelName); if (fs.existsSync(embeddedKernel)) { return embeddedKernel; } @@ -39,8 +42,8 @@ export function getArkKernelPath(context: vscode.ExtensionContext): string | und // by developers, who have `positron` and `amalthea` directories side-by-side. let devKernel = undefined; const positronParent = path.dirname(path.dirname(path.dirname(context.extensionPath))); - const devDebugKernel = path.join(positronParent, 'amalthea', 'target', 'debug', 'ark'); - const devReleaseKernel = path.join(positronParent, 'amalthea', 'target', 'release', 'ark'); + const devDebugKernel = path.join(positronParent, 'amalthea', 'target', 'debug', kernelName); + const devReleaseKernel = path.join(positronParent, 'amalthea', 'target', 'release', kernelName); const debugModified = fs.statSync(devDebugKernel, { throwIfNoEntry: false })?.mtime; const releaseModified = fs.statSync(devReleaseKernel, { throwIfNoEntry: false })?.mtime; @@ -55,7 +58,7 @@ export function getArkKernelPath(context: vscode.ExtensionContext): string | und // Finally, look for a local copy of the kernel in our `resources` directory. This is // where the kernel is placed by the `install-kernel` script in development builds. - const localKernel = path.join(context.extensionPath, 'resources', 'ark', 'ark'); + const localKernel = path.join(context.extensionPath, 'resources', 'ark', kernelName); if (fs.existsSync(localKernel)) { return localKernel; } diff --git a/extensions/positron-r/src/provider.ts b/extensions/positron-r/src/provider.ts index 803b30c4018..f5b232f4167 100644 --- a/extensions/positron-r/src/provider.ts +++ b/extensions/positron-r/src/provider.ts @@ -71,14 +71,21 @@ export async function* rRuntimeDiscoverer( binaries.add(b); } - // make sure we include R executable found on the PATH - // we've probably already discovered it, but we still need to single it out, so that we mark - // that particular R installation as the current one - const whichR = await which('R', { nothrow: true }) as string; - if (whichR) { - const whichRCanonical = fs.realpathSync(whichR); - rInstallations.push(new RInstallation(whichRCanonical, true)); - binaries.delete(whichRCanonical); + // TODO: Windows + // On Windows this finds `C:\Program Files\R\bin\R.BAT`, a batch file that starts + // the underlying version of R, i.e. try right clicking and editing the batch file to see the + // underlying path it ends up using. We will need some way to associate this with the `R.exe` + // file it ends up starting. + if (os.platform() !== 'win32') { + // make sure we include R executable found on the PATH + // we've probably already discovered it, but we still need to single it out, so that we mark + // that particular R installation as the current one + const whichR = await which('R', { nothrow: true }) as string; + if (whichR) { + const whichRCanonical = fs.realpathSync(whichR); + rInstallations.push(new RInstallation(whichRCanonical, true)); + binaries.delete(whichRCanonical); + } } binaries.forEach((b: string) => { @@ -297,11 +304,12 @@ export async function getRunningRRuntime(runtimes: Map): Promi function rHeadquarters(): string { switch (process.platform) { case 'darwin': - return '/Library/Frameworks/R.framework/Versions'; + return path.join('/Library', 'Frameworks', 'R.framework', 'Versions'); case 'linux': - return '/opt/R'; + return path.join('/opt', 'R'); + case 'win32': + return path.join('C:\\', 'Program Files', 'R'); default: - // TODO: handle Windows throw new Error('Unsupported platform'); } } @@ -309,11 +317,12 @@ function rHeadquarters(): string { function binFragment(version: string): string { switch (process.platform) { case 'darwin': - return `${version}/Resources/bin/R`; + return path.join(version, 'Resources', 'bin', 'R'); case 'linux': - return `${version}/bin/R`; + return path.join(version, 'bin', 'R'); + case 'win32': + return path.join(version, 'bin', 'R.exe'); default: - // TODO: handle Windows throw new Error('Unsupported platform'); } } @@ -379,6 +388,7 @@ function isRStudioUser(): boolean { * @returns The path to RStudio's state folder directory. */ function rstudioStateFolderPath(pathToAppend = ''): string { + // TODO: Windows const newPath = path.join(process.env.HOME!, '.local/share/rstudio', pathToAppend); return newPath; } diff --git a/extensions/positron-r/src/r-installation.ts b/extensions/positron-r/src/r-installation.ts index 2686f6dfc7b..bfcdaf59470 100644 --- a/extensions/positron-r/src/r-installation.ts +++ b/extensions/positron-r/src/r-installation.ts @@ -2,6 +2,7 @@ * Copyright (C) 2023 Posit Software, PBC. All rights reserved. *--------------------------------------------------------------------------------------------*/ +import * as os from 'os'; import * as semver from 'semver'; import * as path from 'path'; import * as fs from 'fs'; @@ -42,25 +43,30 @@ export class RInstallation { this.binpath = pth; this.current = current; - const binLines = readLines(this.binpath); - const re = new RegExp('Shell wrapper for R executable'); - if (!binLines.some(x => re.test(x))) { - Logger.info('Binary is not a shell script wrapping the executable'); - return; - } - const targetLine = binLines.find(line => line.match('R_HOME_DIR')); - if (!targetLine) { - Logger.info('Can\'t determine R_HOME_DIR from the binary'); - return; - } - // macOS: R_HOME_DIR=/Library/Frameworks/R.framework/Versions/4.3-arm64/Resources - // macOS non-orthogonal: R_HOME_DIR=/Library/Frameworks/R.framework/Resources - // linux: R_HOME_DIR=/opt/R/4.2.3/lib/R - const R_HOME_DIR = extractValue(targetLine, 'R_HOME_DIR'); - this.homepath = R_HOME_DIR; - if (this.homepath === '') { - Logger.info('Can\'t determine R_HOME_DIR from the binary'); - return; + if (os.platform() === 'win32') { + // TODO: Windows - do we want something more robust here? + this.homepath = path.join(pth, '..', '..'); + } else { + const binLines = readLines(this.binpath); + const re = new RegExp('Shell wrapper for R executable'); + if (!binLines.some(x => re.test(x))) { + Logger.info('Binary is not a shell script wrapping the executable'); + return; + } + const targetLine = binLines.find(line => line.match('R_HOME_DIR')); + if (!targetLine) { + Logger.info('Can\'t determine R_HOME_DIR from the binary'); + return; + } + // macOS: R_HOME_DIR=/Library/Frameworks/R.framework/Versions/4.3-arm64/Resources + // macOS non-orthogonal: R_HOME_DIR=/Library/Frameworks/R.framework/Resources + // linux: R_HOME_DIR=/opt/R/4.2.3/lib/R + const R_HOME_DIR = extractValue(targetLine, 'R_HOME_DIR'); + this.homepath = R_HOME_DIR; + if (this.homepath === '') { + Logger.info('Can\'t determine R_HOME_DIR from the binary'); + return; + } } // orthogonality is a concern specific to macOS @@ -89,6 +95,7 @@ export class RInstallation { // macOS arm64: Built: R 4.3.1; aarch64-apple-darwin20; 2023-06-16 21:52:54 UTC; unix // macOS intel: Built: R 4.3.1; x86_64-apple-darwin20; 2023-06-16 21:51:34 UTC; unix // linux: Built: R 4.2.3; x86_64-pc-linux-gnu; 2023-03-15 09:03:13 UTC; unix + // windows: Built: R 4.3.2; x86_64-w64-mingw32; 2023-10-31 13:57:45 UTC; windows const builtField = extractValue(targetLine2, 'Built', ':'); const builtParts = builtField.split(new RegExp(';\\s+')); From aebf50c7713ae108df8376f4f3f63a119e7df15e Mon Sep 17 00:00:00 2001 From: DavisVaughan Date: Wed, 29 Nov 2023 11:44:46 -0500 Subject: [PATCH 3/7] Place the current R `bin/` folder on the `PATH` Like RStudio https://github.com/rstudio/rstudio/blob/4edf9598de477ba4eca8038980f77169e0d9fb65/src/node/desktop/src/main/detect-r.ts#L173-L179 --- extensions/positron-r/src/provider.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/extensions/positron-r/src/provider.ts b/extensions/positron-r/src/provider.ts index f5b232f4167..741b564b279 100644 --- a/extensions/positron-r/src/provider.ts +++ b/extensions/positron-r/src/provider.ts @@ -166,6 +166,22 @@ export async function* rRuntimeDiscoverer( } + if (process.platform === 'win32') { + // On Windows, we must place the `bin/` path for the current R version on the PATH + // so that the DLLs in that same folder can be resolved properly when ark starts up + // (like `R.dll`, `Rblas.dll`, `Rgraphapp.dll`, `Riconv.dll`, and `Rlapack.dll`). + // https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-unpackaged-apps + const binpath = path.join(rHome.homepath, 'bin', 'x64'); + + const processPath = process.env['PATH']; + + const subprocessPath = processPath === undefined ? + binpath : + processPath + ';' + binpath; + + env['PATH'] = subprocessPath; + } + // Is the runtime path within the user's home directory? const homedir = os.homedir(); const isUserInstallation = rHome.homepath.startsWith(homedir); From 184a52db0ab6e705478c9089801ace4dc163418b Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Wed, 6 Dec 2023 10:49:57 -0800 Subject: [PATCH 4/7] Add dll2lib.R --- extensions/positron-r/scripts/dll2lib.R | 68 +++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 extensions/positron-r/scripts/dll2lib.R diff --git a/extensions/positron-r/scripts/dll2lib.R b/extensions/positron-r/scripts/dll2lib.R new file mode 100644 index 00000000000..26edab7c20f --- /dev/null +++ b/extensions/positron-r/scripts/dll2lib.R @@ -0,0 +1,68 @@ +# 2023-12-06 +# At the time of writing, this script is for "manual" execution on Windows. +# For the moment, it is a one-time setup task for a specific R installation. +# +# Two key points: +# 1. You must be running R as an administrator to execute this script. +# If, for example, you do this via RStudio, make sure to launch RStudio as an administrator. +# 2. Edit `path` to point to the correct version of the Visual Studio tools for your installation. + +# `path` for Davis was slightly different than Jenny +# path <- "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.37.32822\\bin\\Hostx86\\x86" +path <- "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.38.33130\\bin\\Hostx86\\x86" +if (!dir.exists(path)) { + stop("Visual Studio tools directory is incorrect or the tools have not been installed.") +} + +# Put the path containing the tools on the PATH. +Sys.setenv(PATH = paste(path, Sys.getenv("PATH"), sep = ";")) + +# Find R DLLs. +dlls <- list.files(R.home("bin"), pattern = "dll$", full.names = TRUE) + +message("Generating .lib files for DLLs in ", R.home("bin")) + +# Generate corresponding 'lib' file for each DLL. +for (dll in dlls) { + + # check to see if we've already generated our exports + def <- sub("dll$", "def", dll) + if (file.exists(def)) + next + + # Call it on R.dll to generate exports. + command <- sprintf("dumpbin.exe /EXPORTS /NOLOGO %s", dll) + message("> ", command) + output <- system(paste(command), intern = TRUE) + + # Remove synonyms. + output <- sub("=.*$", "", output) + + # Find start, end markers + start <- grep("ordinal\\s+hint\\s+RVA\\s+name", output) + end <- grep("^\\s*Summary\\s*$", output) + contents <- output[start:(end - 1)] + contents <- contents[nzchar(contents)] + + # Remove forwarded fields (not certain that this does anything) + contents <- grep("forwarded to", contents, invert = TRUE, value = TRUE, fixed = TRUE) + + # parse into a table + tbl <- read.table(text = contents, header = TRUE, stringsAsFactors = FALSE) + exports <- tbl$name + + # sort and re-format exports + exports <- sort(exports) + exports <- c("EXPORTS", paste("\t", tbl$name, sep = "")) + + # Write the exports to a def file + def <- sub("dll$", "def", dll) + cat(exports, file = def, sep = "\n") + + # Call 'lib.exe' to generate the library file. + outfile <- sub("dll$", "lib", dll) + fmt <- "lib.exe /def:%s /out:%s /machine:%s" + cmd <- sprintf(fmt, def, outfile, .Platform$r_arch) + system(cmd) + +} From ebec5c9fecc17990f20a7986ed698e1ce23bfd5c Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 6 Dec 2023 17:08:10 -0500 Subject: [PATCH 5/7] Add the warning back in, but after local ark check --- extensions/positron-r/scripts/install-kernel.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/positron-r/scripts/install-kernel.ts b/extensions/positron-r/scripts/install-kernel.ts index 53a5b71ea82..3cd5e9a4b9b 100644 --- a/extensions/positron-r/scripts/install-kernel.ts +++ b/extensions/positron-r/scripts/install-kernel.ts @@ -228,8 +228,6 @@ async function downloadAndReplaceArk(version: string, } async function main() { - // TODO: Relying on locally build ark to exist for Windows - // Before we do any work, check to see if there is a locally built copy of Amalthea in the // `amalthea / target` directory. If so, we'll assume that the user is a kernel developer // and skip the download; this version will take precedence over any downloaded version. @@ -271,6 +269,12 @@ async function main() { `checking downloaded version.`); } + // TODO: Remove once we have ark releases + if (platform() === 'win32') { + console.warn('On Windows, only locally built versions of Ark are currently supported.'); + return; + } + const packageJsonVersion = await getVersionFromPackageJson(); const localArkVersion = await getLocalArkVersion(); From ad04a63cefcf9ec9c8f5b9dcd63a7f8a0b3f9789 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 6 Dec 2023 17:52:14 -0500 Subject: [PATCH 6/7] Dynamically look up VS tools year and version --- build/filters.js | 1 + .../positron-r/resources/scripts/dll2lib.R | 119 ++++++++++++++++++ extensions/positron-r/scripts/dll2lib.R | 68 ---------- 3 files changed, 120 insertions(+), 68 deletions(-) create mode 100644 extensions/positron-r/resources/scripts/dll2lib.R delete mode 100644 extensions/positron-r/scripts/dll2lib.R diff --git a/build/filters.js b/build/filters.js index d22a651e54f..de1ada24977 100644 --- a/build/filters.js +++ b/build/filters.js @@ -150,6 +150,7 @@ module.exports.indentationFilter = [ // --- Start Positron --- '!**/amalthea/**/*', + '!extensions/positron-r/resources/scripts/*.R' // --- End Positron --- ]; diff --git a/extensions/positron-r/resources/scripts/dll2lib.R b/extensions/positron-r/resources/scripts/dll2lib.R new file mode 100644 index 00000000000..4c346cecabd --- /dev/null +++ b/extensions/positron-r/resources/scripts/dll2lib.R @@ -0,0 +1,119 @@ +# --------------------------------------------------------------------------------------------- +# Copyright (C) 2023 Posit Software, PBC. All rights reserved. +# --------------------------------------------------------------------------------------------- + +# 2023-12-06 +# At the time of writing, this script is for "manual" execution on Windows. +# For the moment, it is a one-time setup task for a specific R installation. +# +# You must be running R as an administrator to execute this script. +# If, for example, you do this via RStudio, make sure to launch RStudio as an administrator. + +# Typically something like: +# "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.37.32822\\bin\\Hostx86\\x86" +# We try to dynamically look up the year (2022) and exact version (14.37.32822) +# in case they change on us +get_visual_studio_tools_directory <- function() { + path <- file.path("C:", "Program Files", "Microsoft Visual Studio") + + if (!dir.exists(path)) { + stop("Microsoft Visual Studio has not been installed.") + } + + # Dynamically look up the next folder, which should be a year like `2022` + files <- dir(path) + n_files <- length(files) + + if (n_files == 0L) { + stop("Expected at least 1 version of Microsoft Visual Studio.") + } else if (n_files == 1L) { + year <- files + } else { + warning("Expected exactly 1 version of Microsoft Visual Studio. Using the last (hopefully newest) version.") + year <- files[[n_files]] + } + + path <- file.path(path, year, "Community", "VC", "Tools", "MSVC") + + if (!dir.exists(path)) { + stop("Microsoft Visual Studio tools have not been installed.") + } + + # Dynamically look up the next folder, which should be a very specific version + # of the tools like `14.38.33130` + files <- dir(path) + n_files <- length(files) + + if (n_files == 0L) { + stop("Expected at least 1 version of the Microsoft Visual Studio tools.") + } else if (n_files == 1L) { + version <- files + } else { + warning("Expected exactly 1 version of the Microsoft Visual Studio tools. Using the last (hopefully newest) version.") + version <- files[[n_files]] + } + + path <- file.path(path, version, "bin", "Hostx86", "x86") + + if (!dir.exists(path)) { + stop("Microsoft Visual Studio tools directory is incorrect or missing.") + } + + normalizePath(path, mustWork = TRUE) +} + +# Get the Visual Studio tools directory where `dumpbin.exe` and `lib.exe` live +path <- get_visual_studio_tools_directory() + +# Put the path containing the tools on the PATH. +Sys.setenv(PATH = paste(path, Sys.getenv("PATH"), sep = ";")) + +# Find R DLLs. +dlls <- list.files(R.home("bin"), pattern = "dll$", full.names = TRUE) + +message("Generating .lib files for DLLs in ", R.home("bin")) + +# Generate corresponding 'lib' file for each DLL. +for (dll in dlls) { + + # Check to see if we've already generated our exports + def <- sub("dll$", "def", dll) + if (file.exists(def)) + next + + # Call it on R.dll to generate exports. + command <- sprintf("dumpbin.exe /EXPORTS /NOLOGO %s", dll) + message("> ", command) + output <- system(paste(command), intern = TRUE) + + # Remove synonyms. + output <- sub("=.*$", "", output) + + # Find start, end markers + start <- grep("ordinal\\s+hint\\s+RVA\\s+name", output) + end <- grep("^\\s*Summary\\s*$", output) + contents <- output[start:(end - 1)] + contents <- contents[nzchar(contents)] + + # Remove forwarded fields (not certain that this does anything) + contents <- grep("forwarded to", contents, invert = TRUE, value = TRUE, fixed = TRUE) + + # Parse into a table + tbl <- read.table(text = contents, header = TRUE, stringsAsFactors = FALSE) + exports <- tbl$name + + # Sort and re-format exports + exports <- sort(exports) + exports <- c("EXPORTS", paste("\t", tbl$name, sep = "")) + + # Write the exports to a def file + def <- sub("dll$", "def", dll) + cat(exports, file = def, sep = "\n") + + # Call 'lib.exe' to generate the library file. + outfile <- sub("dll$", "lib", dll) + fmt <- "lib.exe /def:%s /out:%s /machine:%s" + cmd <- sprintf(fmt, def, outfile, .Platform$r_arch) + system(cmd) + +} diff --git a/extensions/positron-r/scripts/dll2lib.R b/extensions/positron-r/scripts/dll2lib.R deleted file mode 100644 index 26edab7c20f..00000000000 --- a/extensions/positron-r/scripts/dll2lib.R +++ /dev/null @@ -1,68 +0,0 @@ -# 2023-12-06 -# At the time of writing, this script is for "manual" execution on Windows. -# For the moment, it is a one-time setup task for a specific R installation. -# -# Two key points: -# 1. You must be running R as an administrator to execute this script. -# If, for example, you do this via RStudio, make sure to launch RStudio as an administrator. -# 2. Edit `path` to point to the correct version of the Visual Studio tools for your installation. - -# `path` for Davis was slightly different than Jenny -# path <- "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.37.32822\\bin\\Hostx86\\x86" -path <- "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.38.33130\\bin\\Hostx86\\x86" -if (!dir.exists(path)) { - stop("Visual Studio tools directory is incorrect or the tools have not been installed.") -} - -# Put the path containing the tools on the PATH. -Sys.setenv(PATH = paste(path, Sys.getenv("PATH"), sep = ";")) - -# Find R DLLs. -dlls <- list.files(R.home("bin"), pattern = "dll$", full.names = TRUE) - -message("Generating .lib files for DLLs in ", R.home("bin")) - -# Generate corresponding 'lib' file for each DLL. -for (dll in dlls) { - - # check to see if we've already generated our exports - def <- sub("dll$", "def", dll) - if (file.exists(def)) - next - - # Call it on R.dll to generate exports. - command <- sprintf("dumpbin.exe /EXPORTS /NOLOGO %s", dll) - message("> ", command) - output <- system(paste(command), intern = TRUE) - - # Remove synonyms. - output <- sub("=.*$", "", output) - - # Find start, end markers - start <- grep("ordinal\\s+hint\\s+RVA\\s+name", output) - end <- grep("^\\s*Summary\\s*$", output) - contents <- output[start:(end - 1)] - contents <- contents[nzchar(contents)] - - # Remove forwarded fields (not certain that this does anything) - contents <- grep("forwarded to", contents, invert = TRUE, value = TRUE, fixed = TRUE) - - # parse into a table - tbl <- read.table(text = contents, header = TRUE, stringsAsFactors = FALSE) - exports <- tbl$name - - # sort and re-format exports - exports <- sort(exports) - exports <- c("EXPORTS", paste("\t", tbl$name, sep = "")) - - # Write the exports to a def file - def <- sub("dll$", "def", dll) - cat(exports, file = def, sep = "\n") - - # Call 'lib.exe' to generate the library file. - outfile <- sub("dll$", "lib", dll) - fmt <- "lib.exe /def:%s /out:%s /machine:%s" - cmd <- sprintf(fmt, def, outfile, .Platform$r_arch) - system(cmd) - -} From ca2025519627ae8ec5942af7575dfec2f20bf12e Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 6 Dec 2023 18:10:40 -0500 Subject: [PATCH 7/7] Move `dll2lib.R` to amalthea --- .../positron-r/resources/scripts/dll2lib.R | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 extensions/positron-r/resources/scripts/dll2lib.R diff --git a/extensions/positron-r/resources/scripts/dll2lib.R b/extensions/positron-r/resources/scripts/dll2lib.R deleted file mode 100644 index 4c346cecabd..00000000000 --- a/extensions/positron-r/resources/scripts/dll2lib.R +++ /dev/null @@ -1,119 +0,0 @@ -# --------------------------------------------------------------------------------------------- -# Copyright (C) 2023 Posit Software, PBC. All rights reserved. -# --------------------------------------------------------------------------------------------- - -# 2023-12-06 -# At the time of writing, this script is for "manual" execution on Windows. -# For the moment, it is a one-time setup task for a specific R installation. -# -# You must be running R as an administrator to execute this script. -# If, for example, you do this via RStudio, make sure to launch RStudio as an administrator. - -# Typically something like: -# "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.37.32822\\bin\\Hostx86\\x86" -# We try to dynamically look up the year (2022) and exact version (14.37.32822) -# in case they change on us -get_visual_studio_tools_directory <- function() { - path <- file.path("C:", "Program Files", "Microsoft Visual Studio") - - if (!dir.exists(path)) { - stop("Microsoft Visual Studio has not been installed.") - } - - # Dynamically look up the next folder, which should be a year like `2022` - files <- dir(path) - n_files <- length(files) - - if (n_files == 0L) { - stop("Expected at least 1 version of Microsoft Visual Studio.") - } else if (n_files == 1L) { - year <- files - } else { - warning("Expected exactly 1 version of Microsoft Visual Studio. Using the last (hopefully newest) version.") - year <- files[[n_files]] - } - - path <- file.path(path, year, "Community", "VC", "Tools", "MSVC") - - if (!dir.exists(path)) { - stop("Microsoft Visual Studio tools have not been installed.") - } - - # Dynamically look up the next folder, which should be a very specific version - # of the tools like `14.38.33130` - files <- dir(path) - n_files <- length(files) - - if (n_files == 0L) { - stop("Expected at least 1 version of the Microsoft Visual Studio tools.") - } else if (n_files == 1L) { - version <- files - } else { - warning("Expected exactly 1 version of the Microsoft Visual Studio tools. Using the last (hopefully newest) version.") - version <- files[[n_files]] - } - - path <- file.path(path, version, "bin", "Hostx86", "x86") - - if (!dir.exists(path)) { - stop("Microsoft Visual Studio tools directory is incorrect or missing.") - } - - normalizePath(path, mustWork = TRUE) -} - -# Get the Visual Studio tools directory where `dumpbin.exe` and `lib.exe` live -path <- get_visual_studio_tools_directory() - -# Put the path containing the tools on the PATH. -Sys.setenv(PATH = paste(path, Sys.getenv("PATH"), sep = ";")) - -# Find R DLLs. -dlls <- list.files(R.home("bin"), pattern = "dll$", full.names = TRUE) - -message("Generating .lib files for DLLs in ", R.home("bin")) - -# Generate corresponding 'lib' file for each DLL. -for (dll in dlls) { - - # Check to see if we've already generated our exports - def <- sub("dll$", "def", dll) - if (file.exists(def)) - next - - # Call it on R.dll to generate exports. - command <- sprintf("dumpbin.exe /EXPORTS /NOLOGO %s", dll) - message("> ", command) - output <- system(paste(command), intern = TRUE) - - # Remove synonyms. - output <- sub("=.*$", "", output) - - # Find start, end markers - start <- grep("ordinal\\s+hint\\s+RVA\\s+name", output) - end <- grep("^\\s*Summary\\s*$", output) - contents <- output[start:(end - 1)] - contents <- contents[nzchar(contents)] - - # Remove forwarded fields (not certain that this does anything) - contents <- grep("forwarded to", contents, invert = TRUE, value = TRUE, fixed = TRUE) - - # Parse into a table - tbl <- read.table(text = contents, header = TRUE, stringsAsFactors = FALSE) - exports <- tbl$name - - # Sort and re-format exports - exports <- sort(exports) - exports <- c("EXPORTS", paste("\t", tbl$name, sep = "")) - - # Write the exports to a def file - def <- sub("dll$", "def", dll) - cat(exports, file = def, sep = "\n") - - # Call 'lib.exe' to generate the library file. - outfile <- sub("dll$", "lib", dll) - fmt <- "lib.exe /def:%s /out:%s /machine:%s" - cmd <- sprintf(fmt, def, outfile, .Platform$r_arch) - system(cmd) - -}