1{ stdenv, buildPackages, lib
2, fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub
3, zlib, openssl, gdbm, ncurses, readline, groff, libyaml, libffi, jemalloc, autoreconfHook, bison
4, autoconf, libiconv, libobjc, libunwind, Foundation
5, buildEnv, bundler, bundix
6, makeWrapper, buildRubyGem, defaultGemConfig, removeReferencesTo
7} @ args:
8
9let
10 op = lib.optional;
11 ops = lib.optionals;
12 opString = lib.optionalString;
13 patchSet = import ./rvm-patchsets.nix { inherit fetchFromGitHub; };
14 config = import ./config.nix { inherit fetchFromSavannah; };
15 rubygems = import ./rubygems { inherit stdenv lib fetchurl; };
16
17 # Contains the ruby version heuristics
18 rubyVersion = import ./ruby-version.nix { inherit lib; };
19
20 # Needed during postInstall
21 buildRuby =
22 if stdenv.hostPlatform == stdenv.buildPlatform
23 then "$out/bin/ruby"
24 else "${buildPackages.ruby}/bin/ruby";
25
26 generic = { version, sha256 }: let
27 ver = version;
28 tag = ver.gitTag;
29 atLeast30 = lib.versionAtLeast ver.majMin "3.0";
30 baseruby = self.override {
31 useRailsExpress = false;
32 docSupport = false;
33 rubygemsSupport = false;
34 };
35 self = lib.makeOverridable (
36 { stdenv, buildPackages, lib
37 , fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub
38 , useRailsExpress ? true
39 , rubygemsSupport ? true
40 , zlib, zlibSupport ? true
41 , openssl, opensslSupport ? true
42 , gdbm, gdbmSupport ? true
43 , ncurses, readline, cursesSupport ? true
44 , groff, docSupport ? true
45 , libyaml, yamlSupport ? true
46 , libffi, fiddleSupport ? true
47 , jemalloc, jemallocSupport ? false
48 # By default, ruby has 3 observed references to stdenv.cc:
49 #
50 # - If you run:
51 # ruby -e "puts RbConfig::CONFIG['configure_args']"
52 # - In:
53 # $out/${passthru.libPath}/${stdenv.hostPlatform.system}/rbconfig.rb
54 # Or (usually):
55 # $(nix-build -A ruby)/lib/ruby/2.6.0/x86_64-linux/rbconfig.rb
56 # - In $out/lib/libruby.so and/or $out/lib/libruby.dylib
57 , removeReferencesTo, jitSupport ? false
58 , autoreconfHook, bison, autoconf
59 , buildEnv, bundler, bundix
60 , libiconv, libobjc, libunwind, Foundation
61 , makeWrapper, buildRubyGem, defaultGemConfig
62 }:
63 stdenv.mkDerivation rec {
64 pname = "ruby";
65 inherit version;
66
67 src = if useRailsExpress then fetchFromGitHub {
68 owner = "ruby";
69 repo = "ruby";
70 rev = tag;
71 sha256 = sha256.git;
72 } else fetchurl {
73 url = "https://cache.ruby-lang.org/pub/ruby/${ver.majMin}/ruby-${ver}.tar.gz";
74 sha256 = sha256.src;
75 };
76
77 # Have `configure' avoid `/usr/bin/nroff' in non-chroot builds.
78 NROFF = if docSupport then "${groff}/bin/nroff" else null;
79
80 outputs = [ "out" ] ++ lib.optional docSupport "devdoc";
81
82 nativeBuildInputs = [ autoreconfHook bison ]
83 ++ (op docSupport groff)
84 ++ op (stdenv.buildPlatform != stdenv.hostPlatform) buildPackages.ruby;
85 buildInputs = [ autoconf ]
86 ++ (op fiddleSupport libffi)
87 ++ (ops cursesSupport [ ncurses readline ])
88 ++ (op zlibSupport zlib)
89 ++ (op opensslSupport openssl)
90 ++ (op gdbmSupport gdbm)
91 ++ (op yamlSupport libyaml)
92 ++ (op jemallocSupport jemalloc)
93 # Looks like ruby fails to build on darwin without readline even if curses
94 # support is not enabled, so add readline to the build inputs if curses
95 # support is disabled (if it's enabled, we already have it) and we're
96 # running on darwin
97 ++ op (!cursesSupport && stdenv.isDarwin) readline
98 ++ ops stdenv.isDarwin [ libiconv libobjc libunwind Foundation ];
99
100 enableParallelBuilding = true;
101
102 patches =
103 (import ./patchsets.nix {
104 inherit patchSet useRailsExpress ops fetchpatch;
105 patchLevel = ver.patchLevel;
106 }).${ver.majMinTiny}
107 ++ [ ./do-not-regenerate-revision.h.patch ]
108 ++ op (atLeast30 && useRailsExpress) ./do-not-update-gems-baseruby.patch
109 # Ruby prior to 3.0 has a bug the installer (tools/rbinstall.rb) but
110 # the resulting error was swallowed. Newer rubygems no longer swallows
111 # this error. We upgrade rubygems when rubygemsSupport is enabled, so
112 # we have to fix this bug to prevent the install step from failing.
113 # See https://github.com/ruby/ruby/pull/2930
114 ++ op (!atLeast30 && rubygemsSupport)
115 (fetchpatch {
116 url = "https://github.com/ruby/ruby/commit/261d8dd20afd26feb05f00a560abd99227269c1c.patch";
117 sha256 = "0wrii25cxcz2v8bgkrf7ibcanjlxwclzhayin578bf0qydxdm9qy";
118 });
119
120 postUnpack = opString rubygemsSupport ''
121 rm -rf $sourceRoot/{lib,test}/rubygems*
122 cp -r ${rubygems}/lib/rubygems* $sourceRoot/lib
123 cp -r ${rubygems}/test/rubygems $sourceRoot/test
124 '';
125
126 postPatch = ''
127 sed -i configure.ac -e '/config.guess/d'
128 cp --remove-destination ${config}/config.guess tool/
129 cp --remove-destination ${config}/config.sub tool/
130 '' + opString (!atLeast30) ''
131 # Make the build reproducible for ruby <= 2.7
132 # See https://github.com/ruby/io-console/commit/679a941d05d869f5e575730f6581c027203b7b26#diff-d8422f096931c58d4463e2489f62a228b0f24f0492950ba88c8c89a0d741cfe6
133 sed -i ext/io/console/io-console.gemspec -e '/s\.date/d'
134 '';
135
136 configureFlags = ["--enable-shared" "--enable-pthread" "--with-soname=ruby-${version}"]
137 ++ op useRailsExpress "--with-baseruby=${baseruby}/bin/ruby"
138 ++ op (!jitSupport) "--disable-jit-support"
139 ++ op (!docSupport) "--disable-install-doc"
140 ++ op (jemallocSupport) "--with-jemalloc"
141 ++ ops stdenv.isDarwin [
142 # on darwin, we have /usr/include/tk.h -- so the configure script detects
143 # that tk is installed
144 "--with-out-ext=tk"
145 # on yosemite, "generating encdb.h" will hang for a very long time without this flag
146 "--with-setjmp-type=setjmp"
147 ]
148 ++ op (stdenv.hostPlatform != stdenv.buildPlatform)
149 "--with-baseruby=${buildRuby}";
150
151 preConfigure = opString docSupport ''
152 configureFlagsArray+=("--with-ridir=$devdoc/share/ri")
153
154 # rdoc creates XDG_DATA_DIR (defaulting to $HOME/.local/share) even if
155 # it's not going to be used.
156 export HOME=$TMPDIR
157 '';
158
159 # fails with "16993 tests, 2229489 assertions, 105 failures, 14 errors, 89 skips"
160 # mostly TZ- and patch-related tests
161 # TZ- failures are caused by nix sandboxing, I didn't investigate others
162 doCheck = false;
163
164 preInstall = ''
165 # Ruby installs gems here itself now.
166 mkdir -pv "$out/${passthru.gemPath}"
167 export GEM_HOME="$out/${passthru.gemPath}"
168 '';
169
170 installFlags = lib.optional docSupport "install-doc";
171 # Bundler tries to create this directory
172 postInstall = ''
173 rbConfig=$(find $out/lib/ruby -name rbconfig.rb)
174 # Remove unnecessary groff reference from runtime closure, since it's big
175 sed -i '/NROFF/d' $rbConfig
176 ${
177 lib.optionalString (!jitSupport) ''
178 # Get rid of the CC runtime dependency
179 ${removeReferencesTo}/bin/remove-references-to \
180 -t ${stdenv.cc} \
181 $out/lib/libruby*
182 ${removeReferencesTo}/bin/remove-references-to \
183 -t ${stdenv.cc} \
184 $rbConfig
185 sed -i '/CC_VERSION_MESSAGE/d' $rbConfig
186 ''
187 }
188 # Bundler tries to create this directory
189 mkdir -p $out/nix-support
190 cat > $out/nix-support/setup-hook <<EOF
191 addGemPath() {
192 addToSearchPath GEM_PATH \$1/${passthru.gemPath}
193 }
194 addRubyLibPath() {
195 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby
196 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}
197 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}/${stdenv.hostPlatform.system}
198 }
199
200 addEnvHooks "$hostOffset" addGemPath
201 addEnvHooks "$hostOffset" addRubyLibPath
202 EOF
203 '' + opString docSupport ''
204 # Prevent the docs from being included in the closure
205 sed -i "s|\$(DESTDIR)$devdoc|\$(datarootdir)/\$(RI_BASE_NAME)|" $rbConfig
206 sed -i "s|'--with-ridir=$devdoc/share/ri'||" $rbConfig
207
208 # Add rbconfig shim so ri can find docs
209 mkdir -p $devdoc/lib/ruby/site_ruby
210 cp ${./rbconfig.rb} $devdoc/lib/ruby/site_ruby/rbconfig.rb
211 '' + opString useRailsExpress ''
212 # Prevent the baseruby from being included in the closure.
213 sed -i '/^ CONFIG\["BASERUBY"\]/d' $rbConfig
214 sed -i "s|'--with-baseruby=${baseruby}/bin/ruby'||" $rbConfig
215 '';
216
217 disallowedRequisites = op (!jitSupport) stdenv.cc.cc;
218
219 meta = with lib; {
220 description = "The Ruby language";
221 homepage = "http://www.ruby-lang.org/en/";
222 license = licenses.ruby;
223 maintainers = with maintainers; [ vrthra manveru marsam ];
224 platforms = platforms.all;
225 };
226
227 passthru = rec {
228 version = ver;
229 rubyEngine = "ruby";
230 baseRuby = baseruby;
231 libPath = "lib/${rubyEngine}/${ver.libDir}";
232 gemPath = "lib/${rubyEngine}/gems/${ver.libDir}";
233 devEnv = import ./dev.nix {
234 inherit buildEnv bundler bundix;
235 ruby = self;
236 };
237
238 inherit (import ../../ruby-modules/with-packages {
239 inherit lib stdenv makeWrapper buildRubyGem buildEnv;
240 gemConfig = defaultGemConfig;
241 ruby = self;
242 }) withPackages gems;
243
244 # deprecated 2016-09-21
245 majorVersion = ver.major;
246 minorVersion = ver.minor;
247 teenyVersion = ver.tiny;
248 patchLevel = ver.patchLevel;
249 };
250 }
251 ) args; in self;
252
253in {
254 ruby_2_7 = generic {
255 version = rubyVersion "2" "7" "4" "";
256 sha256 = {
257 src = "0nxwkxh7snmjqf787qsp4i33mxd1rbf9yzyfiky5k230i680jhrh";
258 git = "1prsrqwkla4k5japlm54k0j700j4824rg8z8kpswr9r3swrmrf5p";
259 };
260 };
261
262 ruby_3_0 = generic {
263 version = rubyVersion "3" "0" "2" "";
264 sha256 = {
265 src = "1wg6yyzc6arzikcy48igqbxfcdc79bmfpiyfi9m9j1lzmphdx1ah";
266 git = "1kbkxqichi11vli080jgyvjf2xgnlbl9l2f2n1hv4s8b31gjib3r";
267 };
268 };
269}