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