factor: Restructure package for easier extension

This commit is contained in:
Michael Raitza 2024-02-09 18:36:08 +01:00 committed by Michael Raitza
parent f379c22fee
commit ba8b602211
15 changed files with 861 additions and 42 deletions

View File

@ -0,0 +1,231 @@
# Factor {#sec-language-factor}
## Development Environment {#ssec-factor-dev-env}
All Nix expressions for the Factor compiler and development environment can be found in `pkgs/top-level/factor-packages.nix`.
The default package `factor-lang` provides support for the built-in graphical user interface and a selected set of C library bindings, e.g., for sound and TLS connections.
It also comes with the Fuel library for Emacs that provides an integrated development environment for developing Factor programs including access to the Factor runtime and online documentation.
For using less frequently used libraries that need additional bindings, you can override the `factor-lang` package and add more library bindings and/or binaries to its PATH.
The package is defined in `pkgs/development/compilers/factor-lang/wrapper.nix` and provides several attributes for adding those:
- `extraLibs` adds the packages' `/lib` paths to the wrapper and adds all shared libraries to an ld.so cache such that they can be found dynamically by the Factor runtime.
- `binPackages` does the same as `extraLibs` and additionally adds the packages to Factor's PATH environment variable.
- `extraVocabs` adds Factor vocabularies to the tree that are not part of the standard library.
The packages must adhere to the default vocabulary root structure to be found.
- `guiSupport` draws in all necessary graphical libraries to enable the Factor GUI.
This should be set to `true` when considering building and running graphical applications with this Factor runtime (even if the Factor GUI is not used for programming).
This argument is `true` by default.
- `enableDefaults` can be deactivated to only wrap libraries that are named in `extraLibs` or `binPackages`.
This reduces the runtime dependencies especially when shipping Factor applications.
The package also passes through several attributes listing the wrapped libraries and binaries, namely, `extraLibs` and `binPackages` as well as `defaultLibs` and `defaultBins`.
Additionally, all `runtimeLibs` is the concatenation of all the above for the purpose of providing all necessary dynamic libraries as "`propagatedBuildInputs`".
`factorPackages` provides pre-configured Factor packages:
- `factorPackages.factor-lang` is the default package with GUI support and several default library bindings (e.g. openssl, openal etc.).
- `factorPackages.factor-no-gui` turns off GUI support while maintaining default library bindings.
- `factorPackages.factor-minimal` comes with practically no additional library bindings and binaries and no GUI support.
- `factorPackages.factor-minimal-gui` comes with no additional library bindings but includes GUI support.
### Scaffolding and the `work` vocabulary root {#ssec-factor-scaffolding}
Factor uses the concept of "scaffolding" to spin off a new vocabulary in a personal workspace rooted at the `work` vocabulary root.
This concept does not scale very well, because it makes many assumptions which all turn out to be wrong at some point.
In the current implementation, the `work` vocabulary root points to `/var/lib/factor` on the target machine.
This can be suitable for a single-user system.
Create the location and make it writable to your user.
Then, you can use the `scaffold-work` word as instructed by many tutorials.
If you don't like this approach, you can work around it by creating a `~/.factor-roots` file in your home directory which contains the locations you desire to represent additional Factor vocabulary roots, one directory per line.
Use `scaffold-vocab` to create your vocabularies in one of these additional roots.
The online Factor documentation is extensive on how to use the scaffolding framework.
## Packaging Factor Vocabularies {#ssec-factor-packaging}
All Factor vocabularies that shall be added to a Factor environment via the `extraVocabs` attribute must adhere to the following directory scheme.
Its top-level directory must be one (or multiple) of `basis`, `core` or `extra`.
`work` is routed to `/var/lib/factor` and is not shipped nor referenced in the nix store, see the section on [scaffolding](#ssec-factor-scaffolding).
You should usually use `extra`, but you can use the other roots to overwrite built-in vocabularies.
Be aware that vocabularies in `core` are part of the Factor image which the development environment is run from.
This means the code in those vocabularies is not loaded from the sources, such that you need to call `refresh-all` to re-compile and load the changed definitions.
In these instances, it is advised to override the `factor-unwrapped` package directly, which compiles and packages the core Factor libraries into the default Factor
image.
As per Factor convention, your vocabulary `foo.factor` must be in a directory of the same name in addition to one of the previously mentioned vocabulary roots, e.g. `extra/foo/foo.factor`.
All extra Factor vocabularies are registered in `pkgs/top-level/factor-packages.nix` and their package definitions usually live in `development/compilers/factor-lang/vocabs/`.
Package a vocabulary using the `buildFactorVocab` function.
Its default `installPhase` takes care of installing it under `out/lib/factor`.
It also understands the following special attributes:
- `vocabName` is the path to the vocabulary to be installed.
Defaults to `pname`.
- `vocabRoot` is the vocabulary root to install the vocabulary under.
Defaults to `extra`.
Unless you know what you are doing, do not change it.
Other readily understood vocabulary roots are `core` and `base`, which allow you to modify the default Factor runtime environment with an external package.
- `extraLibs`, `extraVocabs`, `extraPaths` have the same meaning as for [applications](#ssec-factor-applications).
They have no immediate effect and are just passed through.
When building factor-lang packages and Factor applications that use this respective vocabulary, these variables are evaluated and their paths added to the runtime environment.
The function understands several forms of source directory trees:
1. Simple single-vocab projects with their Factor and supplementary files directly in the project root.
All `.factor` and `.txt` files are copied to `out/lib/factor/<vocabRoot>/<vocabName>`.
2. More complex projects with several vocabularies next to each other, e.g. `./<vocabName>` and `./<otherVocab>`.
All directories except `bin`, `doc` and `lib` are copied to `out/lib/factor/<vocabRoot>`.
3. Even more complex projects that touch multiple vocabulary roots.
Vocabularies must reside under `lib/factor/<root>/<vocab>` with the name-giving vocabulary being in `lib/factor/<vocabRoot>/<vocabName>`.
All directories in `lib/factor` are copied to `out/`.
For instance, packaging the Bresenham algorithm for line interpolation looks like this, see `pkgs/development/compilers/factor-lang/vocabs/bresenham` for the complete file:
```nix
{
factorPackages,
fetchFromGitHub,
}:
factorPackages.buildFactorVocab {
pname = "bresenham";
version = "dev";
src = fetchFromGitHub {
owner = "Capital-EX";
repo = "bresenham";
rev = "58d76b31a17f547e19597a09d02d46a742bf6808";
hash = "sha256-cfQOlB877sofxo29ahlRHVpN3wYTUc/rFr9CJ89dsME=";
};
}
```
The vocabulary goes to `lib/factor/extra`, extra files, like licenses etc. would go to `share/` as usual and could be added to the output via a `postInstall` phase.
In case the vocabulary binds to a shared library or calls a binary that needs to be present in the runtime environment of its users, add `extraPaths` and `extraLibs` attributes respectively.
They are then picked up by the `buildFactorApplication` function and added as runtime dependencies.
## Building Applications {#ssec-factor-applications}
Factor applications are built using Factor's `deploy` facility with the help of the `buildFactorApplication` function.
### `buildFactorApplication` function {#ssec-factor-buildFactorApplication-func}
`factorPackages.buildFactorApplication` *`buildDesc`*
When packaging a Factor application with [`buildFactorApplication`](#ssec-factor-buildFactorApplication-func), its [`override`](#sec-pkg-override) interface should contain the `factorPackages` argument.
For example:
```nix
{
lib,
fetchurl,
factorPackages,
}:
factorPackages.buildFactorApplication (finalAttrs: {
pname = "foo";
version = "1.0";
src = fetchurl {
url = "https://some-forge.org/foo-${finalAttrs.version}.tar.gz"
};
})
```
The `buildFactorApplication` function expects the following source structure for a package `foo-1.0` and produces a `/bin/foo` application:
```
foo-1.0/
foo/
foo.factor
deploy.factor
<more files and directories>...
```
It provides the additional attributes `vocabName` and `binName` to cope with naming deviations.
The `deploy.factor` file controls how the application is deployed and is documented in the Factor online documentation on the `deploy` facility.
Use the `preInstall` or `postInstall` hooks to copy additional files and directories to `out/`.
The function itself only builds the application in `/lib/factor/` and a wrapper in `/bin/`.
A more complex example shows how to specify runtime dependencies and additional Factor vocabularies at the example of the `painter` Factor application:
```nix
{
lib,
fetchFromGitHub,
factorPackages,
curl,
}:
factorPackages.buildFactorApplication (finalAttrs: {
pname = "painter";
version = "1";
factor-lang = factorPackages.factor-minimal-gui;
src = fetchFromGitHub {
name = finalAttrs.vocabName;
owner = "Capital-EX";
repo = "painter";
rev = "365797be8c4f82440bec0ad0a50f5a858a06c1b6";
hash = "sha256-VdvnvKNGcFAtjWVDoxyYgRSyyyy0BEZ2MZGQ71O8nUI=";
};
sourceRoot = ".";
enableUI = true;
extraVocabs = [ factorPackages.bresenham ];
extraPaths = with finalAttrs.factor-lang; binPackages ++ defaultBins ++ [ curl ];
})
```
The use of the `src.name` and`sourceRoot` attributes conveniently establish the necessary `painter` vocabulary directory that is needed for the deployment to work.
It requires the packager to specify the full set of binaries to be made available at runtime.
This enables the standard pattern for application packages to specify all runtime dependencies explicitly without the Factor runtime interfering.
`buildFactorApplication` is a wrapper around `stdenv.mkDerivation` and takes all of its attributes.
Additional attributes that are understood by `buildFactorApplication`:
*`buildDesc`* (Function or attribute set)
: A build description similar to `stdenv.mkDerivation` with the following attributes:
`vocabName` (String; _optional_)
: is the path to the vocabulary to be deployed relative to the source root.
So, directory `foo/` from the example above could be `extra/deep/down/foo`.
This allows you to maintain Factor's vocabulary hierarchy and distribute the same source tree as a stand-alone application and as a library in the Factor development environment via the `extraVocabs` attribute.
`binName` (String; _optional_)
: is the name of the resulting binary in `/bin/`.
It defaults to the last directory component in `vocabName`.
It is also added as the `meta.mainProgram` attribute to facilitate `nix run`.
`enableUI` (Boolean; _optional_)
: is `false` by default.
Set this to `true` when you ship a graphical application.
`extraLibs` (List; _optional_)
: adds additional libraries as runtime dependencies.
Defaults to `[]` and is concatenated with `runtimeLibs` from the used factor-lang package.
Use `factor-minimal` to minimize the closure of runtime libraries.
`extraPaths` (List; _optional_)
: adds additional binaries to the runtime PATH environment variable (without adding their libraries, as well).
Defaults to `[]` and is concatenated with `defaultBins` and `binPackages` from the used factor-lang package.
Use `factor-minimal` to minimize the closure of runtime libraries.
`deployScriptText` (String; _optional_)
: is the actual deploy Factor file that is executed to deploy the application.
You can change it if you need to perform additional computation during deployment.
`factor-lang` (Package; _optional_)
: overrides the Factor package to use to deploy this application, which also affects the default library bindings and programs in the runtime PATH.
It defaults to `factor-lang` when `enableUI` is turned on and `factor-no-gui` when it is turned off.
Applications that use only Factor libraries without external bindings or programs may set this to `factor-minimal` or `factor-minimal-gui`.

View File

@ -67,6 +67,7 @@ dhall.section.md
dlang.section.md
dotnet.section.md
emscripten.section.md
factor.section.md
gnome.section.md
go.section.md
gradle.section.md

View File

@ -2754,6 +2754,24 @@
"declarative-debugging": [
"index.html#declarative-debugging"
],
"sec-language-factor": [
"index.html#sec-language-factor"
],
"ssec-factor-scaffolding": [
"index.html#ssec-factor-scaffolding"
],
"ssec-factor-packaging": [
"index.html#ssec-factor-packaging"
],
"ssec-factor-buildFactorApplication-func": [
"index.html#ssec-factor-buildFactorApplication-func"
],
"ssec-factor-dev-env": [
"index.html#ssec-factor-dev-env"
],
"ssec-factor-applications": [
"index.html#ssec-factor-applications"
],
"sec-language-gnome": [
"index.html#sec-language-gnome"
],

View File

@ -18,6 +18,8 @@
- LLVM has been updated from LLVM 16 (on Darwin) and LLVM 18 (on other platforms) to LLVM 19.
This introduces some backwardsincompatible changes; see the [upstream release notes](https://releases.llvm.org/) for details.
- The Factor programming language packages were reworked. `factor-lang-scope` is now named `factorPackages` and provides a `buildFactorApplication` function to deploy Factor programs as binaries. It has also received proper documentation in the Nixpkgs manual.
- Emacs has been updated to 30.1.
This introduces some backwardsincompatible changes; see the NEWS for details.
NEWS can been viewed from Emacs by typing `C-h n`, or by clicking `Help->Emacs News` from the menu bar.

View File

@ -1,24 +1,19 @@
From da8a4b9c1094a568f443c525ca1ce11f686be1bc Mon Sep 17 00:00:00 2001
From: timor <timor.dd@googlemail.com>
Date: Thu, 8 Aug 2019 14:13:09 +0200
Subject: [PATCH] adjust unit test for finding executables in path for NixOS
---
basis/io/standard-paths/unix/unix-tests.factor | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/basis/io/standard-paths/unix/unix-tests.factor b/basis/io/standard-paths/unix/unix-tests.factor
index acd5029..870537f 100644
--- a/basis/io/standard-paths/unix/unix-tests.factor
+++ b/basis/io/standard-paths/unix/unix-tests.factor
@@ -5,13 +5,13 @@ sequences tools.test ;
diff -ur factor.orig/basis/io/standard-paths/unix/unix-tests.factor factor/basis/io/standard-paths/unix/unix-tests.factor
--- factor.orig/basis/io/standard-paths/unix/unix-tests.factor 2024-02-09 14:38:33.932439180 +0100
+++ factor/basis/io/standard-paths/unix/unix-tests.factor 2024-02-09 15:41:18.529141569 +0100
@@ -1,21 +1,21 @@
! Copyright (C) 2011 Doug Coleman.
! See https://factorcode.org/license.txt for BSD license.
USING: environment io.standard-paths io.standard-paths.unix
-sequences tools.test ;
+kernel sequences tools.test ;
{ f } [ "" find-in-path ] unit-test
{ t } [
- "ls" find-in-path { "/bin/ls" "/usr/bin/ls" } member?
+ "ls" find-in-path not not
] unit-test
{ t } [
"/sbin:" "PATH" os-env append "PATH" [
"ps" find-in-path
@ -26,3 +21,9 @@ index acd5029..870537f 100644
+ not not
] with-os-env
] unit-test
{ t } [
"ls" find-in-standard-login-path
- { "/bin/ls" "/usr/bin/ls" } member?
+ not not
] unit-test

View File

@ -0,0 +1,27 @@
diff -ur factor.orig/basis/alien/libraries/finder/linux/linux.factor factor/basis/alien/libraries/finder/linux/linux.factor
--- factor.orig/basis/alien/libraries/finder/linux/linux.factor 2024-02-09 14:38:33.966439078 +0100
+++ factor/basis/alien/libraries/finder/linux/linux.factor 2024-02-09 14:41:16.775938179 +0100
@@ -2,7 +2,7 @@
! See https://factorcode.org/license.txt for BSD license
USING: accessors alien.libraries.finder arrays assocs
combinators.short-circuit environment io io.encodings.utf8
-io.launcher kernel make sequences sets splitting system
+io.files io.launcher kernel make sequences sets splitting system
unicode ;
IN: alien.libraries.finder.linux
@@ -25,8 +25,12 @@
] map ;
: load-ldconfig-cache ( -- seq )
- "/sbin/ldconfig -p" utf8 [ read-lines ] with-process-reader*
- 2drop [ f ] [ rest parse-ldconfig-lines ] if-empty ;
+ "FACTOR_LD_SO_CACHE" os-env [
+ utf8 [ read-lines ] with-file-reader
+ ] [
+ { } clone
+ ] if*
+ [ f ] [ rest parse-ldconfig-lines ] if-empty ;
: ldconfig-arch ( -- str )
mach-map cpu of { "libc6" } or ;

View File

@ -0,0 +1,141 @@
{
stdenv,
lib,
writeText,
makeWrapper,
factor-lang,
factor-no-gui,
librsvg,
gdk-pixbuf,
}@initAttrs:
drvArgs:
let
flang = factor-lang; # workaround to satisfy nixf-tidy
in
(stdenv.mkDerivation drvArgs).overrideAttrs (
finalAttrs:
{
name ? "${finalAttrs.pname}-${finalAttrs.version}",
factor-lang ? if enableUI then flang else factor-no-gui,
enableUI ? false,
# Allow overriding the path to the deployed vocabulary name. A
# $vocabName.factor file must exist!
vocabName ? finalAttrs.pname or name,
# Allow overriding the binary name
binName ? lib.last (lib.splitString "/" vocabName),
# Extra libraries needed
extraLibs ? [ ],
# Extra binaries in PATH
extraPaths ? [ ],
# Extra vocabularies needed by this application
extraVocabs ? [ ],
deployScriptText ? ''
USING: command-line io io.backend io.pathnames kernel namespaces sequences
tools.deploy tools.deploy.config tools.deploy.backend vocabs.loader ;
IN: deploy-me
: load-and-deploy ( path/vocab -- )
normalize-path [
parent-directory add-vocab-root
] [
file-name dup reload deploy
] bi ;
: deploy-vocab ( path/vocab path/target -- )
normalize-path deploy-directory set
f open-directory-after-deploy? set
load-and-deploy ;
: deploy-me ( -- )
command-line get dup length 2 = [
first2 deploy-vocab
] [
drop
"usage: deploy-me <PATH-TO-VOCAB> <TARGET-DIR>" print
nl
] if ;
MAIN: deploy-me
'',
...
}@attrs:
let
deployScript = writeText "deploy-me.factor" finalAttrs.deployScriptText;
wrapped-factor = finalAttrs.factor-lang.override {
inherit (finalAttrs) extraLibs extraVocabs;
doInstallCheck = false;
};
runtimePaths = with finalAttrs.wrapped-factor; defaultBins ++ binPackages ++ finalAttrs.extraPaths;
in
{
inherit
enableUI
vocabName
deployScriptText
extraLibs
extraPaths
extraVocabs
binName
factor-lang
wrapped-factor
;
nativeBuildInputs = [
makeWrapper
(lib.hiPrio finalAttrs.wrapped-factor)
] ++ attrs.nativeBuildInputs or [ ];
buildInputs = (lib.optional enableUI gdk-pixbuf) ++ attrs.buildInputs or [ ];
buildPhase =
attrs.buildPhase or ''
runHook preBuild
vocabBaseName=$(basename "$vocabName")
mkdir -p "$out/lib/factor" "$TMPDIR/.cache"
export XDG_CACHE_HOME="$TMPDIR/.cache"
factor "${deployScript}" "./$vocabName" "$out/lib/factor"
cp "$TMPDIR/factor-temp"/*.image "$out/lib/factor/$vocabBaseName"
runHook postBuild
'';
__structuredAttrs = true;
installPhase =
attrs.installPhase or (
''
runHook preInstall
''
+ (lib.optionalString finalAttrs.enableUI ''
# 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}"
appendToVar makeWrapperArgs --set GDK_PIXBUF_MODULE_FILE "$GDK_PIXBUF_MODULE_FILE"
appendToVar makeWrapperArgs --prefix LD_LIBRARY_PATH : /run/opengl-driver/lib
'')
+ (lib.optionalString (wrapped-factor.runtimeLibs != [ ])) ''
appendToVar makeWrapperArgs --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath wrapped-factor.runtimeLibs}"
''
+ ''
mkdir -p "$out/bin"
makeWrapper "$out/lib/factor/$vocabBaseName/$vocabBaseName" \
"$out/bin/$binName" \
--prefix PATH : "${lib.makeBinPath runtimePaths}" \
"''${makeWrapperArgs[@]}"
runHook postInstall
''
);
passthru = {
vocab = finalAttrs.src;
} // attrs.passthru or { };
meta = {
platforms = wrapped-factor.meta.platforms;
mainProgram = finalAttrs.binName;
} // attrs.meta or { };
}
)

View File

@ -0,0 +1,59 @@
{
stdenv,
}@initAttrs:
drvArgs:
(stdenv.mkDerivation drvArgs).overrideAttrs (
finalAttrs:
{
name ? "${finalAttrs.pname}-${finalAttrs.version}",
vocabName ? finalAttrs.pname or name,
vocabRoot ? "extra",
# Runtime libraries needed to run this vocab, handed to runtime wrapper
extraLibs ? [ ],
# Extra vocabularies, handed to runtime wrapper
extraVocabs ? [ ],
# Extra binaries in PATH, handed to runtime wrapper
extraPaths ? [ ],
...
}@attrs:
{
inherit vocabName vocabRoot;
installPhase =
# Default installer
# 1. If lib/factor/<vocabRoot>/<vocabName> exists, copy all vocab roots
# under lib/factor/* to out/.
# 2. If <vocabName> exists, copy all directories next to <vocabName> to
# out/.
# These two carry over package-defined vocabs that the name-giving vocab
# depends on.
# 3. Otherwise, copy all .factor and .txt files to out/. For simple
# single-vocab packages.
attrs.installPhase or ''
runHook preInstall
mkdir -p "$out/lib/factor/${finalAttrs.vocabRoot}/${finalAttrs.vocabName}"
if [ -d "lib/factor/${finalAttrs.vocabRoot}/${finalAttrs.vocabName}" ]; then
find lib/factor -mindepth 1 -maxdepth 1 -type d -exec \
cp -r -t "$out/lib/factor" {} \+
elif [ -d "${finalAttrs.vocabName}" ]; then
fname="${finalAttrs.vocabName}"
base=$(basename "${finalAttrs.vocabName}")
root=''${fname%$base}
root=''${root:-.}
find "$root" -mindepth 1 -maxdepth 1 -type -d \
-not \( -name bin -or -name doc -or -name lib \) -exec \
cp -r -t "$out/lib/factor/${finalAttrs.vocabRoot}" {} \+
else
cp *.factor *.txt "$out/lib/factor/${finalAttrs.vocabRoot}/${finalAttrs.vocabName}"
fi
runHook postInstall
'';
passthru = {
inherit extraLibs extraVocabs extraPaths;
};
meta = attrs.meta or { };
}
)

View File

@ -1,24 +0,0 @@
{
lib,
pkgs,
overrides ? (self: super: { }),
}:
let
inside = (
self:
let
callPackage = pkgs.newScope self;
in
{
interpreter = callPackage ./factor99.nix { inherit (pkgs) stdenv; };
# Convenience access for using the returned attribute the same way as the
# interpreter derivation. Takes a list of runtime libraries as its only
# argument.
inherit (self.interpreter) withLibs;
}
);
extensible-self = lib.makeExtensible (lib.extends overrides inside);
in
extensible-self

View File

@ -0,0 +1,110 @@
{
lib,
stdenv,
fetchurl,
makeWrapper,
curl,
git,
ncurses,
tzdata,
unzip,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "factor-lang";
version = "0.99";
src = fetchurl {
url = "https://downloads.factorcode.org/releases/${finalAttrs.version}/factor-src-${finalAttrs.version}.zip";
sha256 = "f5626bb3119bd77de9ac3392fdbe188bffc26557fab3ea34f7ca21e372a8443e";
};
patches = [
# Use full path to image while bootstrapping
./staging-command-line-0.99-pre.patch
# Point work vocabulary root to a writable location
./workdir-0.99-pre.patch
# Patch hard-coded FHS paths
./adjust-paths-in-unit-tests.patch
# Avoid using /sbin/ldconfig
./ld.so.cache-from-env.patch
];
nativeBuildInputs = [
git
makeWrapper
curl
unzip
];
postPatch = ''
sed -ie '4i GIT_LABEL = heads/master-'$(< git-id) GNUmakefile
# Some other hard-coded paths to fix:
substituteInPlace extra/tzinfo/tzinfo.factor \
--replace-fail '/usr/share/zoneinfo' '${tzdata}/share/zoneinfo'
substituteInPlace extra/terminfo/terminfo.factor \
--replace-fail '/usr/share/terminfo' '${ncurses.out}/share/terminfo'
# update default paths in fuel-listener.el for fuel mode
substituteInPlace misc/fuel/fuel-listener.el \
--replace-fail '(defcustom fuel-factor-root-dir nil' "(defcustom fuel-factor-root-dir \"$out/lib/factor\""
'';
dontConfigure = true;
preBuild = ''
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
'';
makeTarget = "linux-x86-64";
postBuild = ''
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
'';
installPhase = ''
runHook preInstall
mkdir -p $out/lib/factor $out/share/emacs/site-lisp
cp -r factor factor.image libfactor.a libfactor-ffi-test.so \
boot.*.image LICENSE.txt README.md basis core extra misc \
$out/lib/factor
# install fuel mode for emacs
ln -r -s $out/lib/factor/misc/fuel/*.el $out/share/emacs/site-lisp
runHook postInstall
'';
meta = with lib; {
homepage = "https://factorcode.org/";
description = "A 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; [
vrthra
spacefrogg
];
platforms = [ "x86_64-linux" ];
};
})

View File

@ -0,0 +1,183 @@
{
lib,
stdenv,
makeWrapper,
buildEnv,
factor-unwrapped,
cairo,
freealut,
gdk-pixbuf,
glib,
gnome2,
gtk2-x11,
libGL,
libGLU,
librsvg,
graphviz,
libogg,
libvorbis,
openal,
openssl,
pango,
pcre,
udis86,
zlib,
# Enable factor GUI support
guiSupport ? true,
# Libraries added to ld.so.cache
extraLibs ? [ ],
# Packages added to path (and ld.so.cache)
binPackages ? [ ],
# Extra vocabularies added to out/lib/factor
extraVocabs ? [ ],
# Enable default libs and bins to run most of the standard library code.
enableDefaults ? true,
doInstallCheck ? true,
}:
let
inherit (lib) optional optionals optionalString;
# missing from lib/strings
escapeNixString = s: lib.escape [ "$" ] (builtins.toJSON s);
toFactorArgs = x: lib.concatStringsSep " " (map escapeNixString x);
defaultLibs = optionals enableDefaults [
libogg
libvorbis
openal
openssl
pcre
udis86
zlib
];
defaultBins = optionals enableDefaults [ graphviz ];
runtimeLibs =
defaultLibs
++ extraLibs
++ binPackages
++ (lib.flatten (map (v: v.extraLibs or [ ]) extraVocabs))
++ optionals guiSupport [
cairo
freealut
gdk-pixbuf
glib
gnome2.gtkglext
gtk2-x11
libGL
libGLU
pango
];
bins = binPackages ++ defaultBins ++ (lib.flatten (map (v: v.extraPaths or [ ]) extraVocabs));
vocabTree = buildEnv {
name = "${factor-unwrapped.pname}-vocabs";
ignoreCollisions = true;
pathsToLink = map (r: "/lib/factor/${r}") [
"basis"
"core"
"extra"
];
paths = [ factor-unwrapped ] ++ extraVocabs;
};
in
stdenv.mkDerivation (finalAttrs: {
pname = "${factor-unwrapped.pname}-env";
inherit (factor-unwrapped) version;
nativeBuildInputs = [ makeWrapper ];
buildInputs = optional guiSupport gdk-pixbuf;
dontUnpack = true;
installPhase =
''
runHook preInstall
''
+ optionalString guiSupport ''
# 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}"
makeWrapperArgs+=(--set GDK_PIXBUF_MODULE_FILE "$GDK_PIXBUF_MODULE_FILE")
''
+ ''
makeWrapperArgs+=(
--prefix LD_LIBRARY_PATH : /run/opengl-driver/lib:${lib.makeLibraryPath runtimeLibs}
--prefix PATH : ${lib.makeBinPath bins})
mkdir -p "$out/bin" "$out/share"
cp -r "${factor-unwrapped}/lib" "$out/"
cp -r "${factor-unwrapped}/share/emacs" "$out/share/"
chmod -R u+w "$out/lib" "$out/share"
(
cd ${vocabTree}
for f in "lib/factor/"* ; do
rm -r "$out/$f"
ln -s "${vocabTree}/$f" "$out/$f"
done
)
# 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 ([ stdenv.cc.libc ] ++ 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
# Create a wrapper in bin/ and lib/factor/
wrapProgram "$out/lib/factor/factor" \
--argv0 factor \
--set FACTOR_LD_SO_CACHE "$out/lib/factor/ld.so.cache" \
"''${makeWrapperArgs[@]}"
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 -rs $out/lib/factor/.factor-wrapped.image $out/lib/factor/factor.image
# Update default paths in fuel-listener.el to new output
sed -E -i -e 's#(\(defcustom fuel-factor-root-dir ").*(")#'"\1$out/lib/factor\2#" \
"$out/share/emacs/site-lisp/fuel-listener.el"
runHook postInstall
'';
inherit doInstallCheck;
disabledTests = toFactorArgs [
"io.files.info.unix"
"io.launcher.unix"
"io.ports"
"io.sockets"
"io.sockets.unix"
"io.sockets.secure.openssl"
"io.sockets.secure.unix"
];
installCheckPhase = ''
runHook preCheck
export HOME=$TMPDIR
$out/bin/factor -e='USING: tools.test tools.test.private
zealot.factor sequences namespaces formatting ;
zealot-core-vocabs
{ ${finalAttrs.disabledTests} } without
"compiler" suffix
[ test-vocab ] each :test-failures
test-failures get length "Number of failed tests: %d\n" printf'
runHook postCheck
'';
passthru = {
inherit
defaultLibs
defaultBins
extraLibs
runtimeLibs
binPackages
extraVocabs
;
};
meta = factor-unwrapped.meta // {
mainProgram = "factor";
};
})

View File

@ -0,0 +1,26 @@
{
lib,
factorPackages,
fetchFromGitHub,
curl,
gnutls,
}:
factorPackages.buildFactorVocab {
pname = "bresenham";
version = "dev";
src = fetchFromGitHub {
owner = "Capital-EX";
repo = "bresenham";
rev = "58d76b31a17f547e19597a09d02d46a742bf6808";
hash = "sha256-cfQOlB877sofxo29ahlRHVpN3wYTUc/rFr9CJ89dsME=";
};
meta = {
description = "Bresenham's line interpolation algorithm";
homepage = "https://github.com/Capital-EX/bresenham";
license = lib.licenses.bsd2;
maintainers = with lib.maintainers; [ spacefrogg ];
};
}

View File

@ -582,6 +582,7 @@ mapAliases {
### F ###
factor-lang-scope = throw "'factor-lang-scope' has been renamed to 'factorPackages'"; # added 2024-11-28
fahcontrol = throw "fahcontrol has been removed because the download is no longer available"; # added 2024-09-24
fahviewer = throw "fahviewer has been removed because the download is no longer available"; # added 2024-09-24
fam = throw "'fam' (aliased to 'gamin') has been removed as it is unmaintained upstream"; # Added 2024-04-19

View File

@ -9280,8 +9280,8 @@ with pkgs;
inherit (darwin.apple_sdk.frameworks) Carbon OpenGL;
};
factor-lang-scope = callPackage ../development/compilers/factor-lang/scope.nix { };
factor-lang = factor-lang-scope.interpreter;
factorPackages = callPackage ./factor-packages.nix { };
factor-lang = factorPackages.factor-lang;
far2l = callPackage ../applications/misc/far2l {
inherit (darwin.apple_sdk.frameworks)

View File

@ -0,0 +1,43 @@
{
lib,
pkgs,
overrides ? (self: super: { }),
}:
let
inside =
self:
let
callPackage = pkgs.newScope self;
in
lib.recurseIntoAttrs {
buildFactorApplication =
callPackage ../development/compilers/factor-lang/mk-factor-application.nix
{ };
buildFactorVocab = callPackage ../development/compilers/factor-lang/mk-vocab.nix { };
factor-unwrapped = callPackage ../development/compilers/factor-lang/unwrapped.nix { };
factor-lang = callPackage ../development/compilers/factor-lang/wrapper.nix { };
factor-no-gui = callPackage ../development/compilers/factor-lang/wrapper.nix {
guiSupport = false;
};
factor-minimal = callPackage ../development/compilers/factor-lang/wrapper.nix {
enableDefaults = false;
guiSupport = false;
};
factor-minimal-gui = callPackage ../development/compilers/factor-lang/wrapper.nix {
enableDefaults = false;
};
# Vocabularies
bresenham = callPackage ../development/factor-vocabs/bresenham { };
}
// lib.optionalAttrs pkgs.config.allowAliases {
interpreter = builtins.throw "factorPackages now offers various wrapped factor runtimes (see documentation) and the buildFactorApplication helper.";
};
extensible-self = lib.makeExtensible (lib.extends overrides inside);
in
extensible-self