-
-
Save egasimus/0254dcd67f95f262aa6e133794738392 to your computer and use it in GitHub Desktop.
See also: | |
* https://github.com/NixOS/nixpkgs/issues/49626 | |
* https://gist.github.com/telent/4a92294a767656759959006fe8440122 |
({ lib, newScope, stdenv, pkgs }: let | |
# nicer aliases | |
derive = stdenv.mkDerivation; | |
concat = builtins.concatStringsSep " "; | |
# vendored libuvc: don't build, just make sources available | |
libuvc-src = derive { | |
name = "libuvc-src"; | |
# using fetchgit instead fetchFromGitHub because | |
# the .git directory is needed by arcan's cmake scripts | |
src = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/libuvc.git"; | |
rev = "v0.0.6"; | |
sha256 = "1jdmiinsd91nnli5hgcn9c6ifj0s6ngbyjwm0z6fim4f8krnh0sf"; | |
}; | |
nativeBuildInputs = with pkgs; [ git ]; | |
# fetchgit strips all refs, leaving just a fetchgit branch | |
# but cmake needs to check out the ref called 'master': | |
installPhase = '' | |
git tag master | |
cp -r . $out/ | |
cd $out | |
''; | |
}; | |
# cmake flags pointing to locations of arcan headers | |
arcanIncludeDirs = arcan: [ | |
"-DARCAN_SHMIF_INCLUDE_DIR=${arcan}/include/arcan/shmif" | |
"-DARCAN_TUI_INCLUDE_DIR=${arcan}/include/arcan" | |
]; | |
# cmake flags pointing to locations of libusb1 headers and binaries | |
libusbDirs = libusb1: [ | |
"-DLIBUSB_1_INCLUDE_DIRS=${libusb1.dev}/include/libusb-1.0" | |
"-DLIBUSB_1_LIBRARIES=${libusb1}/lib/libusb-1.0.so" | |
]; | |
in lib.makeScope newScope (self: with self; let | |
mkArcanAppl = { name, src, applRoot }: callPackage ({ pkgs }: derive { | |
name = name; | |
src = src; | |
nativeBuildInputs = with pkgs; [ envsubst ]; | |
buildInputs = [ arcan ]; | |
installPhase = '' | |
mkdir -p $out/${name} $out/bin | |
cp -r ./${applRoot}/* $out/${name}/ | |
Arcan=${arcan} Appls=$out Appl=${name} envsubst \ | |
< ${./Arcan.wrapper} \ | |
> $out/bin/arcan.${name} | |
chmod +x $out/bin/arcan.${name} | |
''; | |
}) {}; | |
arcanRev = "280bb2f1b39da4465e391158d7debba4a8c168c6"; | |
arcanCoreSrc = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/arcan.git"; | |
rev = arcanRev; | |
sha256 = "0pzgb8s74na9wr8dy3bgvv23fry2zny4w6kzjyq1q5lnsgma0zqn"; | |
}; | |
in { | |
# arcan core: | |
arcan = callPackage ({ pkgs }: derive { | |
name = "arcan"; | |
src = arcanCoreSrc; | |
patches = [ ./Arcan.nosuid.patch ]; # nix refuses to build suid binaries | |
postUnpack = '' # add vendored libuvc | |
mkdir -p ./arcan/external/git/libuvc | |
pushd ./arcan/external/git/ | |
shopt -s dotglob nullglob # bashism: * now also matches dotfiles | |
cp -r ${libuvc-src}/* libuvc/ | |
shopt -u dotglob nullglob # phases are stateful | |
popd | |
''; | |
nativeBuildInputs = with pkgs; [ cmake gcc git ]; | |
buildInputs = with pkgs; [ | |
apr | |
espeak-classic | |
file | |
ffmpeg-full | |
freetype | |
harfbuzzFull | |
leptonica | |
libGL | |
libdrm | |
libjpeg | |
libusb1 | |
libvncserver | |
libxkbcommon | |
luajit | |
lzma | |
mesa | |
openal | |
SDL2 | |
sqlite | |
tesseract | |
vlc | |
wayland | |
wayland-protocols | |
xorg.libxcb | |
xorg.xcbutil | |
xorg.xcbutilwm | |
]; | |
PKG_CONFIG_PATH = concat [ # make wayland protocols available | |
"${pkgs.wayland-protocols}/share/pkgconfig" | |
"${pkgs.libusb1.dev}/lib/pkgconfig" | |
]; | |
CFLAGS = concat [ # don't warn on read()/write() without a format | |
"-Wno-format" # (Arcan code uses them on SHMIFs) | |
"-Wno-format-security" | |
]; | |
cmakeFlags = concat ( | |
# cmake won't be able to find these paths on its own: | |
(libusbDirs pkgs.libusb) ++ [ | |
"-DDRM_INCLUDE_DIR=${pkgs.libdrm.dev}/include/libdrm" | |
"-DGBM_INCLUDE_DIR=${pkgs.libGL.dev}/include" | |
"-DWAYLANDPROTOCOLS_PATH=${pkgs.wayland-protocols}/share/wayland-protocols" | |
# enable features: | |
"-DVIDEO_PLATFORM=egl-dri" | |
"-DSHMIF_TUI_ACCEL=ON" | |
"-DENABLE_LWA=ON" | |
"-DNO_BUILTIN_OPENHMD=ON" | |
"-DHYBRID_SDL=On" | |
"-DHYBRID_HEADLESS=On" | |
"-DFSRV_DECODE_UVC=Off" | |
# optional | |
"-DVERBOSE=ON" | |
#"--debug-output" | |
#"--trace" | |
"../src" | |
]); | |
}) {}; | |
# arcan utilities: | |
acfgfs = callPackage ({ pkgs }: derive { | |
name = "acfgfs"; | |
src = arcanCoreSrc; | |
nativeBuildInputs = with pkgs; [ cmake gcc git ]; | |
buildInputs = [ arcan ] ++ (with pkgs; [ fuse3 ]); | |
cmakeFlags = concat ((arcanIncludeDirs arcan) ++ [ "../src/tools/acfgfs" ]); | |
}) {}; | |
aclip = callPackage ({ pkgs }: derive { | |
name = "aclip"; | |
src = arcanCoreSrc; | |
nativeBuildInputs = with pkgs; [ cmake gcc git pkg-config ]; | |
buildInputs = [ arcan ]; | |
PKG_CONFIG_PATH = concat [ "${arcan}/lib/pkgconfig" ]; | |
cmakeFlags = concat ((arcanIncludeDirs arcan) ++ [ "../src/tools/aclip" ]); | |
}) {}; | |
aloadimage = callPackage ({ pkgs }: derive { | |
name = "aloadimage"; | |
src = arcanCoreSrc; | |
nativeBuildInputs = with pkgs; [ cmake gcc git ]; | |
buildInputs = [ arcan ]; | |
cmakeFlags = concat ((arcanIncludeDirs arcan) ++ [ "../src/tools/aloadimage" ]); | |
}) {}; | |
shmmon = callPackage ({ pkgs }: derive { | |
name = "shmmon"; | |
src = arcanCoreSrc; | |
nativeBuildInputs = with pkgs; [ cmake gcc git ]; | |
buildInputs = [ arcan ]; | |
cmakeFlags = concat ((arcanIncludeDirs arcan) ++ [ "../src/tools/shmmon" ]); | |
}) {}; | |
# TODO: provide <hidapi/hidapi.h> include path | |
#vrbridge = callPackage ({ pkgs }: derive { | |
#name = "vrbridge"; | |
#src = ./arcan; | |
#nativeBuildInputs = with pkgs; [ cmake gcc git pkg-config ]; | |
#buildInputs = [ arcan ] ++ (with pkgs; [ libusb1 ]); | |
#cmakeFlags = concat ( | |
#(arcanIncludeDirs arcan) ++ | |
#(libusbDirs pkgs.libusb1) ++ | |
#[ "../src/tools/vrbridge" ] | |
#); | |
#}) {}; | |
# arcan appls | |
awb = mkArcanAppl { | |
name = "awb"; | |
src = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/awb.git"; | |
rev = "271ef7ffd7f24569d2f836198e4c96b8c617e372"; | |
sha256 = "1jdmiinsd91nnli5hgcn9c6ifj0s6ngbyjwm0z6fim4f8krnh0s8"; | |
}; | |
applRoot = ""; | |
}; | |
prio = mkArcanAppl { | |
name = "prio"; | |
src = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/prio.git"; | |
rev = "c3f97491339d15f063d6937d5f89bcfaea774dd1"; | |
sha256 = "0igsbzp0df24f856sfwzcgcfanxlvxmw5v94gqq2p42kwardfmm9"; | |
}; | |
applRoot = ""; | |
}; | |
durden = mkArcanAppl { | |
name = "durden"; | |
src = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/durden.git"; | |
rev = "bfbfe68bc325a5fb06ea1869a99404e277291a89"; | |
sha256 = "11zfd1cf0sh63a9wrm5n129jmb5m0ibfh51ryjjjgxgx901k2qhi"; | |
}; | |
applRoot = "durden"; | |
}; | |
safespaces = mkArcanAppl { | |
name = "safespaces"; | |
src = pkgs.fetchgit { | |
leaveDotGit = true; | |
url = "https://github.com/letoram/safespaces.git"; | |
rev = "https://github.com/letoram/safespaces/commit/58eef59afba091293cab4d2b156e725f75d92eaf"; | |
sha256 = "1jdmiinsd91nnli5hgcn9c6ifj0s6ngbyjwm0z6fim4f8krnh0s9"; | |
}; | |
applRoot = "safespaces"; | |
}; | |
})) |
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt | |
index 34a0d20a..f90ce0a6 100644 | |
--- a/src/CMakeLists.txt | |
+++ b/src/CMakeLists.txt | |
@@ -740,7 +740,6 @@ if (VIDEO_PLATFORM STREQUAL "egl-dri") | |
amsg("${CL_YEL}egl-dri+privsep${CL_RST}\t${CL_GRN}installing SUID${CL_RST}") | |
install(TARGETS arcan DESTINATION bin | |
PERMISSIONS | |
- SETUID | |
OWNER_WRITE OWNER_READ OWNER_EXECUTE | |
GROUP_READ GROUP_EXECUTE | |
WORLD_READ WORLD_EXECUTE |
#!/bin/sh | |
pushd $Arcan/bin # otherwise `arcan doesn't find system-binaries` | |
trap "popd" EXIT # let's not leave the user stranded, though | |
./arcan \ | |
-T ../share/arcan/scripts \ | |
-p ../share/arcan/resources \ | |
-t $Appls $@ $Appl |
# A minimal configuration.nix containing just Arcan. | |
{pkgs,...}:{ | |
environment.systemPackages = let | |
arcan = (pkgs.callPackage (import ./Arcan.nix) {}); | |
in [ | |
arcan.arcan | |
arcan.acfgfs | |
arcan.aloadimage | |
arcan.aclip | |
arcan.shmmon | |
arcan.prio | |
arcan.durden | |
]; | |
users.groups.input.members = ["user"]; | |
} |
@payasrelekar Feel free to fork my nixpkgs PR or start a new one. I realized I need to be way more organized in order to productively contribute to nixpkgs. I don't have that kind of mental clarity right now.
To be perfectly honest, my failure to even find the entrypoint of the most basic Arcan appl so I can start putting things on the screen dissuaded me somewhat from pursuing this further. I wish I had something more to contribute than initiative, but right now that's in everyone else's hands too.
@egasimus Have you joined arcan's IRC channel or discord server? Discord server is a pretty new addition, but the IRC channel is decently active.
As for the entrypoint, I'd recommend checking the small tutorial series found under arcan's wiki page. It mentions there, that all Lua appls have entry point in script [APPL_NAME].lua
in function matching the appl's name. So for durden you'll find durden.lua
with function durden()
defined somewhere within it.
That structure is slightly more thought out than it might initially seem. With the forced prefix for all engine->script calls and applnames being unique means that you can embed an appl in an appl. Durden or Safespaces can pull in Pipeworld and have it structurally work without any namespace collisions.
Sure, I got that far. Another project I find inspirational is Deno, which has similar "non-standard" entry points (#!
doesnt work with deno run
unless using non-POSIX /usr/bin/env -S deno run
) - in both cases I've tried to make my Nix builds include a single-command invocation with no parameters that covers the default case (e.g. arcan.durden
, etc).
But my problem lies elsewhere - last time I tried writing an appl I started from the simplest "bouncing logo" example included, and still couldn't figure out what the main function is/does. Like I said, maybe I just haven't approached this with sufficient clarity of mind - I find myself lacking the time to achieve it these days :-(
Lua is kinda new to me but it supports a traditional imperative style, right? Guess I sorta expected a main loop with a draw function; if there's one in there I must've missed it by a long shot. As a contrived example, Processing gets this "right" (as far as my intuition is concerned anyway).
I understand the two projects differ vastly in scope, but I'm just looking for a way to put things on a screen (first and foremost for my own personal use) that has better semantics than a canvas or a X11 WM, and better performance than a browser. If I ever manage to do that, I'd be happy to write a tutorial on how to get the whole stack running and how to start developing with it - unless someone already beat me to it?
When I first encountered Arcan, I hoped it would be easy to write bindings to it for another language (JS, Rust - the usual suspects; Arcan+Deno+some form of hot module reloading sounds like a blissful way to build a personal GUI from scratch) and have that structurally work with no collisions.
Is there something about Lua's namespacing that necessitates a more thought out naming scheme than just slapping things together? I'm accustomed to expect composability at the function level, not the module level though I understand different languages come with different approaches.
As it stands, I'm quite sad to admit that I found the code that I'm supposed to interface with in order to build something on Arcan nearly impenetrable. (And that's from someone who enjoys writing Nix builds!)
I'll try to find some time to check out the community - I've stood by the sidelines long enough, and Pipeworld really blew my mind, so guess it's about time I saw what y'all are really up to :-)
First - a problem with the NixOS module itself:
It does not build arcan_lwa (which is used under the hood to run arcan applications inside of other arcan applications). The reason for that is, most likely, that the in-source version of OpenAL is ignored (external/clone.sh). That one has patches which adds an 'arcan' audio backend that should not be upstreamed or be integrated with system OpenAL (which normal arcan uses). The dependency will eventually be refactored out and swapped for something slimmer, but not today.
Second, as to your general remarks:
The development style in Lua is very much up to the engine integration, hence why it is rarely a standalone language itself and does not fit very well with such a mold. Arcan forces a more functional/event-driven nature rather than giving you control over an imperative main loop - you are almost guaranteed to screw up something like a while(true){ process_input(); move_things_around(); if (time_to_draw) draw_frame(); }. Regular game developers do so repeatedly (locking animations and logic to %30Hz or so and breaking spectacularly on variable frame rate displays and so on). On a system graphics level, this problem is much more complex with many soft failure modes.
The applname() entry point is a substitution for the '.html' file in your normal web application -- any up-front loading of resources and necessary allocations should be done there. Before that point none of the actual APIs are exposed - leaving much less room for obfuscation and funny tricks for concealing intent. As a side note, that is also one of the reasons why normal "loadstring(str)()" kind of functions are not exposed. If you harden the setup a bit (separate appl, appl-out namespaces, block the .so form of system_load()) dynamic coding tricks for packers/unpackers and other shady tactics are closed off.
The Lua part isn't simply a language that is substitutable by anything else, in reality it is treated as a 'safe' keyword for C. Lua itself (as in arcan_lua.c) is a bit of a misnomer as quite a few functions in that behemoth do provide additional abstractions and encode idioms that evolved over time. There is a lot of work behind how its specific VM interface interacts with the rest of the engine when it comes to error and crash recovery, as well as GC cadence and so on.
If anything, other language support should be done as part of the scripting space and keep actual execution out of process more akin to how WMs work in X11. A single appl or hookscript that uses open_nonblock to create an socket, then generate bindings from doc/*.lua. Unfortunately those files were not written with the intent of being used as an IDL, and it is a slow burn task reworking that format in this direction where the overloaded arguments each have their expected types explicitly written out and so on. What helps is that the macro in the arcan_lua.c that marks every entry-point also has a #define hack at the top of the source unit to emit a trace, so running that against something like durden/pipeworld would give decent statistics of the more useful functions versus the edge case ones.
function myapp()
logo = load_image("logo.png")
blend_image(logo, 1.0, 50)
move_image(logo, VRESW, 0, 100, INTERP_SMOOTHSTEP)
move_image(logo, 0, 0, 100, INTERP_SINE)
image_transform_cycle(logo, true)
end
store as myapp/myapp.lua, shove logo.png into the myapp folder or somewhere accessible with arcan -p /path/to/resource/base myapp and done.
This would have your logo move from the left edge to the right edge indefinitely (though missing a myapp_display_state handler to deal with window resizes changing the VRESW/VRESH constants). It was never a strong intent that the Lua API would be used directly (albeit that's basically what I do), but rather emitted by a translator from something else. I have reconsidered somewhat since then, and a 'REPL-' style wrapper for easier experimentation is on the todo along with something that targets pine* and RPI400 etc. specifically to get back to a sort of "power on" 10 print "hello world" kind of computing.
Hi! @letoram linked this gist in Discord. I've just pushed a commit with a Nix expression what enables building arcan. I haven't tested it out yet, so I don't know if there's any bugs. :)
It's very a WIP, so I just wanted to commit and push as a backup.
EDIT: And it builds arcan_lwa
.
@cipharius thanks, I'll check it out over weekend.
I'm wondering, how far along are we to submitting this work to Nixpkgs?