at 24.05-pre 15 kB view raw
1{ stdenv, buildPackages, lib 2, fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub 3, zlib, gdbm, ncurses, readline, groff, libyaml, libffi, jemalloc, autoreconfHook, bison 4, autoconf, libiconv, libobjc, libunwind, Foundation 5, buildEnv, bundler, bundix, cargo, rustPlatform, rustc 6, makeBinaryWrapper, buildRubyGem, defaultGemConfig, removeReferencesTo 7, openssl, openssl_1_1 8, linuxPackages, libsystemtap 9} @ args: 10 11let 12 op = lib.optional; 13 ops = lib.optionals; 14 opString = lib.optionalString; 15 config = import ./config.nix { inherit fetchFromSavannah; }; 16 rubygems = import ./rubygems { inherit stdenv lib fetchurl; }; 17 18 # Contains the ruby version heuristics 19 rubyVersion = import ./ruby-version.nix { inherit lib; }; 20 21 generic = { version, sha256, cargoSha256 ? null }: let 22 ver = version; 23 atLeast30 = lib.versionAtLeast ver.majMin "3.0"; 24 atLeast31 = lib.versionAtLeast ver.majMin "3.1"; 25 atLeast32 = lib.versionAtLeast ver.majMin "3.2"; 26 # https://github.com/ruby/ruby/blob/v3_2_2/yjit.h#L21 27 yjitSupported = atLeast32 && (stdenv.hostPlatform.isx86_64 || (!stdenv.hostPlatform.isWindows && stdenv.hostPlatform.isAarch64)); 28 self = lib.makeOverridable ( 29 { stdenv, buildPackages, lib 30 , fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub 31 , rubygemsSupport ? true 32 , zlib, zlibSupport ? true 33 , openssl, openssl_1_1, opensslSupport ? true 34 , gdbm, gdbmSupport ? true 35 , ncurses, readline, cursesSupport ? true 36 , groff, docSupport ? true 37 , libyaml, yamlSupport ? true 38 , libffi, fiddleSupport ? true 39 , jemalloc, jemallocSupport ? false 40 , linuxPackages, systemtap ? linuxPackages.systemtap, libsystemtap, dtraceSupport ? false 41 # By default, ruby has 3 observed references to stdenv.cc: 42 # 43 # - If you run: 44 # ruby -e "puts RbConfig::CONFIG['configure_args']" 45 # - In: 46 # $out/${passthru.libPath}/${stdenv.hostPlatform.system}/rbconfig.rb 47 # Or (usually): 48 # $(nix-build -A ruby)/lib/ruby/2.6.0/x86_64-linux/rbconfig.rb 49 # - In $out/lib/libruby.so and/or $out/lib/libruby.dylib 50 , removeReferencesTo, jitSupport ? yjitSupport 51 , cargo, rustPlatform, rustc, yjitSupport ? yjitSupported 52 , autoreconfHook, bison, autoconf 53 , buildEnv, bundler, bundix 54 , libiconv, libobjc, libunwind, Foundation 55 , makeBinaryWrapper, buildRubyGem, defaultGemConfig 56 , baseRuby ? buildPackages.ruby.override { 57 docSupport = false; 58 rubygemsSupport = false; 59 } 60 , useBaseRuby ? stdenv.hostPlatform != stdenv.buildPlatform 61 }: 62 stdenv.mkDerivation rec { 63 pname = "ruby"; 64 inherit version; 65 66 src = fetchurl { 67 url = "https://cache.ruby-lang.org/pub/ruby/${ver.majMin}/ruby-${ver}.tar.gz"; 68 inherit sha256; 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 strictDeps = true; 77 78 nativeBuildInputs = [ autoreconfHook bison ] 79 ++ (op docSupport groff) 80 ++ (ops (dtraceSupport && stdenv.isLinux) [ systemtap libsystemtap ]) 81 ++ ops yjitSupport [ rustPlatform.cargoSetupHook cargo rustc ] 82 ++ op useBaseRuby baseRuby; 83 buildInputs = [ autoconf ] 84 ++ (op fiddleSupport libffi) 85 ++ (ops cursesSupport [ ncurses readline ]) 86 ++ (op zlibSupport zlib) 87 ++ (op (atLeast30 && opensslSupport) openssl) 88 ++ (op (!atLeast30 && opensslSupport) openssl_1_1) 89 ++ (op gdbmSupport gdbm) 90 ++ (op yamlSupport libyaml) 91 # Looks like ruby fails to build on darwin without readline even if curses 92 # support is not enabled, so add readline to the build inputs if curses 93 # support is disabled (if it's enabled, we already have it) and we're 94 # running on darwin 95 ++ op (!cursesSupport && stdenv.isDarwin) readline 96 ++ ops stdenv.isDarwin [ libiconv libobjc libunwind Foundation ]; 97 propagatedBuildInputs = op jemallocSupport jemalloc; 98 99 enableParallelBuilding = true; 100 # /build/ruby-2.7.7/lib/fileutils.rb:882:in `chmod': 101 # No such file or directory @ apply2files - ...-ruby-2.7.7-devdoc/share/ri/2.7.0/system/ARGF/inspect-i.ri (Errno::ENOENT) 102 # make: *** [uncommon.mk:373: do-install-all] Error 1 103 enableParallelInstalling = false; 104 105 patches = op (lib.versionOlder ver.majMin "3.1") ./do-not-regenerate-revision.h.patch 106 ++ op (atLeast30 && useBaseRuby) ( 107 if atLeast32 then ./do-not-update-gems-baseruby-3.2.patch 108 else ./do-not-update-gems-baseruby.patch 109 ) 110 ++ ops (ver.majMin == "3.0") [ 111 # Ruby 3.0 adds `-fdeclspec` to $CC instead of $CFLAGS. Fixed in later versions. 112 (fetchpatch { 113 url = "https://github.com/ruby/ruby/commit/0acc05caf7518cd0d63ab02bfa036455add02346.patch"; 114 sha256 = "sha256-43hI9L6bXfeujgmgKFVmiWhg7OXvshPCCtQ4TxqK1zk="; 115 }) 116 ] 117 ++ ops (!atLeast30 && rubygemsSupport) [ 118 # We upgrade rubygems to a version that isn't compatible with the 119 # ruby 2.7 installer. Backport the upstream fix. 120 ./rbinstall-new-rubygems-compat.patch 121 122 # Ruby prior to 3.0 has a bug the installer (tools/rbinstall.rb) but 123 # the resulting error was swallowed. Newer rubygems no longer swallows 124 # this error. We upgrade rubygems when rubygemsSupport is enabled, so 125 # we have to fix this bug to prevent the install step from failing. 126 # See https://github.com/ruby/ruby/pull/2930 127 (fetchpatch { 128 url = "https://github.com/ruby/ruby/commit/261d8dd20afd26feb05f00a560abd99227269c1c.patch"; 129 sha256 = "0wrii25cxcz2v8bgkrf7ibcanjlxwclzhayin578bf0qydxdm9qy"; 130 }) 131 ] 132 ++ ops atLeast31 [ 133 # When using a baseruby, ruby always sets "libdir" to the build 134 # directory, which nix rejects due to a reference in to /build/ in 135 # the final product. Removing this reference doesn't seem to break 136 # anything and fixes cross compliation. 137 ./dont-refer-to-build-dir.patch 138 ]; 139 140 cargoRoot = opString yjitSupport "yjit"; 141 142 cargoDeps = if yjitSupport then rustPlatform.fetchCargoTarball { 143 inherit src; 144 sourceRoot = "${pname}-${version}/${cargoRoot}"; 145 sha256 = cargoSha256; 146 } else null; 147 148 postUnpack = opString rubygemsSupport '' 149 rm -rf $sourceRoot/{lib,test}/rubygems* 150 cp -r ${rubygems}/lib/rubygems* $sourceRoot/lib 151 cp -r ${rubygems}/test/rubygems $sourceRoot/test 152 ''; 153 154 postPatch = '' 155 sed -i configure.ac -e '/config.guess/d' 156 cp --remove-destination ${config}/config.guess tool/ 157 cp --remove-destination ${config}/config.sub tool/ 158 '' + opString (!atLeast30) '' 159 # Make the build reproducible for ruby <= 2.7 160 # See https://github.com/ruby/io-console/commit/679a941d05d869f5e575730f6581c027203b7b26#diff-d8422f096931c58d4463e2489f62a228b0f24f0492950ba88c8c89a0d741cfe6 161 sed -i ext/io/console/io-console.gemspec -e '/s\.date/d' 162 ''; 163 164 configureFlags = [ 165 (lib.enableFeature (!stdenv.hostPlatform.isStatic) "shared") 166 (lib.enableFeature true "pthread") 167 (lib.withFeatureAs true "soname" "ruby-${version}") 168 (lib.withFeatureAs useBaseRuby "baseruby" "${baseRuby}/bin/ruby") 169 (lib.enableFeature dtraceSupport "dtrace") 170 (lib.enableFeature jitSupport "jit-support") 171 (lib.enableFeature yjitSupport "yjit") 172 (lib.enableFeature docSupport "install-doc") 173 (lib.withFeature jemallocSupport "jemalloc") 174 (lib.withFeatureAs docSupport "ridir" "${placeholder "devdoc"}/share/ri") 175 # ruby enables -O3 for gcc, however our compiler hardening wrapper 176 # overrides that by enabling `-O2` which is the minimum optimization 177 # needed for `_FORTIFY_SOURCE`. 178 ] ++ lib.optional stdenv.cc.isGNU "CFLAGS=-O3" ++ [ 179 ] ++ ops stdenv.isDarwin [ 180 # on darwin, we have /usr/include/tk.h -- so the configure script detects 181 # that tk is installed 182 "--with-out-ext=tk" 183 # on yosemite, "generating encdb.h" will hang for a very long time without this flag 184 "--with-setjmp-type=setjmp" 185 ]; 186 187 preConfigure = opString docSupport '' 188 # rdoc creates XDG_DATA_DIR (defaulting to $HOME/.local/share) even if 189 # it's not going to be used. 190 export HOME=$TMPDIR 191 ''; 192 193 # fails with "16993 tests, 2229489 assertions, 105 failures, 14 errors, 89 skips" 194 # mostly TZ- and patch-related tests 195 # TZ- failures are caused by nix sandboxing, I didn't investigate others 196 doCheck = false; 197 198 preInstall = '' 199 # Ruby installs gems here itself now. 200 mkdir -pv "$out/${passthru.gemPath}" 201 export GEM_HOME="$out/${passthru.gemPath}" 202 ''; 203 204 installFlags = lib.optional docSupport "install-doc"; 205 # Bundler tries to create this directory 206 postInstall = '' 207 rbConfig=$(find $out/lib/ruby -name rbconfig.rb) 208 # Remove references to the build environment from the closure 209 sed -i '/^ CONFIG\["\(BASERUBY\|SHELL\|GREP\|EGREP\|MKDIR_P\|MAKEDIRS\|INSTALL\)"\]/d' $rbConfig 210 # Remove unnecessary groff reference from runtime closure, since it's big 211 sed -i '/NROFF/d' $rbConfig 212 ${ 213 lib.optionalString (!jitSupport) '' 214 # Get rid of the CC runtime dependency 215 ${removeReferencesTo}/bin/remove-references-to \ 216 -t ${stdenv.cc} \ 217 $out/lib/libruby* 218 ${removeReferencesTo}/bin/remove-references-to \ 219 -t ${stdenv.cc} \ 220 $rbConfig 221 sed -i '/CC_VERSION_MESSAGE/d' $rbConfig 222 '' 223 } 224 225 # Allow to override compiler. This is important for cross compiling as 226 # we need to set a compiler that is different from the build one. 227 sed -i 's/CONFIG\["CC"\] = "\(.*\)"/CONFIG["CC"] = if ENV["CC"].nil? || ENV["CC"].empty? then "\1" else ENV["CC"] end/' "$rbConfig" 228 229 # Remove unnecessary external intermediate files created by gems 230 extMakefiles=$(find $out/${passthru.gemPath} -name Makefile) 231 for makefile in $extMakefiles; do 232 make -C "$(dirname "$makefile")" distclean 233 done 234 find "$out/${passthru.gemPath}" \( -name gem_make.out -o -name mkmf.log \) -delete 235 # Bundler tries to create this directory 236 mkdir -p $out/nix-support 237 cat > $out/nix-support/setup-hook <<EOF 238 addGemPath() { 239 addToSearchPath GEM_PATH \$1/${passthru.gemPath} 240 } 241 addRubyLibPath() { 242 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby 243 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir} 244 addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}/${stdenv.hostPlatform.system} 245 } 246 247 addEnvHooks "$hostOffset" addGemPath 248 addEnvHooks "$hostOffset" addRubyLibPath 249 EOF 250 '' + opString docSupport '' 251 # Prevent the docs from being included in the closure 252 sed -i "s|\$(DESTDIR)$devdoc|\$(datarootdir)/\$(RI_BASE_NAME)|" $rbConfig 253 sed -i "s|'--with-ridir=$devdoc/share/ri'||" $rbConfig 254 255 # Add rbconfig shim so ri can find docs 256 mkdir -p $devdoc/lib/ruby/site_ruby 257 cp ${./rbconfig.rb} $devdoc/lib/ruby/site_ruby/rbconfig.rb 258 '' + opString useBaseRuby '' 259 # Prevent the baseruby from being included in the closure. 260 ${removeReferencesTo}/bin/remove-references-to \ 261 -t ${baseRuby} \ 262 $rbConfig $out/lib/libruby* 263 ''; 264 265 installCheckPhase = '' 266 overriden_cc=$(CC=foo $out/bin/ruby -rrbconfig -e 'puts RbConfig::CONFIG["CC"]') 267 if [[ "$overriden_cc" != "foo" ]]; then 268 echo "CC cannot be overwritten: $overriden_cc != foo" >&2 269 false 270 fi 271 272 fallback_cc=$(unset CC; $out/bin/ruby -rrbconfig -e 'puts RbConfig::CONFIG["CC"]') 273 if [[ "$fallback_cc" != "$CC" ]]; then 274 echo "CC='$fallback_cc' should be '$CC' by default" >&2 275 false 276 fi 277 ''; 278 doInstallCheck = true; 279 280 disallowedRequisites = op (!jitSupport) stdenv.cc.cc 281 ++ op useBaseRuby baseRuby; 282 283 meta = with lib; { 284 description = "An object-oriented language for quick and easy programming"; 285 homepage = "https://www.ruby-lang.org/"; 286 license = licenses.ruby; 287 maintainers = with maintainers; [ vrthra manveru marsam ]; 288 platforms = platforms.all; 289 knownVulnerabilities = op (lib.versionOlder ver.majMin "3.0") "This Ruby release has reached its end of life. See https://www.ruby-lang.org/en/downloads/branches/."; 290 }; 291 292 passthru = rec { 293 version = ver; 294 rubyEngine = "ruby"; 295 libPath = "lib/${rubyEngine}/${ver.libDir}"; 296 gemPath = "lib/${rubyEngine}/gems/${ver.libDir}"; 297 devEnv = import ./dev.nix { 298 inherit buildEnv bundler bundix; 299 ruby = self; 300 }; 301 302 inherit rubygems; 303 inherit (import ../../ruby-modules/with-packages { 304 inherit lib stdenv makeBinaryWrapper buildRubyGem buildEnv; 305 gemConfig = defaultGemConfig; 306 ruby = self; 307 }) withPackages buildGems gems; 308 309 } // lib.optionalAttrs useBaseRuby { 310 inherit baseRuby; 311 }; 312 } 313 ) args; in self; 314 315in { 316 mkRubyVersion = rubyVersion; 317 mkRuby = generic; 318 319 ruby_2_7 = generic { 320 version = rubyVersion "2" "7" "8" ""; 321 sha256 = "sha256-wtq2PLyPKgVSYQitQZ76Y6Z+1AdNu8+fwrHKZky0W6A="; 322 }; 323 324 ruby_3_1 = generic { 325 version = rubyVersion "3" "1" "4" ""; 326 sha256 = "sha256-o9VYeaDfqx1xQf3xDSKgfb+OXNxEFdob3gYSfVzDx7Y="; 327 }; 328 329 ruby_3_2 = generic { 330 version = rubyVersion "3" "2" "2" ""; 331 sha256 = "sha256-lsV1WIcaZ0jeW8nydOk/S1qtBs2PN776Do2U57ikI7w="; 332 cargoSha256 = "sha256-6du7RJo0DH+eYMOoh3L31F3aqfR5+iG1iKauSV1uNcQ="; 333 }; 334 335 ruby_3_3 = generic { 336 version = rubyVersion "3" "3" "0" "preview3"; 337 sha256 = "sha256-CWkUG+kuZ+DtuEqPs1SsyY8BvXjmAqI6DxNgRcgvSAk="; 338 cargoSha256 = "sha256-GeelTMRFIyvz1QS2L+Q3KAnyQy7jc0ejhx3TdEFVEbk="; 339 }; 340 341}