배포판이 제공하는 R 패키지는 버전이 뒤처지는 경우가 많고, 분석 플랫폼과 연동하려면 특정 버전을 특정 경로에 두어야 하는 일이 잦다. 소스에서 빌드하면 버전과 설치 경로를 모두 제어할 수 있다. 여기서는 RHEL 계열 기준으로 소스 빌드와, 인터넷이 없는 서버로 CRAN 패키지를 옮기는 절차를 정리한다. 최신 버전은 R 4.6.1 이다[1].
빌드에 필요한 패키지를 먼저 넣는다. 빠뜨리면 configure 가 조용히 기능을 꺼 버려, 나중에 패키지 설치 단계에서야 문제가 드러난다.
dnf groupinstall -y "Development Tools"
dnf install -y gcc-gfortran \
readline-devel ncurses-devel \
bzip2-devel xz-devel zlib-devel pcre2-devel \
libcurl-devel openssl-devel libxml2-devel \
cairo-devel libX11-devel libXt-devel libjpeg-devel libpng-devel libtiff-devel \
java-11-openjdk-devel
gcc-gfortran 은 선택이 아니다. R 의 수치 연산 코드 상당 부분이 Fortran 이라 없으면 configure 부터 막힌다. cairo-devel 과 X 관련 패키지가 없으면 그래픽 장치가 빠진 채 빌드된다 — 서버에서 파일로만 그림을 뽑더라도 cairo 는 필요하다.
RHEL 계열에서는 위 -devel 패키지 상당수가 CodeReady Builder(CRB) 저장소에 있다. 미리 켜 둔다.
dnf config-manager --set-enabled crb # RHEL 9 · Rocky 9
버전을 경로에 넣어 두면 여러 버전을 나란히 둘 수 있다.
cd /usr/local/src
curl -LO https://cran.r-project.org/src/base/R-4/R-4.6.1.tar.gz
tar xf R-4.6.1.tar.gz
cd R-4.6.1
./configure \
--prefix=/opt/R/4.6.1 \
--enable-R-shlib \
--enable-memory-profiling \
--with-blas --with-lapack \
--with-readline --with-x=no
make -j"$(nproc)"
make install
--enable-R-shlib 는 공유 라이브러리 형태의 libR.so 를 만든다. RStudio Server 나 다른 프로그램이 R 을 끼워 쓰려면 반드시 필요하다. 나중에 켜려면 통째로 다시 빌드해야 하므로 처음부터 넣는다.
--with-x=no 는 X11 그래픽 장치를 뺀다. 헤드리스 서버에서는 흔한 선택이지만, 이 경우 cairo 기반 장치가 있는지 확인해야 그림을 그릴 수 있다.
설치 후 PATH 를 잡는다. make install 과 PATH 등록은 별개의 명령이므로 반드시 줄을 나눠 실행한다.
echo 'export PATH=/opt/R/4.6.1/bin:$PATH' > /etc/profile.d/r461.sh
source /etc/profile.d/r461.sh
확인한다.
R --version
R RHOME # /opt/R/4.6.1/lib64/R
Rscript -e 'capabilities()'
capabilities() 에서 cairo · libcurl · png 가 TRUE 인지 본다. FALSE 가 있으면 개발 패키지를 넣고 다시 빌드한다.
download.packages() 에는 dependencies 인자가 없다[2]. 넘겨도 무시되고 이름을 적은 패키지만 내려받는다. 이대로 옮기면 폐쇄망에서 설치할 때 "there is no package called ..." 가 줄줄이 난다.
의존성 목록은 tools::package_dependencies() 로 먼저 펼친 뒤 그 전체를 내려받는다.
# 인터넷이 되는 서버에서 실행
options(repos = c(CRAN = "https://cran.r-project.org"))
pkgs <- c("tidyverse", "data.table", "caret", "xgboost", "h2o",
"openxlsx", "haven", "lubridate", "doParallel")
db <- available.packages(type = "source")
deps <- tools::package_dependencies(
pkgs, db = db, recursive = TRUE,
which = c("Depends", "Imports", "LinkingTo"))
all <- unique(c(pkgs, unlist(deps, use.names = FALSE)))
# base·recommended 패키지는 R 에 이미 들어 있으므로 제외
base_pkgs <- rownames(installed.packages(priority = "high"))
all <- setdiff(all, base_pkgs)
dir.create("/tmp/R_pkgs", recursive = TRUE, showWarnings = FALSE)
download.packages(all, destdir = "/tmp/R_pkgs", type = "source")
which 에 Suggests 를 넣으면 목록이 폭발적으로 늘어난다. 설치에 꼭 필요한 것은 Depends · Imports · LinkingTo 셋이다.
tar czf R_pkgs.tar.gz -C /tmp R_pkgs
# (매체 반입)
tar xzf R_pkgs.tar.gz -C /opt
설치는 디렉터리를 저장소처럼 취급하는 방식이 가장 편하다. 의존성 순서를 R 이 알아서 정한다.
install.packages(
c("tidyverse", "data.table", "caret", "xgboost", "h2o"),
repos = paste0("file:///opt/R_pkgs"),
type = "source"
)
이 방법을 쓰려면 디렉터리에 PACKAGES 색인 파일이 있어야 한다. 반입 전에 만들어 함께 옮기거나, 폐쇄망에서 만든다.
tools::write_PACKAGES("/opt/R_pkgs", type = "source")
색인 없이 파일 목록을 직접 넘기는 방법도 있지만, 이 경우 설치 순서를 R 이 정해 주지 않아 의존성이 앞서지 않으면 실패한다.
install.packages(list.files("/opt/R_pkgs", full.names = TRUE),
repos = NULL, type = "source")
사용자마다 다른 곳에 설치되면 공유 환경에서 문제가 된다. 설치 경로를 한 곳으로 묶는다.
mkdir -p /opt/R/library/4.6.1
echo 'R_LIBS_SITE=/opt/R/library/4.6.1' >> /opt/R/4.6.1/lib64/R/etc/Renviron.site
소스 설치는 C · C++ · Fortran 컴파일을 동반하므로, 해당 시스템 라이브러리가 없으면 그 패키지에서 멈춘다. 자주 걸리는 것들이다.
| 패키지 | 필요한 것 |
|---|---|
stringi |
ICU (libicu-devel). 없으면 번들 ICU 를 받으려 하는데 폐쇄망에서는 실패한다 |
curl · httr |
libcurl-devel |
openssl |
openssl-devel |
xml2 |
libxml2-devel |
RPostgres · RPostgreSQL |
libpq-devel |
RMariaDB |
mariadb-connector-c-devel |
rJava (xlsx · h2o 일부 경로) |
JDK 와 R CMD javareconf |
xgboost |
gcc-c++ |
sf · terra |
gdal-devel · proj-devel · geos-devel |
stringi 는 폐쇄망에서 특히 자주 막힌다. libicu-devel 을 미리 넣어 시스템 ICU 를 쓰게 하거나, configure.vars="ICUDT_DIR=<경로>" 로 ICU 데이터 위치를 알려 준다.
rJava 를 쓰려면 JDK 설치 후 R 쪽 설정을 한 번 갱신해야 한다.
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
R CMD javareconf
pkgs <- c("tidyverse", "data.table", "caret", "xgboost", "h2o", "dplyr")
sapply(pkgs, requireNamespace, quietly = TRUE)
모두 TRUE 여야 한다. require() 대신 requireNamespace() 를 쓰면 부수 효과 없이 적재 가능 여부만 확인할 수 있다.
renv 나 Posit Package Manager 의 스냅샷 저장소를 쓰는 편이 낫다. 위 절차는 "지금 시점의 최신" 을 그대로 가져오는 방식이라 반입 시점마다 버전이 달라진다.BiocManager::repositories() 로 저장소를 추가한 뒤 같은 방식으로 내려받아야 한다. 어떤 패키지가 여기 해당하는지는 대상 목록마다 다르므로 package_dependencies() 결과에서 CRAN 에 없는 이름이 나오는지로 확인한다. (확인 필요)최신 버전 R 4.6.1 (2026-06-24) — 2026-09-20 확인. https://cran.r-project.org/src/base/R-4/ ↩︎
download.packages(pkgs, destdir, available, repos, strip4dest, contriburl, method, type, ...) — 2026-09-20 확인. https://stat.ethz.ch/R-manual/R-devel/library/utils/html/download.packages.html ↩︎