1{ stdenv, buildPackages, lib
2, fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub
3, zlib, openssl, gdbm, ncurses, readline, groff, libyaml, libffi, 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 fetchpatch; };
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 atLeast27 = lib.versionAtLeast ver.majMin "2.7";
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 # ruby -e "puts RbConfig::CONFIG['configure_args']"
48 # puts a reference to the C compiler in the binary.
49 # This might be required by some gems at runtime,
50 # but we allow to strip it out for smaller closure size.
51 , removeReferencesTo, removeReferenceToCC ? true
52 , autoreconfHook, bison, autoconf
53 , buildEnv, bundler, bundix
54 , libiconv, libobjc, libunwind, Foundation
55 , makeWrapper, buildRubyGem, defaultGemConfig
56 }:
57 stdenv.mkDerivation rec {
58 pname = "ruby";
59 inherit version;
60
61 src = if useRailsExpress then fetchFromGitHub {
62 owner = "ruby";
63 repo = "ruby";
64 rev = tag;
65 sha256 = sha256.git;
66 } else fetchurl {
67 url = "https://cache.ruby-lang.org/pub/ruby/${ver.majMin}/ruby-${ver}.tar.gz";
68 sha256 = sha256.src;
69 };
70
71 # Have `configure' avoid `/usr/bin/nroff' in non-chroot builds.
72 NROFF = if docSupport then "${groff}/bin/nroff" else null;
73
74 outputs = [ "out" ] ++ lib.optional docSupport "devdoc";
75
76 nativeBuildInputs = [ autoreconfHook bison ]
77 ++ (op docSupport groff)
78 ++ op (stdenv.buildPlatform != stdenv.hostPlatform) buildPackages.ruby;
79 buildInputs = [ autoconf ]
80 ++ (op fiddleSupport libffi)
81 ++ (ops cursesSupport [ ncurses readline ])
82 ++ (op zlibSupport zlib)
83 ++ (op opensslSupport openssl)
84 ++ (op gdbmSupport gdbm)
85 ++ (op yamlSupport libyaml)
86 # Looks like ruby fails to build on darwin without readline even if curses
87 # support is not enabled, so add readline to the build inputs if curses
88 # support is disabled (if it's enabled, we already have it) and we're
89 # running on darwin
90 ++ op (!cursesSupport && stdenv.isDarwin) readline
91 ++ ops stdenv.isDarwin [ libiconv libobjc libunwind Foundation ];
92
93 enableParallelBuilding = true;
94
95 patches =
96 (import ./patchsets.nix {
97 inherit patchSet useRailsExpress ops fetchpatch;
98 patchLevel = ver.patchLevel;
99 }).${ver.majMinTiny};
100
101 postUnpack = opString rubygemsSupport ''
102 rm -rf $sourceRoot/{lib,test}/rubygems*
103 cp -r ${rubygems}/lib/rubygems* $sourceRoot/lib
104 cp -r ${rubygems}/test/rubygems $sourceRoot/test
105 '';
106
107 postPatch = ''
108 sed -i configure.ac -e '/config.guess/d'
109 cp --remove-destination ${config}/config.guess tool/
110 cp --remove-destination ${config}/config.sub tool/
111 '';
112
113 # Force the revision.h generation. Somehow `revision.tmp` is an empty
114 # file and because we don't add `git` to buildInputs, hence the check is
115 # always true.
116 # https://github.com/ruby/ruby/commit/97a5af62a318fcd93a4e5e4428d576c0280ddbae
117 buildFlags = lib.optionals atLeast27 [ "REVISION_LATEST=0" ];
118
119 configureFlags = ["--enable-shared" "--enable-pthread" "--with-soname=ruby_${tag}"]
120 ++ op useRailsExpress "--with-baseruby=${baseruby}/bin/ruby"
121 ++ op (!docSupport) "--disable-install-doc"
122 ++ ops stdenv.isDarwin [
123 # on darwin, we have /usr/include/tk.h -- so the configure script detects
124 # that tk is installed
125 "--with-out-ext=tk"
126 # on yosemite, "generating encdb.h" will hang for a very long time without this flag
127 "--with-setjmp-type=setjmp"
128 ]
129 ++ op (stdenv.hostPlatform != stdenv.buildPlatform)
130 "--with-baseruby=${buildRuby}";
131
132 preConfigure = opString docSupport ''
133 configureFlagsArray+=("--with-ridir=$devdoc/share/ri")
134 '';
135
136 # fails with "16993 tests, 2229489 assertions, 105 failures, 14 errors, 89 skips"
137 # mostly TZ- and patch-related tests
138 # TZ- failures are caused by nix sandboxing, I didn't investigate others
139 doCheck = false;
140
141 preInstall = ''
142 # Ruby installs gems here itself now.
143 mkdir -pv "$out/${passthru.gemPath}"
144 export GEM_HOME="$out/${passthru.gemPath}"
145 '';
146
147 installFlags = stdenv.lib.optional docSupport "install-doc";
148 # Bundler tries to create this directory
149 postInstall = ''
150 # Remove unnecessary groff reference from runtime closure, since it's big
151 sed -i '/NROFF/d' $out/lib/ruby/*/*/rbconfig.rb
152 ${
153 lib.optionalString removeReferenceToCC ''
154 # Get rid of the CC runtime dependency
155 ${removeReferencesTo}/bin/remove-references-to \
156 -t ${stdenv.cc} \
157 $out/lib/libruby*
158 ''
159 }
160 # Bundler tries to create this directory
161 mkdir -p $out/nix-support
162 cat > $out/nix-support/setup-hook <<EOF
163 addGemPath() {
164 addToSearchPath GEM_PATH \$1/${passthru.gemPath}
165 }
166 addRubyLibPath() {
167 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby
168 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}
169 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}/${stdenv.targetPlatform.system}
170 }
171
172 addEnvHooks "$hostOffset" addGemPath
173 addEnvHooks "$hostOffset" addRubyLibPath
174 EOF
175
176 rbConfig=$(find $out/lib/ruby -name rbconfig.rb)
177 '' + opString docSupport ''
178 # Prevent the docs from being included in the closure
179 sed -i "s|\$(DESTDIR)$devdoc|\$(datarootdir)/\$(RI_BASE_NAME)|" $rbConfig
180 sed -i "s|'--with-ridir=$devdoc/share/ri'||" $rbConfig
181
182 # Add rbconfig shim so ri can find docs
183 mkdir -p $devdoc/lib/ruby/site_ruby
184 cp ${./rbconfig.rb} $devdoc/lib/ruby/site_ruby/rbconfig.rb
185 '' + opString useRailsExpress ''
186 # Prevent the baseruby from being included in the closure.
187 sed -i '/^ CONFIG\["BASERUBY"\]/d' $rbConfig
188 sed -i "s|'--with-baseruby=${baseruby}/bin/ruby'||" $rbConfig
189 '';
190
191 meta = with stdenv.lib; {
192 description = "The Ruby language";
193 homepage = http://www.ruby-lang.org/en/;
194 license = licenses.ruby;
195 maintainers = with maintainers; [ vrthra manveru ];
196 platforms = platforms.all;
197 };
198
199 passthru = rec {
200 version = ver;
201 rubyEngine = "ruby";
202 baseRuby = baseruby;
203 libPath = "lib/${rubyEngine}/${ver.libDir}";
204 gemPath = "lib/${rubyEngine}/gems/${ver.libDir}";
205 devEnv = import ./dev.nix {
206 inherit buildEnv bundler bundix;
207 ruby = self;
208 };
209
210 inherit (import ../../ruby-modules/with-packages {
211 inherit lib stdenv makeWrapper buildRubyGem buildEnv;
212 gemConfig = defaultGemConfig;
213 ruby = self;
214 }) withPackages gems;
215
216 # deprecated 2016-09-21
217 majorVersion = ver.major;
218 minorVersion = ver.minor;
219 teenyVersion = ver.tiny;
220 patchLevel = ver.patchLevel;
221 };
222 }
223 ) args; in self;
224
225in {
226 ruby_2_5 = generic {
227 version = rubyVersion "2" "5" "8" "";
228 sha256 = {
229 src = "16md4jspjwixjlbhx3pnd5iwpca07p23ghkxkqd82sbchw3xy2vc";
230 git = "19gkk3q9l33cwkfsp5k8f8fipq7gkyqkqirm9farbvy425519rv2";
231 };
232 };
233
234 ruby_2_6 = generic {
235 version = rubyVersion "2" "6" "6" "";
236 sha256 = {
237 src = "1492x795qzgp3zhpl580kd1sdp50n5hfsmpbfhdsq2rnxwyi8jrn";
238 git = "1jr9v99a7awssqmw7531afbx4a8i9x5yfqyffha545g7r4s7kj50";
239 };
240 };
241
242 ruby_2_7 = generic {
243 version = rubyVersion "2" "7" "1" "";
244 sha256 = {
245 src = "0674x98f542y02r7n2yv2qhmh97blqhi2mvh2dn5f000vlxlh66l";
246 git = "0qk729kr5wm67xmwpljpdprwhp5wvn5y4ikqy00p1zcgwlwdcs33";
247 };
248 };
249}