Hi Daniel, Like many Guix build systems, copy-build-system inherits the gnu-build-system. [1] Due to its simplicity, it drops nearly all inherited phases [2] except 'install. [3]
The new 'install phase calls a procedure that is also called "install". It takes an install-plan. [4] Unfortunately, the "install" procedure then shadows its own definition with another procedure called "install". [5]. That second procedure ultimately processes the install plan. [6] I personally find the inheritance in the build systems confusing. I also dislike when programmers shadow definitions. The English language has more words than that! Please feel free to refer to my generic-build-system [7] while you write your own. My build system turns the Guix philosopy inside out: It replaces the implicit phases with procedures that are called from the respective build recipe. (It also wraps executables automatically with Guile wrappers, not Bash, and compiles any Guile modules.) In my view, it's easier to read and use, but people are entitled to their opinions. Good luck! Kind regards Felix [1] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L168 [2] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L169-L172 [3] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L173 [4] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L39 [5] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L142 [6] https://codeberg.org/guix/guix/src/commit/2c4657f9bb181b978f639dc8ef07ee3ceced853c/guix/build/copy-build-system.scm#L162 [7] https://codeberg.org/lechner/juix-channel/src/branch/history/juix/build-system/generic.scm On Mon, Sep 28 2026, Daniel Littlewood wrote: > 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.scm > > I'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
