I would like to create a Guix package of the Fortran Package Manager (FPM).
This is the recommended compilation procedure, taken (with slight modifications) from the FPM documentation.
git clone https://github.com/fortran-lang/fpm
cd fpm
git checkout v0.10.1
fpm
:wget https://github.com/fortran-lang/fpm/releases/download/v0.8.0/fpm-0.8.0.F90 -0 fpm.F90
mkdir -p build/bootstrap
gfortran -J build/bootstrap -o build/bootstrap/fpm fpm.F90
./build/bootstrap/fpm install [--prefix custom/path]
This command will use the local fpm.toml
file to compile and install the latest release of fpm
.
I think the best approach is to use the trivial-build-system
, due to the specificity of the compilation process.
So far, I have a package file with this content:
;; fortran-fpm.scm
(define-module (fortran-fpm)
#:use-module (guix packages)
#:use-module (guix git-download)
#:use-module (guix build-system trivial)
#:use-module (guix licenses)
#:use-module (guix gexp)
#:use-module (guix build utils)
#:use-module (guix utils)
;; #:use-module (guix store)
#:use-module (guix download)
;; #:use-module (guix modules)
;; #:use-module (guix derivations)
#:use-module (gnu packages guile)
#:use-module (gnu packages gcc))
(define-public fortran-fpm
(package
(name "fortran-fpm")
(version "0.10.1")
(source
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/fortran-lang/fpm.git")
(commit version)))
(sha256
(base32
"1sh6mn1ajnyf1a5flcf8fpixn5al2spqpaxgw9g1yp4p36mfd8wz"))))
(build-system trivial-build-system)
(arguments
(list
#:builder
(with-imported-modules
'((guix build utils))
#~(begin
(use-modules (guix build utils))
(let* ((source (assoc-ref %build-inputs "source"))
(fpm-bootstrap-url "https://github.com/fortran-lang/fpm/releases/download/v0.8.0/fpm-0.8.0.F90")
(bootstrap-build-dir "/build/bootstrap")
(fpm-bootstrap-file "fpm.F90"))
(chdir source)
(invoke "wget" fpm-bootstrap-url "-O"
fpm-bootstrap-file)
(mkdir-p bootstrap-build-dir)
(invoke "gfortran" "-J" bootstrap-build-dir "-o" (string-append bootstrap-build-dir "/fpm") fpm-bootstrap-file)
(invoke (string-append bootstrap-build-dir "/fpm") "install"))
))))
(inputs
`(("gfortran-toolchain" ,gfortran)))
(synopsis "Fortran Package Manager")
(description
"Fortran Package Manager (fpm) is a package manager and build system for Fortran.
Its key goal is to improve the user experience of Fortran programmers.
It does so by making it easier to build your Fortran program or library,
run the executables, tests, and examples, and distribute it as a dependency to other Fortran projects.
Fpm's user interface is modeled after Rust's Cargo, so if you're familiar with that tool,
you will feel at home with fpm.
Fpm's long term vision is to nurture and grow the ecosystem of modern Fortran applications and libraries.")
(home-page "https://fpm.fortran-lang.org")
(license expat)))
fortran-fpm ;; just for the purpose of testing it with --install-from-file
I try to install using guix package -f fortran-fpm.scm --keep-failed
. The build process fails, I extract the .drv.bz2
produced by the build process. Its content is:
In execvp of wget: No such file or directory
Backtrace:
2 (primitive-load "/gnu/store/z2qpwsicr8wffhcig4m4c2ypyg1?")
In ice-9/eval.scm:
619:8 1 (_ #(#(#(#(#<directory (guile-user) 7ffff78?> ?) ?) ?) ?))
In guix/build/utils.scm:
822:6 0 (invoke "wget" "https://github.com/fortran-lang/fpm/re?" ?)
guix/build/utils.scm:822:6: In procedure invoke:
ERROR:
1. &invoke-error:
program: "wget"
arguments: ("https://github.com/fortran-lang/fpm/releases/download/v0.8.0/fpm-0.8.0.F90" "-O" "fpm.F90")
exit-status: 127
term-signal: #f
stop-signal: #f
So, apparently, wget
is not in scope (first line of the log), am I wrong?
Note also that the kept derivation (if it is the correct term) folder /tmp/guix-build-fortran-fpm-0.10.1.drv-0/
is empty.
I was also considering url-fetch
and download-to-store
, instead of resorting to a system call, but I don't know how to make either of them work.
Any other comment is welcome.
After following Noé Lopez's suggestions and some debugging with Copilot's assistance, I finally managed to get guix
install the package with the following package definition:
(define-module (fortran-fpm)
#:use-module (guix packages)
#:use-module (guix git-download)
#:use-module (guix build-system copy)
#:use-module (guix licenses)
#:use-module (guix gexp)
#:use-module (guix download)
#:use-module (gnu packages gcc))
(define-public fortran-fpm
(package
(name "fortran-fpm")
(version "0.10.1")
(source
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/fortran-lang/fpm.git")
(commit version)))
(sha256
(base32
"1sh6mn1ajnyf1a5flcf8fpixn5al2spqpaxgw9g1yp4p36mfd8wz"))))
(build-system copy-build-system)
(arguments
(list
#:phases
#~(modify-phases
%standard-phases
(add-after 'patch-generated-file-shebangs 'build
(lambda* (#:key #:allow-other-keys)
(let* ((source (assoc-ref %build-inputs "source"))
(build-dir (string-append source "/../build"))
(bootstrap-dir
(string-append build-dir "/bootstrap"))
(fpm-bootstrap-file
#$(this-package-input "bootstrap"))
(out (assoc-ref %outputs "out")))
(mkdir-p bootstrap-dir)
(invoke "gfortran"
"-J" bootstrap-dir
"-o" (string-append bootstrap-dir "/fpm")
fpm-bootstrap-file)
(invoke (string-append bootstrap-dir "/fpm")
"install"
"--prefix" out))))
(add-before
'build 'patch-fpm-toml
(lambda* (#:key inputs #:allow-other-keys)
(use-modules (ice-9 textual-ports) (srfi srfi-1))
(let* ((deps-dir "local-deps")
(deps `(("toml-f" . "toml-f")
("M_CLI2" . "M_CLI2")
("fortran-regex" . "fortran-regex")
("jonquil" . "jonquil")
("fortran-shlex" . "fortran-shlex"))))
(mkdir-p deps-dir)
;; Symlink each dependency into local-deps/
(for-each
(lambda (dep)
(let* ((name (car dep))
(dir (assoc-ref inputs name)))
(symlink dir (string-append deps-dir "/" (cdr dep)))))
deps)
(substitute*
"fpm.toml"
(("toml-f\\.git.*")
(string-append "toml-f.path = \"" deps-dir "/toml-f\"\n"))
(("M_CLI2\\.git.*")
(string-append "M_CLI2.path = \"" deps-dir "/M_CLI2\"\n"))
(("fortran-regex\\.git.*")
(string-append "fortran-regex.path = \"" deps-dir "/fortran-regex\"\n"))
(("jonquil\\.git.*")
(string-append "jonquil.path = \"" deps-dir "/jonquil\"\n"))
(("fortran-shlex\\.git.*")
(string-append "fortran-shlex.path = \"" deps-dir "/fortran-shlex\"\n"))
(("^.*\\.rev.*") "")
(("^.*\\.tag.*") "")
)))
)
(delete 'install)
)
)
)
(inputs
`(("gfortran-toolchain" ,gfortran)
("bootstrap"
,(origin
(method url-fetch)
(uri "https://github.com/fortran-lang/fpm/releases/download/v0.10.1/fpm-0.10.1.F90")
(sha256
(base32
"1jp1hh5yjz3ghk5f1ixz06x6jl8mhh3hm89vla4yi9y2c1dx0lvm"))
(file-name "fpm.F90")))
;; ("git" ,git)
("toml-f"
,(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/toml-f/toml-f")
(commit "d7b892b1d074b7cfc5d75c3e0eb36ebc1f7958c1")))
(sha256
(base32
"07r78dk0q7xxrh3fjfrsx5jmf6ap21b4d5qld6ga3awki0cm75z8"))))
("M_CLI2"
,(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/urbanjost/M_CLI2.git")
(commit "7264878cdb1baff7323cc48596d829ccfe7751b8")))
(sha256
(base32
"06y7zndb0qcnyq7rxwhq0vv0j4dzkdw9hqphkp13k1zqf3vz8z28"))))
("fortran-regex"
,(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/perazz/fortran-regex")
(commit "1.1.2")))
(sha256
(base32
"183vxa1082kkg48rl75nxkm8j67vxpak3347dfzfbbxi0wyfklba"))))
("jonquil"
,(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/toml-f/jonquil")
(commit "4fbd4cf34d577c0fd25e32667ee9e41bf231ece8")))
(sha256
(base32
"1zk3rpl5npk4qaslcbp9nay6p9dsl3sqv2m0zc6337mxqa4dmjm0"))))
("fortran-shlex"
,(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/perazz/fortran-shlex")
(commit "2.0.0")))
(sha256
(base32
"0sygyjqwxyh974bmp8n5bxjs9nsdfavy5k3vhmx2v9bbl31jqk8a"))))
))
(synopsis "Fortran Package Manager")
(description
"Fortran Package Manager (fpm) is a package manager and build system for Fortran.
Its key goal is to improve the user experience of Fortran programmers.
It does so by making it easier to build your Fortran program or library,
run the executables, tests, and examples, and distribute it as a dependency to other Fortran projects.
Fpm's user interface is modeled after Rust's Cargo, so if you're familiar with that tool,
you will feel at home with fpm.
Fpm's long term vision is to nurture and grow the ecosystem of modern Fortran applications and libraries.")
(home-page "https://fpm.fortran-lang.org")
(license expat)))
Big thank you to Noé Lopez again :D
Indeed wget is not in scope, it would have to be in your inputs (in this case native-inputs) to be in scope.
Additionally, guix does not allow downloading files from the build environment for reproducibility. You need to have it as an input, either in the origin or in the inputs. In this way, its hash is checked and you are sure to be always using the same file (it might be modified on the server, breaking the package in the future). So for example, you could do:
(define-public fortran-fpm
(package
(name "fortran-fpm")
(version "0.10.1")
(source
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/fortran-lang/fpm.git")
(commit version)))
(sha256
(base32
"1sh6mn1ajnyf1a5flcf8fpixn5al2spqpaxgw9g1yp4p36mfd8wz"))))
(build-system trivial-build-system)
(arguments
(list
#:builder
(with-imported-modules
'((guix build utils))
#~(begin
(use-modules (guix build utils))
(let* ((source (assoc-ref %build-inputs "source"))
(bootstrap-build-dir "/build/bootstrap")
(fpm-bootstrap-file #$(this-package-input "bootstrap")))
(chdir source)
(mkdir-p bootstrap-build-dir)
(invoke "gfortran" "-J" bootstrap-build-dir "-o" (string-append bootstrap-build-dir "/fpm") fpm-bootstrap-file)
(invoke (string-append bootstrap-build-dir "/fpm") "install"))
))))
(inputs
`(("gfortran-toolchain" ,gfortran)
("bootstrap" ,(origin …)))
(synopsis "Fortran Package Manager")
(description
"Fortran Package Manager (fpm) is a package manager and build system for Fortran.
Its key goal is to improve the user experience of Fortran programmers.
It does so by making it easier to build your Fortran program or library,
run the executables, tests, and examples, and distribute it as a dependency to other Fortran projects.
Fpm's user interface is modeled after Rust's Cargo, so if you're familiar with that tool,
you will feel at home with fpm.
Fpm's long term vision is to nurture and grow the ecosystem of modern Fortran applications and libraries.")
(home-page "https://fpm.fortran-lang.org")
(license expat)))
Lastly, using trivial-build-system is probably not a good idea, as you will be missing out on a lot of things gnu-build-system sets up for you. I recommend you use the copy-build-system (which is based on gnu-build-system) and use modify-phases
to add your build steps, you can find a lot of examples of this in the Guix source.