racket: refactor and add features, 8.14 -> 8.15, mark Darwin as badPlatforms (#365194)

This commit is contained in:
Arne Keller
2025-01-11 22:42:43 +01:00
committed by GitHub
12 changed files with 411 additions and 215 deletions
+216 -168
View File
@@ -2,208 +2,256 @@
lib,
stdenv,
fetchurl,
makeFontsConf,
cacert,
cairo,
coreutils,
fontconfig,
freefont_ttf,
glib,
gmp,
gtk3,
glibcLocales,
libedit,
libffi,
libiconv,
libGL,
libGLU,
libjpeg,
libiconvReal,
libz,
lz4,
ncurses,
libpng,
libtool,
mpfr,
openssl,
isMinimal ? false,
cairo,
fontconfig,
glib,
glibcLocales,
gtk3,
libGL,
libiodbc,
libjpeg,
libpng,
makeFontsConf,
pango,
poppler,
readline,
sqlite,
disableDocs ? false,
CoreFoundation,
gsettings-desktop-schemas,
unixODBC,
wrapGAppsHook3,
disableDocs ? false,
callPackage,
writers,
}:
let
fontsConf = makeFontsConf { fontDirectories = [ freefont_ttf ]; };
libPath = lib.makeLibraryPath (
[
cairo
fontconfig
glib
gmp
gtk3
gsettings-desktop-schemas
libedit
libjpeg
libpng
mpfr
ncurses
openssl
pango
poppler
readline
sqlite
]
++ lib.optionals (!stdenv.hostPlatform.isDarwin) [
libGL
libGLU
makeLibPaths = lib.concatMapStringsSep " " (
lib.flip lib.pipe [
lib.getLib
(x: ''"${x}/lib"'')
]
);
manifest = lib.importJSON ./manifest.json;
inherit (stdenv.hostPlatform) isDarwin isStatic;
runtimeDeps = [ openssl ];
mainDistDeps = [
(if isDarwin then libiodbc else unixODBC)
cairo
fontconfig
glib
gtk3
libGL
libjpeg
libpng
pango
sqlite
];
in
stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
pname = "racket";
version = "8.14"; # always change at once with ./minimal.nix
inherit (manifest) version;
src =
(lib.makeOverridable (
{ name, hash }:
fetchurl {
url = "https://mirror.racket-lang.org/installers/${version}/${name}-src.tgz";
inherit hash;
}
))
{
name = "${pname}-${version}";
hash = "sha256-qrjMDbM27S04KAPHCK1VqV/FKkQ2yRL2FvfEnUhFriw=";
};
let
info = manifest.${if isMinimal then "minimal" else "full"};
in
fetchurl {
url = "https://mirror.racket-lang.org/installers/${manifest.version}/${info.filename}";
inherit (info) sha256;
};
FONTCONFIG_FILE = fontsConf;
LD_LIBRARY_PATH = libPath;
NIX_LDFLAGS = lib.concatStringsSep " " [
(lib.optionalString (stdenv.cc.isGNU && !stdenv.hostPlatform.isDarwin) "-lgcc_s")
];
nativeBuildInputs = [
cacert
nativeBuildInputs = lib.optionals (!isMinimal) [
wrapGAppsHook3
];
buildInputs =
[
fontconfig
libffi
libtool
sqlite
gsettings-desktop-schemas
gtk3
ncurses
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
libiconv
CoreFoundation
];
buildInputs = [
libiconvReal
libz
lz4
ncurses
];
patches = [
# Hardcode variant detection because we wrap the Racket binary making it
# fail to detect its variant at runtime.
# See: https://github.com/NixOS/nixpkgs/issues/114993#issuecomment-812951247
./force-cs-variant.patch
# The entry point binary $out/bin/racket is codesigned at least once. The
# following error is triggered as a result.
# (error 'add-ad-hoc-signature "file already has a signature")
# We always remove the existing signature then call add-ad-hoc-signature to
# circumvent this error.
./force-remove-codesign-then-add.patch
patches = lib.optionals isDarwin [
/*
The entry point binary $out/bin/racket is codesigned at least once. The
following error is triggered as a result.
(error 'add-ad-hoc-signature "file already has a signature")
We always remove the existing signature then call add-ad-hoc-signature to
circumvent this error.
*/
./patches/force-remove-codesign-then-add.patch
];
preConfigure =
''
unset AR
for f in src/lt/configure src/cs/c/configure src/bc/src/string.c; do
substituteInPlace "$f" \
--replace /usr/bin/uname ${coreutils}/bin/uname \
--replace /bin/cp ${coreutils}/bin/cp \
--replace /bin/ln ${coreutils}/bin/ln \
--replace /bin/rm ${coreutils}/bin/rm \
--replace /bin/true ${coreutils}/bin/true
done
# The configure script forces using `libtool -o` as AR on Darwin. But, the
# `-o` option is only available from Apple libtool. GNU ar works here.
/*
The configure script forces using `libtool -o` as AR on Darwin. But, the
`-o` option is only available from Apple libtool. GNU ar works here.
*/
lib.optionalString isDarwin ''
substituteInPlace src/ChezScheme/zlib/configure \
--replace 'ARFLAGS="-o"' 'AR=ar; ARFLAGS="rc"'
--replace-fail 'ARFLAGS="-o"' 'AR=ar; ARFLAGS="rc"'
''
+ ''
mkdir src/build
cd src/build
''
+ lib.optionalString stdenv.hostPlatform.isLinux ''
gappsWrapperArgs+=("--prefix" "LD_LIBRARY_PATH" ":" ${libPath})
gappsWrapperArgs+=("--set" "LOCALE_ARCHIVE" "${glibcLocales}/lib/locale/locale-archive")
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
gappsWrapperArgs+=("--prefix" "DYLD_LIBRARY_PATH" ":" ${libPath})
'';
preBuild = lib.optionalString stdenv.hostPlatform.isDarwin ''
# Cannot set DYLD_LIBRARY_PATH as an attr of this drv, becasue dynamic
# linker environment variables like this are purged.
# See: https://apple.stackexchange.com/a/212954/167199
# Make builders feed it to dlopen(...). Do not expose all of $libPath to
# DYLD_LIBRARY_PATH as the order of looking up symbols like
# `__cg_jpeg_resync_to_restart` will be messed up. Our libJPEG.dyllib
# expects it from our libTIFF.dylib, but instead it could not be found from
# the system `libTIFF.dylib`. DYLD_FALLBACK_LIBRARY_PATH has its own problem
# , too.
export DYLD_FALLBACK_LIBRARY_PATH="${libPath}"
'';
shared = if stdenv.hostPlatform.isDarwin then "dylib" else "shared";
configureFlags =
[
"--enable-${shared}"
"--enable-lt=${libtool}/bin/libtool"
]
++ lib.optionals disableDocs [ "--disable-docs" ]
++ lib.optionals stdenv.hostPlatform.isDarwin [
"--disable-strip"
"--enable-xonx"
];
configureScript = "../configure";
enableParallelBuilding = false;
configureFlags =
[
"--enable-check"
"--enable-csonly"
"--enable-liblz4"
"--enable-libz"
]
++ lib.optional disableDocs "--disable-docs"
++ lib.optionals (!isStatic) [
# instead of `--disable-static` that `stdenv` assumes
"--disable-libs"
# "not currently supported" in `configure --help-cs` but still emphasized in README
"--enable-shared"
]
++ lib.optionals isDarwin [
"--disable-strip"
# "use Unix style (e.g., use Gtk) for Mac OS", which eliminates many problems
"--enable-xonx"
];
dontStrip = stdenv.hostPlatform.isDarwin;
preBuild =
let
libPaths = makeLibPaths mainDistDeps;
libPathsVar = if isDarwin then "DYLD_FALLBACK_LIBRARY_PATH" else "LD_LIBRARY_PATH";
in
lib.optionalString (!isMinimal) (
/*
Makes FFIs available for setting up `main-distribution` and its
dependencies, which is integrated into the build process of Racket
*/
''
for lib_path in ${libPaths}; do
addToSearchPath ${libPathsVar} $lib_path
done
''
# Fixes Fontconfig errors
+ ''
export FONTCONFIG_FILE=${makeFontsConf { fontDirectories = [ ]; }}
export XDG_CACHE_HOME=$(mktemp -d)
''
);
meta = with lib; {
description = "Programmable programming language";
longDescription = ''
Racket is a full-spectrum programming language. It goes beyond
Lisp and Scheme with dialects that support objects, types,
laziness, and more. Racket enables programmers to link
components written in different dialects, and it empowers
programmers to create new, project-specific dialects. Racket's
libraries support applications from web servers and databases to
GUIs and charts.
dontStrip = isDarwin;
preFixup = lib.optionalString (!isMinimal && !isDarwin) ''
gappsWrapperArgs+=("--set" "LOCALE_ARCHIVE" "${glibcLocales}/lib/locale/locale-archive")
'';
postFixup =
let
libPaths = makeLibPaths (runtimeDeps ++ lib.optionals (!isMinimal) mainDistDeps);
in
''
$out/bin/racket -f - <<EOF
(require setup/dirs)
(define config-path (build-path (find-config-dir) "config.rktd"))
(define prev-config (with-input-from-file config-path read))
(define prev-lib-search-dirs (hash-ref prev-config 'lib-search-dirs '(#f)))
(define lib-search-dirs (append '(${libPaths}) prev-lib-search-dirs))
(define config (hash-set prev-config 'lib-search-dirs lib-search-dirs))
(with-output-to-file config-path (thunk (pretty-write config))
#:exists 'replace)
EOF
'';
passthru = {
# Functionalities #
updateScript = {
command = ./update.py;
attrPath = "racket";
supportedFeatures = [ "commit" ];
};
writeScript =
nameOrPath:
{
libraries ? [ ],
...
}@config:
assert lib.assertMsg (libraries == [ ]) "library integration for Racket has not been implemented";
writers.makeScriptWriter (
builtins.removeAttrs config [ "libraries" ]
// {
interpreter = "${lib.getExe finalAttrs.finalPackage}";
}
) nameOrPath;
writeScriptBin = name: finalAttrs.passthru.writeScript "/bin/${name}";
# Tests #
tests = builtins.mapAttrs (name: path: callPackage path { racket = finalAttrs.finalPackage; }) (
{
## Basic ##
write-greeting = ./tests/write-greeting.nix;
get-version-and-variant = ./tests/get-version-and-variant.nix;
load-openssl = ./tests/load-openssl.nix;
## Nixpkgs supports ##
nix-write-script = ./tests/nix-write-script.nix;
}
// lib.optionalAttrs (!isMinimal) {
## `main-distribution` ##
draw-crossing = ./tests/draw-crossing.nix;
}
);
};
meta = {
description =
"Programmable programming language" + lib.optionalString isMinimal " (minimal distribution)";
longDescription =
''
Racket is a full-spectrum programming language. It goes beyond
Lisp and Scheme with dialects that support objects, types,
laziness, and more. Racket enables programmers to link
components written in different dialects, and it empowers
programmers to create new, project-specific dialects. Racket's
libraries support applications from web servers and databases to
GUIs and charts.
''
+ lib.optionalString isMinimal ''
This minimal distribution includes just enough of Racket that you can
use `raco pkg` to install more.
'';
homepage = "https://racket-lang.org/";
changelog = "https://github.com/racket/racket/releases/tag/v${version}";
license = with licenses; [
asl20 # or
changelog = "https://github.com/racket/racket/releases/tag/v${finalAttrs.version}";
/*
> Racket is distributed under the MIT license and the Apache version 2.0
> license, at your option.
> The Racket runtime system embeds Chez Scheme, which is distributed
> under the Apache version 2.0 license.
*/
license = with lib.licenses; [
asl20
mit
];
maintainers = [ ];
platforms = [
"x86_64-darwin"
"x86_64-linux"
"aarch64-linux"
"aarch64-darwin"
];
maintainers = with lib.maintainers; [ rc-zb ];
mainProgram = "racket";
platforms = lib.platforms.${if isMinimal then "all" else "unix"};
badPlatforms = lib.platforms.darwin;
};
}
})
@@ -1,18 +0,0 @@
Hardcode Racket variant to CS
Hardcode variant detection because nixpkgs wraps the Racket binary making it
fail to detect its variant at runtime.
https://github.com/NixOS/nixpkgs/issues/114993#issuecomment-812951247
--- old/collects/setup/variant.rkt
+++ new/collects/setup/variant.rkt
@@ -7,7 +7,8 @@
(provide variant-suffix
script-variant?)
-(define plain-variant
+(define plain-variant 'cs)
+#;(define plain-variant
(delay/sync
(cond
[(cross-installation?)
@@ -0,0 +1,11 @@
{
"version": "8.15",
"full": {
"filename": "racket-8.15-src.tgz",
"sha256": "602b848459daf1b2222a46a9094e85ae2d28e480067219957fa46af8400e1233"
},
"minimal": {
"filename": "racket-minimal-8.15-src.tgz",
"sha256": "1ac132c56bc52312049fa4f0849237f66713e8e0a7ab6c4780504633ee8f1dc3"
}
}
@@ -1,25 +0,0 @@
{ racket }:
racket.overrideAttrs (oldAttrs: rec {
pname = "racket-minimal";
version = oldAttrs.version;
src = oldAttrs.src.override {
name = "${pname}-${version}";
hash = "sha256-/BhnyIw4QQ2aMKW8FDJlsalSW3pTLqP74CXJ15td5so=";
};
meta = oldAttrs.meta // {
description = "Racket without bundled packages, such as Dr. Racket";
longDescription = ''
The essential package racket-libs is included,
as well as libraries that live in collections. In particular, raco
and the pkg library are still bundled.
'';
platforms = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
};
})
@@ -0,0 +1,18 @@
{ runCommandLocal, racket }:
runCommandLocal "racket-test-draw-crossing"
{
nativeBuildInputs = [ racket ];
}
''
racket -f - <<EOF
(require racket/draw)
(define target (make-bitmap 64 64))
(define dc (new bitmap-dc% [bitmap target]))
(send dc draw-line 0 0 64 64)
(send dc draw-line 0 64 64 0)
(send target save-file (getenv "out") 'png)
EOF
''
@@ -0,0 +1,27 @@
{ runCommandLocal, racket }:
runCommandLocal "racket-test-get-version-and-variant"
{
nativeBuildInputs = [ racket ];
}
''
expectation="${racket.version}"
output="$(racket -e '(display (version))')"
if test "$output" != "$expectation"; then
echo "output mismatch: expected ''${expectation}, but got ''${output}"
exit 1
fi
expectation="cs"
output="$(racket -e '(require launcher/launcher) (display (current-launcher-variant))')"
if test "$output" != "$expectation"; then
echo "output mismatch: expected ''${expectation}, but got ''${output}"
exit 1
fi
touch $out
''
@@ -0,0 +1,15 @@
{ runCommandLocal, racket }:
runCommandLocal "racket-test-load-openssl"
{
nativeBuildInputs = [ racket ];
}
''
racket -f - <<EOF
(require openssl)
(unless ssl-available?
(raise ssl-load-fail-reason))
EOF
touch $out
''
@@ -0,0 +1,26 @@
{ runCommandLocal, racket }:
let
script = racket.writeScript "racket-test-nix-write-script-the-script" { } ''
#lang racket/base
(display "success")
(newline)
'';
in
runCommandLocal "racket-test-nix-write-script"
{
nativeBuildInputs = [ racket ];
}
''
expectation="success"
output="$(${script})"
if test "$output" != "$expectation"; then
echo "output mismatch: expected ''${expectation}, but got ''${output}"
exit 1
fi
touch $out
''
@@ -0,0 +1,23 @@
{ runCommandLocal, racket }:
runCommandLocal "racket-test-write-greeting"
{
nativeBuildInputs = [ racket ];
}
''
expectation="Hello, world!"
racket -f - <<EOF
(with-output-to-file (getenv "out")
(lambda ()
(display "Hello, world!")
(newline)))
EOF
output="$(cat $out)"
if test "$output" != "$expectation"; then
echo "output mismatch: expected ''${expectation}, but got ''${output}"
exit 1
fi
''
+73
View File
@@ -0,0 +1,73 @@
#! /usr/bin/env nix-shell
#! nix-shell -i python3 --packages 'python3.withPackages (ps: with ps; [ requests beautifulsoup4 ])'
import os
import re
import json
import requests
from bs4 import BeautifulSoup
SITE = "https://download.racket-lang.org"
MANIFEST_FILENAME = "manifest.json"
def find_info(table, group_name, subgroup_name):
group = table.find(
string=re.compile("^{}\\s*".format(group_name))
).find_parent("tr", class_="group")
subgroup = group.find_next(
string=re.compile("^{}\\s*".format(subgroup_name))
).find_parent(class_="subgroup")
link = subgroup.find_next(
"a",
class_="installer",
string="Source"
)
filename = link["href"].split("/")[1]
sha256 = link.find_next(class_="checksum").string
return {
"filename": filename,
"sha256": sha256,
}
os.chdir(os.path.dirname(os.path.abspath(__file__)))
prev_version = os.environ["UPDATE_NIX_OLD_VERSION"]
homepage = BeautifulSoup(requests.get(SITE).text, "html.parser")
version = homepage.find(
"h3",
string=re.compile("^Version \\d+\\.\\d+")
).string.split()[1]
if version == prev_version:
raise Exception("no newer version available")
down_page_path = homepage.find(
"a",
string="More Installers and Checksums"
)["href"]
down_page = BeautifulSoup(requests.get(SITE + "/" + down_page_path).text, "html.parser")
down_table = down_page.find(class_="download-table")
full = find_info(down_table, "Racket", "Unix")
minimal = find_info(down_table, "Minimal Racket", "All Platforms")
with open(MANIFEST_FILENAME, "w", encoding="utf-8") as f:
json.dump({
"version": version,
"full": full,
"minimal": minimal,
}, f, indent=2, ensure_ascii=False)
f.write("\n")
print(json.dumps(
[
{
"attrPath": os.environ["UPDATE_NIX_ATTR_PATH"],
"oldVersion": prev_version,
"newVersion": version,
"files": [ os.path.abspath(MANIFEST_FILENAME) ],
},
],
indent=2, ensure_ascii=False
))
+2 -4
View File
@@ -7370,10 +7370,8 @@ with pkgs;
wireplumber = callPackage ../development/libraries/pipewire/wireplumber.nix { };
racket = callPackage ../development/interpreters/racket {
inherit (darwin.apple_sdk.frameworks) CoreFoundation;
};
racket-minimal = callPackage ../development/interpreters/racket/minimal.nix { };
racket = callPackage ../development/interpreters/racket { };
racket-minimal = racket.override { isMinimal = true; };
rakudo = callPackage ../development/interpreters/rakudo { };
moarvm = darwin.apple_sdk_11_0.callPackage ../development/interpreters/rakudo/moarvm.nix {