On Sat, 28 Dec 2024, Divya Ranjan <di...@subvertising.org> wrote: > Hello Oliver, > > Thanks for the elaborate response and apologies for a delayed one from > me, the holidays have been occupied.
Sorry for my very late reply. Last months were very busy for me. I appology in advance for this very long answer. > The build system you present looks really interesting. But can you > list down exactly how it works and how a developer can use it to build > something in Guile using Guix? The build system itself is a collection of Guile modules. It provides tools so that you can craft a build system tailored for your need. Maybe this is too low level for what users want. But this kind of plumbing is what I personally prefer. It could be possible to generate templates to make it more polish. Guix on its own does not play any part in this. After all, I want the build system to work on any distros and I want to minimize dependencies, therefore adding Guix as a dependency is a no-go for now. I personnaly only use Guix for a few things in Libpatch. I have a `dev-env' file which is a thin wrapper around `guix-shell'. I have a `.guix-channel' and a Guile module defining package variants that I want Guix to build in my CI. For example, I have a variant with ASAN, another one with TSAN, etc. I say that Guix does not play any part, but this is my case! Since the build system is a collection of Guile modules, you are free to tailor it to your need. If you want, you can couple it with Guix's module to have a reproducible build system I suppose. I explain further bellow how I've tailored the build system to my needs. > Also, have you ever collected any stats on this? I trust you on the > "orders of magnitude faster", but since you already have a project > using it, if you can report some stats, that'd be nice. I want to be clear that by order of magnitude I meant the configuration part. Autotools is basically doing a fork+execve for every single check it makes. So just changing CFLAGS and reconfiguring a project can be very slow on some systems. My build system also do some fork+execve, but most of the things are done in the same process. The build part itself is limited by the linking process of the libraries, so between Makefile and my build system, there is no difference perceivable by a human. > I also read your blogpost from 2022, glad to see that this is > something you've been using for 2-3 years, have you settled down on a > uniform process? What sort of changes did you make? Back then, I was doing my master thesis. I was doing research on dynamic instrumentation and I knew that I would be very frustated by the limitation of build systems. When you do research, you do a lot of iterations and you need to go fast. The clock is ticking. But, I wanted my project to not be dead after graduation. I wanted it to be a solid project that could be used for production systems. So I needed a build system that allows me to quickly iterate and change the project configuration, while being robust whenever the research is done. I figured that writing Guile is so easy that it was probably faster to just write a build system from scratch then trying to search on the internet "How to do X with Y" whenever I hit a limitation of say autotools. Needless to say debugging these build systems is also a nightmare (just have a look at cmake backtrace). Turns out, this decision of mine was a good choice for me and I have been very happy with it. So I settled down on a collection of Guile modules like I mentioned earlier. I figured that there were no point on forcing my view on others. I have my needs and others have their. Having the build system as a library is actually flexibly enough to allow anybody to implement their own build system tailored to their needs. Speaking of my needs, I wanted something as close as the GNU build system. Typically, the `./configure && make && make install' workflow. So I have a `configure' script at the top-level of the project. This script is very important since we don't even know if Guile is on the system or its name (on Fedora, they decided to have guile3.0 instead of guile). The script itself is just using the build system to find various tools and libraries installed on the system. It then export the configuration to some template files (*.in) and configuration files (config.h for C and config.scm for Guile). That last part is actually important. The `config.scm' is used by the project to enable/disable building objects, but also running tests, setting envrionment variables, etc. To support my needs, I wanted to have a Makefile so users could juste do `make' to build the project. The makefile is actually a templated file that call the project REPL: --8<---------------cut here---------------start------------->8--- PROJECT_REPL:=@builddir@/project-repl all: @$(PROJECT_REPL) --emulate-make-flags all Makefile: @$(PROJECT_REPL) --emulate-make-flags all %: @$(PROJECT_REPL) --emulate-make-flags $* --8<---------------cut here---------------end--------------->8--- as you can see, I added a `--emulate-make-flags'. When the project REPL see that, it will parsed the command line arguments of the parent process and try to honor some of them (e.g., -j 4). The project REPL is itself a templated Guile script. It basicaly just forward to a procedure: --8<---------------cut here---------------start------------->8--- #!@GUILE_BIN@ \ -L @srcdir@ -L @srcdir@/src/guile -L @builddir@ -C @builddir@/src/guile -s !# ((@ (project libpatch main) main)) --8<---------------cut here---------------end--------------->8--- As you can see, the main procedure is not part of the build system itself, but is part of the Libpatch project. Afterall, the build system is a library, not an executable. It would not make sens to have a `main' in the build system for that reason. I won't show the main procedure here. You can have a look here if you want <https://git.sr.ht/~old/libpatch/tree/master/item/project/libpatch/main.scm>. Basically what it does is setup the environment of the REPL. Stuffs like `GUILE_AUTO_COMPILE', `TERM', `LD_LIBRARY_PATH', etc. These are derived from the configuration in `config.scm'. It also setup toolchains and flags for building things. For example, `current-c-toolchain' `current-base-cflags', `current-guile-toolchain'. Most importantly, it setup the two very important parameters `srcdir` and `builddir`. These are important because the build system automatically determined the absolute paths of source-files and build-files from these. Finally, the main procedure forward to the REPL. The REPL parses its command line options and execute the wanted action. e.g., all, clean, dist, install, etc. then exit. By default, the REPL start a Guile REPL and wait for further instructions. From there, users can specify what they want to do with the project. For examples: scheme@(project libpatch commands)> (build-project) scheme@(project libpatch commands)> (check-project +pre-inst-env+) scheme@(project libpatch commands)> (check-project +inst-env+) scheme@(project libpatch commands)> (check test-asm +pre-inst-env+) These are all commands defined by the project itself. Again, tailored to my needs. But if you look the `check' command for example: (define (check test environment) (build test environment)) You can see it is just calling the `build' method (defined by the build system) on a test. The test itself is a buildable object as defined by the build system: (define-public test-asm (guile-test-suite (script "tests/test-asm.scm"))) and a Guile test suite is a primitive defined by the build system: --8<---------------cut here---------------start------------->8--- (define-module (project build test-suite guile) #:use-module (ice-9 exceptions) #:use-module (ice-9 string-fun) #:use-module (oop goops) #:use-module (project build) #:use-module (project oop) #:use-module (project test-driver guile) #:export (<guile-test-suite> guile-test-suite)) (define-project-class <guile-test-suite> (<buildable>) (script #:accessor test-suite-script #:init-value #f #:init-keyword #:script #:type string?) (options #:getter test-suite-options #:init-value '() #:init-keyword #:options #:type list?)) ;;; Some initialize methods removed for clarity ... (define-method (build (this <guile-test-suite>)) (build this '())) (define-method (build (this <guile-test-suite>) (env <list>)) (apply run-test (test-suite-script this) #:log-file (output-of this) #:trs-file (string-replace-substring (output-of this) ".log" ".trs") #:environment env (test-suite-options this))) --8<---------------cut here---------------end--------------->8--- So we see that building a `guile-test-suite' object is applying the `run-test' procedure, which is also defined in the build system. But then, since these are all GOOPS methods, you can just overwrite them and use another test-suite runner. I hope this was clear and not too dense. > From what I see in the code you sent is mostly a way to take care of > libraries, defining their inputs, output (.so files) and the flags for > the compiler. If you can elaborate or refer to some documentation, > that'd be nice! Given the historical reason why this build system was made, I have not yet. However, if there is a real interest to make this build system more robust and usable for more cases, I think that would be the one of the next step. Thanks, Olivier > > Regards, > > On 19 December 2024 21:33:25 GMT, Olivier Dion <od...@efficios.com> wrote: >>Hi, >> >>For what it is worth, I have been using my own build system purely in >>Guile for a few years now. I use it in my main project libpatch >>(https://git.sr.ht/~old/libpatch/tree). It is compatible with the >>gnu-build-system (configure && make && make check && make install), but >>it does not have to if you want to diverge from this flow. >> >>However, it is order of magnitude faster than the autotools stuff. >>Configuration for example is a single Guile instance that may do some >>fork, but not that much. Building is also fast, althought it would be >>optimal if fibers were available (I use par-map but the bottleneck is >>due to waitpid). I have plan to add guile-parallel to it instead since >>it is also purely Guile based. >> >>My project is a mix of C, C++ and Guile. Thus I've only added support >>for these, but I it is possible to extend it since it is base on GOOPS. >> >>It is tested on Ubuntu, Debian, Fedora, Arch Linux and Guix. >> >>Here are some snippets of what it looks like: >> >>project/libpatch/build/libraries.scm (C libraries): >>--8<---------------cut here---------------start------------->8--- >>(define-module (project libpatch build libraries) >> #:use-module ((config) #:prefix conf:) >> #:use-module (ice-9 match) >> #:use-module (project build c) >> #:use-module (project utils list) >> #:use-module (srfi srfi-26) >> #:export (libpatch >> libpatch-ftrace)) >> >>(define libpatch-common >> (c-binary >> (inputs >> '("src/lib/libpatch-common/io.c" >> "src/lib/libpatch-common/read.c" >> "src/lib/libpatch-common/sleep.c" >> "src/lib/libpatch-common/write.c")) >> (cppflags >> (list >> (string-append "-I" conf:srcdir "/src/lib/libpatch-common"))) >> (library? #t) >> (shared? #f) >> (output "src/lib/libpatch-common.a"))) >> >>(define libpatch >> (c-binary >> (inputs >> (cons >> libpatch-common >> (cond-list >> '("src/lib/libpatch/core/address.c" >> "src/lib/libpatch/core/attr.c" >> "src/lib/libpatch/core/canon.c" >> "src/lib/libpatch/core/commit.c" >> "src/lib/libpatch/core/configure.c" >> "src/lib/libpatch/core/const.c" >> "src/lib/libpatch/core/coverage.c" >> "src/lib/libpatch/core/disable.c" >> "src/lib/libpatch/core/disasm.c" >> "src/lib/libpatch/core/drop.c" >> "src/lib/libpatch/core/dump.c" >> "src/lib/libpatch/core/dwarf.c" >> "src/lib/libpatch/core/dynamic.c" >> "src/lib/libpatch/core/enable.c" >> "src/lib/libpatch/core/fini.c" >> "src/lib/libpatch/core/gc.c" >> "src/lib/libpatch/core/global.c" >> "src/lib/libpatch/core/init.c" >> "src/lib/libpatch/core/integrity.c" >> "src/lib/libpatch/core/last-error.c" >> "src/lib/libpatch/core/make.c" >> "src/lib/libpatch/core/olx.c" >> "src/lib/libpatch/core/panic.c" >> "src/lib/libpatch/core/patch.c" >> "src/lib/libpatch/core/resolve.c" >> "src/lib/libpatch/core/states.c" >> "src/lib/libpatch/core/thread.c" >> "src/lib/libpatch/core/tls.c" >> "src/lib/libpatch/core/trampoline.c" >> "src/lib/libpatch/core/wxe.c" >> "src/lib/libpatch/core/page-allocator.c") >> ((string=? conf:arch "x86_64") >> "src/lib/libpatch/x86_64/const.c" >> "src/lib/libpatch/x86_64/disasm.c" >> "src/lib/libpatch/x86_64/dwarf.c" >> "src/lib/libpatch/x86_64/dynamic.c" >> "src/lib/libpatch/x86_64/generic-handlers.S" >> "src/lib/libpatch/x86_64/init.c" >> "src/lib/libpatch/x86_64/patch.c" >> "src/lib/libpatch/x86_64/ret-handlers.S")))) >> (external-dependencies >> (list conf:capstone >> conf:libdw >> conf:libolx >> conf:liburcu-bp)) >> (cppflags (list >> (string-append "-I" conf:srcdir "/src/lib/libpatch") >> (string-append "-I" conf:srcdir "/src/lib/libpatch-common") >> (string-append "-I" conf:srcdir "/src/lib/libpatch/" conf:arch >> "/include") >> "-DLIBPATCH_CORE")) >> (cflags '("-fvisibility=hidden")) >> (libs '("-pthread")) >> (shared? #t) >> (library? #t) >> (output "src/lib/libpatch.so") >> (install-location conf:libdir))) >> >>(define libpatch-ftrace >> (c-binary >> (enabled? conf:build-libpatch-ftrace) >> (inputs >> (list >> libpatch >> "src/lib/libpatch-ftrace/libpatch-ftrace.c")) >> (external-dependencies >> (list conf:lttng-ust)) >> (cppflags >> (list (string-append "-I" conf:srcdir "/src/lib/libpatch-ftrace"))) >> (cflags (list "-fvisibility=hidden")) >> (shared? #t) >> (library? #t) >> (output "src/lib/libpatch-ftrace.so") >> (install-location conf:libdir))) >>--8<---------------cut here---------------end--------------->8--- >> >>project/libpatch/build/bindings.scm (Guile bindings to Libpatch): >>--8<---------------cut here---------------start------------->8--- >>(define-module (project libpatch build bindings) >> #:use-module ((config) #:prefix conf:) >> #:use-module (project build) >> #:use-module (project build guile) >> #:use-module (project libpatch build libraries) >> #:export (bindings)) >> >>(define guile-go-dir >> (string-append conf:libdir "/guile/3.0/site-ccache/libpatch")) >> >>(define guile-sources >> '("src/guile/libpatch/ffi.scm" >> "src/guile/libpatch/patch.scm")) >> >>(define guile-modules >> (map >> (lambda (source) >> (guile-module >> (inputs (list source libpatch)) >> (load-paths (list >> (string-append >> (builddir) "/src/guile") >> (string-append >> (srcdir) "/src/guile"))) >> (install-location guile-go-dir))) >> guile-sources)) >> >>(define bindings >> guile-modules) >>--8<---------------cut here---------------end--------------->8--- >> >> >>configure (compatible with configure.ac): >>--8<---------------cut here---------------start------------->8--- >>#!/bin/sh >>#-*-Scheme-*- >>GUILE="$(command -v guile || command -v guile3.0)" >> >>if [ -z "$GUILE" ]; then >> echo "Missing guile executable." >> exit 1 >>fi >> >>DIR=$(dirname "$0") >>THIS_PATH=$(realpath "$DIR") >> >>exec $GUILE -L "$THIS_PATH" --no-auto-compile -e main -s "$0" "$@" >>!# >> >>(use-modules >> (ice-9 exceptions) >> (ice-9 match) >> (project configure) >> (project configure config-file) >> (project configure guess) >> (project configure option) >> (project configure package) >> (project configure template-file) >> (project configure toolchain) >> (project configure variable) >> (project file-system search) >> (project progress) >> (project utils colors) >> (srfi srfi-1) >> (srfi srfi-26) >> (system base target)) >> >>(define (make-simple-action name value) >> (lambda* (this-opt _ #:key variables #:allow-other-keys) >> (let ((var (assoc-ref variables name))) >> (if var >> (set-variable-value! var value) >> (raise-exception >> (make-exception >> (make-programming-error) >> (make-exception-with-irritants name) >> (make-exception-with-message >> "Unknown variable"))))))) >> >>(define dyninst-allowed? #t) >>(define liteinst-allowed? #t) >>(define lttng-allowed? #t) >> >>(define* (has-dyninst? #:key packages #:allow-other-keys) >> (and >> dyninst-allowed? >> (package-exists? >> (assoc-ref packages "dyninst")))) >> >>(define* (has-liteinst? #:key packages #:allow-other-keys) >> (and >> liteinst-allowed? >> (package-exists? >> (assoc-ref packages "liteinst")))) >> >>(define* (has-lttng-ust? #:key packages #:allow-other-keys) >> (and >> lttng-allowed? >> (package-exists? >> (assoc-ref packages "lttng-ust")))) >> >>(define (support-flags? . flags) >> (lambda* (#:key variables #:allow-other-keys) >> (apply >> toolchain-support-flags? >> (variable-value (assoc-ref variables "CC")) >> flags))) >> >>(define libpatch-configuration >> (configuration >> (unique-file "dev-env") >> (arguments (cdr (program-arguments))) >> (packages >> (list >> (package >> (name "capstone")) >> (package >> (name "libdw") >> (minimum-version "0.158")) >> (package >> (name "libolx")) >> (package >> (name "liburcu-bp")) >> (package >> (name "lttng-ust") >> (required? #f)) >> (package >> (name "dyninst") >> (resolver >> (lambda (this) >> (let* ((lib (find-library "libdyninstAPI.so")) >> (header (find-header "BPatch.h")) >> (exists? (and lib header #t))) >> (set! (package-exists? this) exists?) >> (when exists? >> (set! (package-libs-only-l this) "-ldyninstAPI") >> (set! (package-libs-only-L this) >> (string-append "-L" (dirname lib))) >> (set! (package-cflags-only-I this) >> (string-append "-I" (dirname header))))))) >> (required? #f)) >> (package >> (name "liteinst") >> (resolver >> (lambda (this) >> (let* ((lib (find-library "libliteinst.so")) >> (header (find-header "liteinst.hpp")) >> (exists? (and lib header #t))) >> (set! (package-exists? this) exists?) >> (when exists? >> (set! (package-libs-only-l this) "-lliteinst") >> (set! (package-libs-only-L this) >> (string-append "-L" (dirname lib))) >> (set! (package-cflags-only-I this) >> (string-append "-I" (dirname header))))))) >> (required? #f)))) >> (variables >> (append >> (list >> (variable >> (name "LIBPATCH_VERSION") >> (value "1.0.0")) >> (variable >> (name "GUILE_BIN") >> (value >> (delay >> (or >> (find-binary/progress "guile") >> (find-binary/progress "guile3.0") >> (push-error! >> (make-exception >> (make-external-error) >> (make-exception-with-irritants "guile") >> (make-exception-with-message >> "missing required binary"))))))) >> (variable >> (name "GUILD_BIN") >> (value >> (delay >> (or >> (find-binary/progress "guild") >> (find-binary/progress "guild3.0") >> (push-error! >> (make-exception >> (make-external-error) >> (make-exception-with-irritants "guild") >> (make-exception-with-message >> "missing required binary"))))))) >> (variable >> (name "CC") >> (value (delay (guess-c-toolchain)))) >> (variable >> (name "CXX") >> (value (delay (guess-c++-toolchain #:required? #f)))) >> (variable >> (name "arch") >> (value (delay (target-cpu)))) >> (variable >> (name "build-benchmarks") >> (value #t)) >> (variable >> (name "tsan-native-benchmarks") >> (value #f)) >> (variable >> (name "build-libpatch-ftrace") >> (value has-lttng-ust?)) >> (variable >> (name "build-libpatch-coverage") >> (value #t)) >> (variable >> (name "build-libpatch-integrity") >> (value #t)) >> (variable >> (name "build-manpages") >> (value >> (delay (and (find-binary/progress "emacs") #t)))) >> (variable >> (name "has-man") >> (value >> (delay (and (find-binary/progress "man") #t)))) >> (variable >> (name "manpages-source-highlight") >> (value >> (delay (and (find-binary/progress "source-highlight") #t)))) >> (variable >> (name "has-dyninst") >> (value has-dyninst?)) >> (variable >> (name "has-gdb-inproctrace") >> (value (delay >> (and (find-binary/progress "gdb") >> (find-library "libinproctrace.so"))))) >> (variable >> (name "has-liteinst") >> (value has-liteinst?)) >> (variable >> (name "has-csmith") >> (value >> (delay (and (find-binary/progress "csmith") #t)))) >> (variable >> (name "csmith-include-directory") >> (value >> (delay >> (and=> (find-header "csmith/csmith.h") dirname)))) >> (variable >> (name "environ") >> (value (delay (environ))))) >> %standard-directory-variables)) >> (options >> (append >> (list >> (option >> (switch "disable-ftrace-build") >> (synopsis "do no build libpatch-ftrace.so") >> (action (make-simple-action "build-libpatch-ftrace" #f))) >> (option >> (switch "disable-patch-coverage-build") >> (synopsis "do not build libpatch-coverage.so") >> (action (make-simple-action "build-libpatch-coverage" #f))) >> (option >> (switch "disable-patch-integrity-build") >> (synopsis "do not build libpatch-integrity.so") >> (action (make-simple-action "build-libpatch-integrity" #f))) >> (option >> (switch "enable-tsan-on-native-benchmarks") >> (synopsis "enable TSAN for native benchmarks") >> (action (make-simple-action "tsan-native-benchmarks" #t))) >> (option >> (switch "without-manpages") >> (synopsis "disable manpages generation") >> (action (make-simple-action "build-manpages" #f))) >> (option >> (switch "without-lttng") >> (synopsis "disable any usage of LTTng") >> (action (lambda _ (set! lttng-allowed? #f)))) >> (option >> (switch "without-dyninst") >> (synopsis "disable any usage of Dyninst for benchmarking") >> (action (lambda _ (set! dyninst-allowed? #f)))) >> (option >> (switch "without-liteinst") >> (synopsis "disable any usage of LiteInst for benchmarking") >> (action (lambda _ (set! liteinst-allowed? #f)))) >> (option >> (switch "without-benchmarks") >> (synopsis "do not compile benchmarks") >> (action (make-simple-action "build-benchmarks" #f)))) >> %standard-directory-options)) >> (templates >> (list >> (template-file >> (input "aux/Makefile.in") >> (output "Makefile")) >> (template-file >> (input "aux/project-repl.in") >> (output "project-repl") >> (mode #o744)) >> (template-file >> (input "src/lib/pkgconfig/libpatch.pc.in")) >> (template-file >> (input "src/bin/patch-ftrace.in") >> (mode #o744)) >> (template-file >> (input "src/bin/patch-coverage.in") >> (mode #o744)) >> (template-file >> (input "src/bin/patch-integrity.in") >> (mode #o744)) >> (template-file >> (input "scripts/debug-test.in") >> (mode #o744)))) >> (config-files >> (list >> (c-config-file >> (path ".config.h") >> (namespace "CONFIG_")) >> (scm-config-file >> (path "config.scm") >> (namespace "config")))) >> (status-file >> "config.status"))) >> >>(define (main args) >> (with-exception-handler >> (lambda (exn) >> (if (eq? 'quit (exception-kind exn)) >> (raise-exception exn) >> (begin >> (print-exception (current-error-port) >> #f >> (exception-kind exn) >> (exception-args exn)) >> (primitive-exit EXIT_FAILURE)))) >> (lambda () >> (call-with-values >> (lambda () >> (configure libpatch-configuration)) >> (lambda (variables _ errors) >> (with-nest-progress >> "features summary" >> (for-each >> (match-lambda >> ((feature-name . feature-description) >> (let ((name+feature (assoc feature-name variables))) >> (if name+feature >> (progress "~a ~a" >> (if (cdr name+feature) >> (colorize-string "OK" %enabled-color) >> (colorize-string "NO" %disabled-color)) >> feature-description) >> (raise-exception >> (make-exception >> (make-exception-with-origin >> "Features summary") >> (make-programming-error) >> (make-exception-with-irritants feature-name) >> (make-exception-with-message >> "Unknown feature"))))))) >> '(("build-benchmarks" . "compile benchmarks") >> ("build-libpatch-ftrace" . "compile libpatch-ftace.so") >> ("build-libpatch-coverage" . "compile libpatch-coverage.so") >> ("build-libpatch-integrity" . "compile >> libpatch-integrity.so") >> ("build-manpages" . "generate man pages")))) >> (exit (if (null? errors) >> EXIT_SUCCESS >> EXIT_FAILURE))))))) >>--8<---------------cut here---------------end--------------->8--- >> >> >>On Thu, 19 Dec 2024, Divya Ranjan <di...@subvertising.org> wrote: >>> Hello Guix, >>> >>> The other day, after being frustrated of build systems (auto-tools, meson, >>> maven etc.), I wondered why doesn’t Guix which has such powerful tools >>> within it (`guix build`, `guix pack` etc.) also not have a purely >>> Guile-based build tool? After all, our goal is to make deployment, and >>> building both more declarative and away from the all-too-familiar >>> “dependency hell”. >>> >>> I am not exactly sure how I want to go with this, but I want to extend (if >>> needed) the capabilities of Guix, to allow the developer of a package to >>> use it also to build the package effectively replacing existing build >>> tools. Since we already have build-system, instead of executing make (or >>> whatever other tool) commands from it, we could modify it to itself have >>> all those things that a Makefile would have. >>> >>> The developer would use Guile to declare their build config, I am again not >>> sure what this might exactly look like, but can’t we have it such that we >>> provide the developer with some tools to _declare_ a custom and >>> package-specific build-system in Guile (just like our familiar >>> gnu-build-system), but this is purely in Guile and executes whatever >>> commands, path declarations and other interactions (such as calling gcc) >>> directly from Guile and not by just calling `make`. I haven’t thought >>> through this clearly, but even if this doesn’t work, the main idea I’d like >>> to propose is to fully replace existing build-tools by making a new Guile >>> build tool to work alongside Guix. >>> >>> Ideally, once the developer has a build config ready, one can just wrap it >>> up with a package definition in Guile, just like the ones we create to >>> package something upstream. This package definition can then be used in >>> `guix build -f package.scm` to result in a fully transactional building >>> process that focuses not on getting out of dependency hell, but just >>> declaring your config right. And all of this without having to learn yet >>> another build tool that might disappear, and of course, without leaving the >>> comfortable world of Lisp (Scheme). >>> >>> I was indicated by others that such an idea has previously been conceievd >>> among Guix developers themselves, namely as a GSoC proposal[0]. I couldn’t >>> find if that has progressed towards anything, nor could find anything in >>> the mailing list. I did see Pjotr volunteering to mentor for it, I’ve CC-ed >>> them to see if they’re still interested in such a project. Meanwhile, I’d >>> like input from other Guix core developers on what they think of this, and >>> if they could provide me with some leads on where to go with this. >>> >>> >>> [0]: https://libreplanet.org/wiki/Group:Guix/GSoC-2024 >>> >>> Regards, >>> -- >>> Divya Ranjan, >>> Philosophy, Mathematics, Libre Software. >>> >>-- >>Olivier Dion >>EfficiOS Inc. >>https://www.efficios.com > > Divya Ranjan, Mathematics, Philosophy and Libre Software -- Olivier Dion EfficiOS Inc. https://www.efficios.com