Hi help-guix,I am trying to write a package for a recent version of docker. Docker packages itself via a Dockerfile, so I figured the build process would be idiosyncratic & probably would not work with the packaged go-build-system. For this reason (and also purely for education) I am trying to write a build-system. I am having a lot of trouble with that!
There are some things I understand clearly. First that since builds happen in the "build environment" that there are differences between "normal code" and "build code", and that you have to wrap "build code" up in a g-expression. This explains some things that are not intuitive to me at first glance, like having to re-import modules. And also that since all build dependencies have to be stated explicitly, that you cannot just assume that any standard utilities are available, you have to make sure you state them explicitly.
I can also see in the manual that build-systems are high level objects, which are compiled to low-level "bags" and then to even lower-level derivations, which the build daemon can, well, build. However I cannot see anywhere a mental picture for how to think of "what is a bag" or even "what is a build system". I get the very most basic thing, that a build system is a bit like a procedure for turning package metadata into a store item, but I cannot see anywhere that logic actually exists. When I go to look inside the actual build system source code (like for copy-build-system or ruby-build-system, which seem relatively simple) I can't find any line of code that says "copy this file from the source to the output" or "run this script" or "ensure these env vars are set" or "ensure these directories exist".
Weirdly I can see the sort of thing I'm imagining in the "Dissecting guix: g-expressions" blog post, but I can't match up the examples there with any of the actually implemented build systems.
For example in copy-build-system, I see the function "lower". It looks roughly like this:
(define* (lower ...) (bag ... (build copy-build)))where the abbreviated parts seem to only be boilerplate. So I go to look at copy-build, which looks to me roughly like this:
(define* (copy-build ...) (define builder #~(copy-build ...) (mlet %store-monad ((guile ...)) (gexp->derivation name builder ...))so I can see where we go from a package to a bag to a derivation. But where does "stuff happen"? Where does the copy-build-system copy things?
I feel like it's bad manners to ask for help without posting code, so I did try writing a docker build system, and it is broken in a way I don't understand. I've written a package and a build system, which I'm running with
guix build -L. -f docker.scmI've attached docker.scm, docker-build-system.scm and the error trace which abbreviates to:
no code for module (guix build-system)This is very confusing to me, because the build systems I am cargo-culting from do not seem to declare this module anywhere, apart from declaring that they do use it. It looks to me like the build process is expecting this module, so it should be in with-imported-modules, but I don't know why the build process expects it, since I don't think I use it in the build code.
Anyway, thank you for reading, hopefully someone can point me in the right direction.
Dan Littlewood
nyk84bln666abm5lpsv1sfkcicjg1p-module-import-compiled.drv.gz
Description: application/gzip
(define-module (docker-build-system)
#:use-module (guix build-system)
#:use-module (guix build-system go)
#:use-module (guix build-system gnu)
#:use-module (guix utils)
#:use-module (guix gexp)
#:use-module (guix monads)
#:use-module (guix packages)
#:use-module (guix store)
#:export (%docker-build-system-modules
lower
docker-build
docker-build-system))
(define %docker-build-system-modules
;; Build-side modules imported by default.
`((docker-build-system)
,@%default-gnu-imported-modules))
(define* (docker-build name inputs
#:key source
(outputs '("out"))
(system (%current-system))
(phases '())
(search-paths '())
(target #f)
(guile #f)
(substitutable? #t)
(imported-modules %docker-build-system-modules)
(modules '((docker-build-system)
(guix build utils))))
"Build docker from SOURCE"
(define builder
(with-imported-modules imported-modules
#~(begin
(use-modules #$@modules)
#$(with-build-variables inputs outputs
#~(docker-build #:source #+source
#:system #$system
#:outputs %outputs
#:inputs %build-inputs
#:search-paths '()
#:phases '())))))
(mlet %store-monad ((guile (package->derivation (or guile (default-guile))
system #:graft? #f)))
(gexp->derivation name builder
#:system system
#:target #f
#:substitutable? substitutable?
#:graft? #f
#:guile-for-build guile)))
(define* (lower name
#:key source inputs native-inputs outputs system target
#:allow-other-keys
#:rest arguments)
"Return a bag for NAME." ; ??
(define private-keywords
'(#:target #:inputs #:native-inputs))
(bag
(name name)
(system system)
(host-inputs `(,@(if source
`(("source" ,source))
'())
,@inputs
,@(standard-packages)))
(build-inputs native-inputs)
(outputs outputs)
(build docker-build)
(arguments (strip-keyword-arguments private-keywords arguments))))
(define docker-build-system
(build-system
(name 'docker)
(description "Build system for docker/moby/etc")
(lower lower)))
(use-modules (docker-build-system)
(guix packages)
(guix download)
(guix licenses))
(define-public docker
(package
(name "docker")
(version "29.8.0")
(source (origin
(method url-fetch)
(uri (string-append "https://github.com/moby/moby/archive/refs/tags/docker-"
version ".tar.gz"))
(sha256
(base32
"0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
(build-system docker-build-system)
(synopsis "The Moby Project - a collaborative project for the container ecosystem to assemble container-based systems")
(description "Moby is an open-source project created by Docker to enable and accelerate software containerization.")
(home-page "https://mobyproject.org/")
(license asl2.0)))
docker
