1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
{ lib
, stdenv
, cairo
, curl
, fetchurl
, freealut
, gdk-pixbuf
, git
, glib
, gnome2
, graphviz
, gtk2-x11
, interpreter
, libGL
, libGLU
, libogg
, librsvg
, libvorbis
, makeWrapper
, ncurses
, openal
, openssl
, pango
, pcre
, runCommand
, runtimeShell
, tzdata
, udis86
, unzip
, writeScriptBin
, zlib
}:
let
runtimeLibs = [
cairo
freealut
gdk-pixbuf
glib
gnome2.gtkglext
graphviz
gtk2-x11
libGL
libGLU
libogg
libvorbis
openal
openssl
pango
pcre
udis86
zlib
];
wrapFactorScript = { from, to ? false, runtimeLibs }: ''
# Set Gdk pixbuf loaders file to the one from the build dependencies here
unset GDK_PIXBUF_MODULE_FILE
# Defined in gdk-pixbuf setup hook
findGdkPixbufLoaders "${librsvg}"
${if (builtins.isString to) then "makeWrapper ${from} ${to}" else "wrapProgram ${from}"} \
--set GDK_PIXBUF_MODULE_FILE "$GDK_PIXBUF_MODULE_FILE" \
--argv0 factor \
--prefix LD_LIBRARY_PATH : /run/opengl-driver/lib:${lib.makeLibraryPath runtimeLibs} \
--prefix PATH : ${lib.makeBinPath [ graphviz ]}
'';
wrapFactor = runtimeLibs:
runCommand (lib.appendToName "with-libs" interpreter).name
{
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ gdk-pixbuf ];
passthru.runtimeLibs = runtimeLibs ++ interpreter.runtimeLibs;
}
(wrapFactorScript {
from = "${interpreter}/lib/factor/.factor-wrapped";
to = "$out/bin/factor";
runtimeLibs = (runtimeLibs ++ interpreter.runtimeLibs);
});
# Development helper for use in nix shell
wrapLocalFactor = writeScriptBin "wrapFactor" ''
#!${runtimeShell}
${wrapFactorScript { from = "./factor"; inherit runtimeLibs; }}
ln -sf factor.image .factor-wrapped.image
'';
rev = "e10b64dbc53a8583098e73580a1eb9ff4ce0c709";
version = "0.99";
in
stdenv.mkDerivation {
pname = "factor-lang";
inherit version;
src = fetchurl {
url = "https://downloads.factorcode.org/releases/${version}/factor-src-${version}.zip";
sha256 = "f5626bb3119bd77de9ac3392fdbe188bffc26557fab3ea34f7ca21e372a8443e";
};
patches = [
./staging-command-line-0.99-pre.patch
./workdir-0.99-pre.patch
./adjust-paths-in-unit-tests.patch
];
nativeBuildInputs = [ git makeWrapper curl unzip wrapLocalFactor ];
buildInputs = runtimeLibs;
postPatch = ''
sed -ie '4i GIT_LABEL = heads/master-${rev}' GNUmakefile
# There is no ld.so.cache in NixOS so we patch out calls to that completely.
# This should work as long as no application code relies on `find-library*`
# to return a match, which currently is the case and also a justified assumption.
sed -ie "s#/sbin/ldconfig -p#cat $out/lib/factor/ld.so.cache#g" \
basis/alien/libraries/finder/linux/linux.factor
# Some other hard-coded paths to fix:
sed -i 's#/usr/share/zoneinfo/#${tzdata}/share/zoneinfo/#g' \
extra/tzinfo/tzinfo.factor
sed -i 's#/usr/share/terminfo#${ncurses.out}/share/terminfo#g' \
extra/terminfo/terminfo.factor
# De-memoize xdg-* functions, otherwise they break the image.
sed -ie 's/^MEMO:/:/' basis/xdg/xdg.factor
# update default paths in factor-listener.el for fuel mode
substituteInPlace misc/fuel/fuel-listener.el \
--replace '(defcustom fuel-factor-root-dir nil' "(defcustom fuel-factor-root-dir \"$out/lib/factor\""
'';
buildPhase = ''
runHook preBuild
# Necessary here, because ld.so.cache is needed in its final location during rebuild.
mkdir -p $out/bin $out/lib/factor
patchShebangs ./build.sh
# Factor uses XDG_CACHE_HOME for cache during compilation.
# We can't have that. So, set it to $TMPDIR/.cache
export XDG_CACHE_HOME=$TMPDIR/.cache && mkdir -p $XDG_CACHE_HOME
# There is no ld.so.cache in NixOS so we construct one
# out of known libraries. The side effect is that find-lib
# will work only on the known libraries. There does not seem
# to be a generic solution here.
find $(echo ${lib.makeLibraryPath runtimeLibs} | sed -e 's#:# #g') -name \*.so.\* > $TMPDIR/so.lst
(echo $(cat $TMPDIR/so.lst | wc -l) "libs found in cache \`/etc/ld.so.cache'";
for l in $(<$TMPDIR/so.lst); do
echo " $(basename $l) (libc6,x86-64) => $l";
done)> $out/lib/factor/ld.so.cache
make -j$NIX_BUILD_CORES linux-x86-64
printf "First build from upstream boot image\n" >&2
./build.sh bootstrap
printf "Rebuild boot image\n" >&2
./factor -script -e='"unix-x86.64" USING: system bootstrap.image memory ; make-image save 0 exit'
printf "Second build from local boot image\n" >&2
./build.sh bootstrap
runHook postBuild
'';
# For now, the check phase runs, but should always return 0. This way the logs
# contain the test failures until all unit tests are fixed. Then, it should
# return 1 if any test failures have occured.
doCheck = false;
checkPhase = ''
runHook preCheck
set +e
./factor -e='USING: tools.test zealot.factor sequences namespaces formatting ;
zealot-core-vocabs "compiler" suffix [ test ] each :test-failures
test-failures get length "Number of failed Tests: %d\n" printf'
[ $? -eq 0 ] || {
mkdir -p "$out/nix-support"
touch "$out/nix-support/failed"
}
set -e
runHook postCheck
'';
installPhase = ''
runHook preInstall
cp -r factor factor.image LICENSE.txt README.md basis core extra misc $out/lib/factor
# Create a wrapper in bin/ and lib/factor/
${wrapFactorScript { from = "$out/lib/factor/factor"; inherit runtimeLibs; }}
mv $out/lib/factor/factor.image $out/lib/factor/.factor-wrapped.image
cp $out/lib/factor/factor $out/bin/
# Emacs fuel expects the image being named `factor.image` in the factor base dir
ln -s $out/lib/factor/.factor-wrapped.image $out/lib/factor/factor.image
# install fuel mode for emacs
mkdir -p $out/share/emacs/site-lisp
ln -s $out/lib/factor/misc/fuel/*.el $out/share/emacs/site-lisp/
runHook postInstall
'';
passthru = {
inherit runtimeLibs wrapFactorScript;
withLibs = wrapFactor;
};
meta = with lib; {
homepage = "https://factorcode.org/";
description = "Concatenative, stack-based programming language";
longDescription = ''
The Factor programming language is a concatenative, stack-based
programming language with high-level features including dynamic types,
extensible syntax, macros, and garbage collection. On a practical side,
Factor has a full-featured library, supports many different platforms, and
has been extensively documented.
The implementation is fully compiled for performance, while still
supporting interactive development. Factor applications are portable
between all common platforms. Factor can deploy stand-alone applications
on all platforms. Full source code for the Factor project is available
under a BSD license.
'';
license = licenses.bsd2;
maintainers = with maintainers; [ spacefrogg ];
platforms = lib.intersectLists platforms.x86_64 platforms.linux;
mainProgram = "factor";
};
}
|