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

Reply via email to