πŸ”—Quick Start: Mimicking the R Build Terminal

πŸ”—For x86_64 (Intel/AMD) builds

Open the MSYS2 UCRT64 shell that ships with Rtools45. On a default install this is:

c:\rtools45\ucrt64.exe

Or from cmd.exe:

c:\rtools45\usr\bin\bash.exe --login -i

Once inside, verify the environment:

which gcc        # should resolve to /ucrt64/bin/gcc or similar
which make       # should resolve to the MSYS2 make
echo $MSYSTEM    # should say UCRT64

πŸ”—For aarch64 (ARM) builds

Open the MSYS2 CLANG64 shell from Rtools45-aarch64:

c:\rtools45-aarch64\clangarm64.exe

Or:

c:\rtools45-aarch64\usr\bin\bash.exe --login -i

Verify:

which clang      # should resolve inside the toolchain
echo $MSYSTEM    # should say CLANGARM64

πŸ”—What the Build System Actually Does

πŸ”—Shell: sh (MSYS2), not cmd.exe

The R build Makefiles set:

SHELL = sh

(in src/gnuwin32/fixed/Makeconf, line 9)

This sh is the MSYS2 Bourne shell (/usr/bin/sh) shipped inside Rtools. All Make recipe lines execute through it. This gives you POSIX shell semantics (pipes, redirects, sed, which, etc.) even on Windows.

Important distinction: when R is running (not building) and a user calls system(), R uses COMSPEC (typically cmd.exe /c ...) instead. See src/gnuwin32/run.c.

πŸ”—Toolchain discovery: everything must be on PATH

Since Rtools42, R assumes the compiler toolchain is on PATH. There is no hardcoded path to gcc or any tool. From MkRules.rules:

β€œSince Rtools42, Rtools assumes that the compiler toolchain (e.g. gcc, as, … for Intel targets) is on PATH”

The key PATH entries for Rtools45 x86_64 are:

c:/rtools45/x86_64-w64-mingw32.static.posix/bin   # gcc, g++, gfortran, ar, etc.
c:/rtools45/usr/bin                                 # sh, make, sed, tar, etc.

For aarch64:

c:/rtools45-aarch64/aarch64-w64-mingw32.static.posix/bin   # clang, flang, lld, etc.
c:/rtools45-aarch64/usr/bin                                  # sh, make, sed, tar, etc.

These paths come from Rcmd_environ (lines 39-42) and are what the Rtools MSYS2 shell launchers set up for you automatically.

πŸ”—LOCAL_SOFT: auto-detected from compiler location

LOCAL_SOFT points to the root of the Rtools software collection (headers and static libraries). It is computed dynamically from wherever gcc/clang lives:

LOCAL_SOFT ?= $(shell which `echo $(CC) | sed -e 's/ .*//g'` | sed -e 's!/bin/[^/]\+!!g')

In practice:

  • x86_64: LOCAL_SOFT = /ucrt64 (i.e. c:/rtools45/x86_64-w64-mingw32.static.posix)
  • aarch64: LOCAL_SOFT = /clangarm64 (i.e. c:/rtools45-aarch64/aarch64-w64-mingw32.static.posix)

You can override it with R_CUSTOM_TOOLS_SOFT.


πŸ”—Key Environment Variables

VariablePurposeDefault
MSYSTEMSet by MSYS2 shell launcher; controls which toolchain prefix is activeUCRT64 or CLANGARM64
RTOOLS45_HOMEOverride Rtools install locationc:/rtools45
RTOOLS45_AARCH64_HOMEOverride aarch64 Rtools locationc:/rtools45-aarch64
R_CUSTOM_TOOLS_SOFTOverride LOCAL_SOFT for packages(unset)
R_CUSTOM_TOOLS_PATHOverride the Rtools PATH entries(unset)
USE_LLVMSet to 1 to use clang/flang instead of gcc/gfortran(unset)
WIN64 for x86_64 subarch layout; empty for aarch64 (no subarch)64
BINPREF / BINPREF64Prefix for tool names (for cross-compilation)(empty)
MSYS2_ENV_CONV_EXCLR sets this to R_ARCH to prevent MSYS2 path manglingset in C code

πŸ”—Configuration File Chain

When you run make in src/gnuwin32/, here is what happens:

MkRules.dist          # shipped defaults (template, not read directly)
    |
    v
MkRules.local         # your overrides (copy from .dist, uncomment what you need)
    +
MkRules.rules         # runtime logic: compiler detection, LOCAL_SOFT, tool paths
    =
MkRules               # generated by concatenating .local + .rules
    |
    v
fixed/etc/Makeconf    # template for installed R's Makeconf (@ tokens substituted)
    |
    v  (via fixed/Makefile sed substitutions)
$R_HOME/etc/Makeconf  # final Makeconf shipped with R

πŸ”—What MkRules.rules computes automatically

  • CC = $(BINPREF)$(CCBASE) $(M_ARCH) β€” compiler command
  • CCBASE = gcc or clang (if USE_LLVM is set)
  • FC = gfortran or flang
  • AR, NM, RANLIB, DLLTOOL, RESCOMP β€” all prefixed with BINPREF and optionally LLVMPREF (llvm-) for LLVM builds
  • TEXI2DVI = env COMSPEC= texi2dvi β€” clears COMSPEC to work around an MSYS2 bug
  • PKG_CONFIG = $(BINPREF)pkg-config β€” for library detection

πŸ”—Step-by-Step: Set Up a Terminal That Matches the Build Environment

Just launch the appropriate .exe:

  • x86_64: c:\rtools45\ucrt64.exe
  • aarch64: c:\rtools45-aarch64\clangarm64.exe

This sets MSYSTEM, PATH, and everything else correctly.

πŸ”—Option B: Manual setup from cmd.exe or PowerShell

@echo off
set RTOOLS45_HOME=c:\rtools45
set PATH=%RTOOLS45_HOME%\x86_64-w64-mingw32.static.posix\bin;%RTOOLS45_HOME%\usr\bin;%PATH%
set MSYSTEM=UCRT64

rem Launch the MSYS2 sh (what make uses as SHELL)
%RTOOLS45_HOME%\usr\bin\bash.exe --login

For aarch64, replace paths and set MSYSTEM=CLANGARM64.

πŸ”—Option C: From an existing MSYS2 bash, set up for R building

export PATH="/c/rtools45/x86_64-w64-mingw32.static.posix/bin:/c/rtools45/usr/bin:$PATH"

# Navigate to the R source
cd /c/path/to/r-source/src/gnuwin32

# Create MkRules.local if you haven't (copy from dist, edit as needed)
cp MkRules.dist MkRules.local

# Build
make all recommended

πŸ”—How R Invokes make for Package Installation

When you run R CMD INSTALL on a package with compiled code, R:

  1. Reads $R_HOME/etc/Makeconf (which has all the tool paths baked in)
  2. Reads the package’s Makevars.win (if present)
  3. Invokes make with SHELL = sh
  4. The compiler (gcc/clang) and all tools are found on PATH

The Rcmd_environ file sets up the PATH for this (lines 39-42 are uncommented during installer builds):

R_RTOOLS45_PATH="${RTOOLS45_HOME:-c:/rtools45}/x86_64-w64-mingw32.static.posix/bin;${RTOOLS45_HOME:-c:/rtools45}/usr/bin"
PATH="${R_CUSTOM_TOOLS_PATH:-${R_RTOOLS45_PATH}};${PATH}/"

πŸ”—Common Gotchas

  1. SHELL = sh, not bash. Make recipes use sh semantics. Bashisms (arrays, [[ ]], etc.) will fail in Makefile recipes.

  2. COMSPEC is cleared for texi2dvi. TEXI2DVI = env COMSPEC= texi2dvi works around an MSYS2 bug where texi2dvi gets confused by Windows COMSPEC.

  3. MSYS2 path conversion. MSYS2 auto-converts /c/foo to C:\foo in some contexts. R sets MSYS2_ENV_CONV_EXCL=R_ARCH in C code (src/gnuwin32/system.c) to prevent mangling of R_ARCH.

  4. No hardcoded Rtools path. If gcc isn’t on PATH, the build will fail β€” there is no fallback path detection.

  5. pkg-config is used by default (USE_PKG_CONFIG = 1) to find library flags. Falls back to hardcoded library lists if pkg-config is unavailable.

  6. Static linking. Rtools uses static libraries (the .static.posix in the toolchain name). DLLFLAGS includes -static-libgcc and libraries are linked statically from LOCAL_SOFT/lib.