nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4
5 server ? false, # build server version
6
7 fetchFromGitHub,
8 fetchNpmDeps,
9 fetchYarnDeps,
10 fetchzip,
11 replaceVars,
12 runCommand,
13
14 ant,
15 cacert,
16 cmake,
17 git,
18 jdk,
19 makeWrapper,
20 nodejs,
21 npmHooks,
22 xcbuild,
23 yarn,
24 yarnConfigHook,
25 zip,
26
27 apple-sdk_11,
28 boost187,
29 electron_36,
30 fontconfig,
31 gnumake,
32 hunspellDicts,
33 libuuid,
34 llvmPackages,
35 openssl,
36 pam,
37 pandoc,
38 quarto,
39 R,
40 soci,
41 sqlite,
42 zlib,
43
44 nixosTests,
45}:
46
47let
48 electron = electron_36;
49
50 mathJaxSrc = fetchzip {
51 url = "https://s3.amazonaws.com/rstudio-buildtools/mathjax-27.zip";
52 hash = "sha256-J7SZK/9q3HcXTD7WFHxvh++ttuCd89Vc4SEBrUEU0AI=";
53 };
54
55 # rev should ideally be the last commit of the release/rstudio-[codename] branch
56 quartoSrc = fetchFromGitHub {
57 owner = "quarto-dev";
58 repo = "quarto";
59 rev = "8ee12b5d6bd49c7b212eae894bd011ffbeea1c48";
60 hash = "sha256-pTrWedYeG2SWQ4jl2fstKjsweWhj4aAvVDiSfkdU3No=";
61 };
62
63 hunspellDictionaries = lib.filter lib.isDerivation (lib.unique (lib.attrValues hunspellDicts));
64 # These dicts contain identically-named dict files, so we only keep the
65 # -large versions in case of clashes
66 largeDicts = lib.filter (d: lib.hasInfix "-large-wordlist" d.name) hunspellDictionaries;
67 otherDicts = lib.filter (
68 d: !(lib.hasAttr "dictFileName" d && lib.elem d.dictFileName (map (d: d.dictFileName) largeDicts))
69 ) hunspellDictionaries;
70 dictionaries = largeDicts ++ otherDicts;
71
72 # rstudio assumes quarto bundles pandoc into bin/tools/
73 quartoWrapper = runCommand "quarto-wrapper" { } ''
74 mkdir -p $out/bin/tools
75 ln -s ${lib.getExe pandoc} $out/bin/tools/pandoc
76 ln -s ${lib.getExe quarto} $out/bin/quarto
77 ln -s ${quarto}/share $out/share
78 '';
79in
80stdenv.mkDerivation rec {
81 pname = "RStudio";
82 version = "2025.05.1+513";
83
84 src = fetchFromGitHub {
85 owner = "rstudio";
86 repo = "rstudio";
87 tag = "v${version}";
88 hash = "sha256-KaolU82bxzAlYl+aYwlFljqsmNv0dn8XP1llaLK3LQE=";
89 };
90
91 # sources fetched into _deps via cmake's FetchContent
92 extSrcs = stdenv.mkDerivation {
93 name = "${pname}-${version}-ext-srcs";
94 inherit src;
95
96 nativeBuildInputs = [
97 cacert
98 cmake
99 git
100 ];
101
102 installPhase = ''
103 runHook preInstall
104
105 # this will fail, since this is not meant to be a cmake entrypoint
106 # but it will fetch the dependencies regardless
107 cmake -S src/cpp/ext -B build || true
108
109 mkdir -p "$out"
110 cp -r build/_deps/*-src "$out/"
111 find "$out" -name .git -print0 | xargs -0 rm -rf
112
113 runHook postInstall
114 '';
115
116 dontConfigure = true;
117 dontBuild = true;
118 dontFixup = true;
119
120 outputHash = "sha256-YW+l0/RZf8ek217pfWTwsR4PTugMGHyW+vaZEwGjMas=";
121 outputHashAlgo = "sha256";
122 outputHashMode = "recursive";
123 };
124
125 nativeBuildInputs = [
126 cmake
127 git
128
129 ant
130 jdk
131
132 nodejs
133 yarn
134 yarnConfigHook
135 zip
136 ]
137 ++ lib.optionals stdenv.hostPlatform.isDarwin [
138 xcbuild
139 ]
140 ++ lib.optionals (!server) [
141 makeWrapper
142 (nodejs.python.withPackages (ps: [ ps.setuptools ]))
143 npmHooks.npmConfigHook
144 ];
145
146 buildInputs = [
147 boost187
148 libuuid
149 openssl
150 R
151 soci
152 sqlite.dev
153 ]
154 ++ lib.optionals stdenv.hostPlatform.isDarwin [
155 apple-sdk_11
156 ]
157 ++ lib.optionals (!server) [
158 fontconfig
159 ]
160 ++ lib.optionals server [
161 pam
162 zlib
163 ];
164
165 cmakeFlags = [
166 (lib.cmakeFeature "RSTUDIO_TARGET" (if server then "Server" else "Electron"))
167
168 # don't try fetching the external dependencies already fetched in extSrcs
169 (lib.cmakeBool "FETCHCONTENT_FULLY_DISCONNECTED" true)
170
171 (lib.cmakeBool "RSTUDIO_USE_SYSTEM_BOOST" true)
172 (lib.cmakeBool "RSTUDIO_USE_SYSTEM_SOCI" true)
173
174 (lib.cmakeBool "RSTUDIO_DISABLE_CHECK_FOR_UPDATES" true)
175 (lib.cmakeBool "QUARTO_ENABLED" true)
176 (lib.cmakeBool "RSTUDIO_ENABLE_COPILOT" false) # copilot-language-server is unfree
177 (lib.cmakeBool "RSTUDIO_CRASHPAD_ENABLED" false) # This is a NOOP except on x86_64-darwin
178
179 (lib.cmakeFeature "CMAKE_INSTALL_PREFIX" (
180 (placeholder "out") + (if stdenv.hostPlatform.isDarwin then "/Applications" else "/lib/rstudio")
181 ))
182 ]
183 ++ lib.optionals (!server) [
184 (lib.cmakeBool "RSTUDIO_INSTALL_FREEDESKTOP" stdenv.hostPlatform.isLinux)
185 ];
186
187 env = {
188 ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
189
190 # on Darwin, cmake uses find_library to locate R instead of using the PATH
191 NIX_LDFLAGS = "-L${R}/lib/R/lib";
192
193 RSTUDIO_VERSION_MAJOR = lib.versions.major version;
194 RSTUDIO_VERSION_MINOR = lib.versions.minor version;
195 RSTUDIO_VERSION_PATCH = lib.versions.patch version;
196 RSTUDIO_VERSION_SUFFIX = "+" + toString (lib.tail (lib.splitString "+" version));
197 };
198
199 patches = [
200 # Hack RStudio to only use the input R and provided libclang.
201 (replaceVars ./r-location.patch {
202 R = lib.getBin R;
203 })
204 (replaceVars ./clang-location.patch {
205 libclang = lib.getLib llvmPackages.libclang;
206 })
207
208 ./ignore-etc-os-release.patch
209 ./dont-yarn-install.patch
210 ./fix-darwin.patch
211 ./bump-node-abi.patch
212 ];
213
214 postPatch = ''
215 # fix .desktop Exec field
216 substituteInPlace src/node/desktop/resources/freedesktop/rstudio.desktop.in \
217 --replace-fail "\''${CMAKE_INSTALL_PREFIX}/rstudio" "rstudio"
218
219 # set install path of freedesktop files
220 substituteInPlace src/node/desktop/CMakeLists.txt \
221 --replace-fail "/usr/share" "$out/share"
222 '';
223
224 yarnOfflineCache = fetchYarnDeps {
225 src = quartoSrc;
226 hash = "sha256-F+gqVNNhLmyrC+tJuElw7cpx5z/WLHOiYow/y86KR5c=";
227 };
228
229 dontYarnInstallDeps = true; # will call manually in preConfigure
230
231 npmRoot = "src/node/desktop";
232
233 # don't build native modules with node headers
234 npmFlags = [ "--ignore-scripts" ];
235
236 makeCacheWritable = true;
237
238 npmDeps = fetchNpmDeps {
239 name = "rstudio-${version}-npm-deps";
240 inherit src;
241 postPatch = "cd ${npmRoot}";
242 patches = [
243 # needed for support for electron versions above electron_34
244 ./bump-node-abi.patch
245 ];
246 hash = "sha256-64PJPUE/xwdQdxVGiKzy8ADnxXH/qGQtFMib0unZpoA=";
247 };
248
249 preConfigure = ''
250 # populate the directories used by cmake's FetchContent
251 mkdir -p build/_deps
252 cp -r "$extSrcs"/* build/_deps
253 chmod -R u+w build/_deps
254
255 # set up node_modules directory inside quarto so that panmirror can be built
256 mkdir src/gwt/lib/quarto
257 cp -r --no-preserve=all ${quartoSrc}/* src/gwt/lib/quarto
258 pushd src/gwt/lib/quarto
259 yarnConfigHook
260 popd
261
262 ### set up dependencies that will be copied into the result
263 # note: only the directory names have to match upstream, the actual versions don't
264 # note: symlinks are preserved
265
266 mkdir dependencies/dictionaries
267 for dict in ${builtins.concatStringsSep " " dictionaries}; do
268 for i in "$dict/share/hunspell/"*; do
269 ln -s $i dependencies/dictionaries/
270 done
271 done
272
273 ln -s ${quartoWrapper} dependencies/quarto
274
275 # version in dependencies/common/install-mathjax
276 ln -s ${mathJaxSrc} dependencies/mathjax-27
277
278 mkdir -p dependencies/common/node
279 # node used by cmake
280 # version in cmake/globals.cmake (RSTUDIO_NODE_VERSION)
281 ln -s ${nodejs} dependencies/common/node/22.13.1
282
283 ''
284 + lib.optionalString (!server) ''
285 pushd $npmRoot
286
287 substituteInPlace package.json \
288 --replace-fail "npm ci && " ""
289
290 # use electron's headers to make node-gyp compile against the electron ABI
291 export npm_config_nodedir="${electron.headers}"
292
293 ### override the detected electron version
294 substituteInPlace node_modules/@electron-forge/core-utils/dist/electron-version.js \
295 --replace-fail "return version" "return '${electron.version}'"
296
297 ### create the electron archive to be used by electron-packager
298 cp -r ${electron.dist} electron-dist
299 chmod -R u+w electron-dist
300
301 pushd electron-dist
302 zip -0Xqr ../electron.zip .
303 popd
304
305 rm -r electron-dist
306
307 # force @electron/packager to use our electron instead of downloading it
308 substituteInPlace node_modules/@electron/packager/dist/packager.js \
309 --replace-fail "await this.getElectronZipPath(downloadOpts)" "'$(pwd)/electron.zip'"
310
311 # Work around known nan issue for electron_33 and above
312 # https://github.com/nodejs/nan/issues/978
313 substituteInPlace node_modules/nan/nan.h \
314 --replace-fail '#include "nan_scriptorigin.h"' ""
315
316 # now that we patched everything, we still have to run the scripts we ignored with --ignore-scripts
317 npm rebuild
318
319 popd
320 '';
321
322 postInstall = ''
323 mkdir -p $out/bin
324 ''
325 + lib.optionalString (server && stdenv.hostPlatform.isLinux) ''
326 ln -s $out/lib/rstudio/bin/{crash-handler-proxy,postback,r-ldpath,rpostback,rserver,rserver-pam,rsession,rstudio-server} $out/bin
327 ''
328 + lib.optionalString (!server && stdenv.hostPlatform.isLinux) ''
329 # remove unneeded electron files, since we'll wrap the app with our own electron
330 shopt -s extglob
331 rm -r $out/lib/rstudio/!(locales|resources|resources.pak)
332
333 makeWrapper ${lib.getExe electron} "$out/bin/rstudio" \
334 --add-flags "$out/lib/rstudio/resources/app/" \
335 --set-default ELECTRON_FORCE_IS_PACKAGED 1 \
336 --suffix PATH : ${lib.makeBinPath [ gnumake ]}
337
338 ln -s $out/lib/rstudio/resources/app/bin/{diagnostics,rpostback} $out/bin
339 ''
340 + lib.optionalString (server && stdenv.hostPlatform.isDarwin) ''
341 ln -s $out/Applications/RStudio.app/Contents/MacOS/{crash-handler-proxy,postback,r-ldpath,rpostback,rserver,rserver-pam,rsession,rstudio-server} $out/bin
342 ''
343 + lib.optionalString (!server && stdenv.hostPlatform.isDarwin) ''
344 # electron can't find its files if we use a symlink here
345 makeWrapper $out/Applications/RStudio.app/Contents/MacOS/RStudio $out/bin/rstudio
346
347 ln -s $out/Applications/RStudio.app/Contents/Resources/app/bin/{diagnostics,rpostback} $out/bin
348 '';
349
350 passthru = {
351 inherit server;
352 tests = lib.optionalAttrs stdenv.hostPlatform.isLinux {
353 inherit (nixosTests) rstudio-server;
354 };
355 };
356
357 meta = {
358 changelog = "https://github.com/rstudio/rstudio/tree/${src.rev}/version/news";
359 description = "Set of integrated tools for the R language";
360 homepage = "https://www.rstudio.com/";
361 license = lib.licenses.agpl3Only;
362 maintainers = with lib.maintainers; [
363 ciil
364 cfhammill
365 tomasajt
366 ];
367 mainProgram = "rstudio" + lib.optionalString server "-server";
368 # rstudio-server on darwin is only partially supported by upstream
369 platforms = lib.platforms.linux ++ lib.optionals (!server) lib.platforms.darwin;
370 };
371}