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