diff mbox series

[bug#65486,v2] syscalls: Add support for musl libc

Message ID 20230909130548.31083-2-soeren@soeren-tempel.net
State New
Headers show
Series [bug#65486,v2] syscalls: Add support for musl libc | expand

Commit Message

Sören Tempel Sept. 9, 2023, 1:04 p.m. UTC
From: Sören Tempel <soeren@soeren-tempel.net>

This commit allows using Guix on a foreign distro which uses musl libc,
for example, Alpine Linux. Such a distro is detected via the new
linux-musl? variable based on the %host-type.

Using the new linux-musl? variable, we can now implement musl-specific
quirks. The two compatibility problems I encountered in this regard are
that musl dose not export a readdir64 and statfs64 symbol. On musl,
these two functions are implemented as CPP macros that expand to
readdir/statfs. For this reason, a case-distinction was added.

The existing linux? variable is now set to a truth value if the
host-system is either a linux-gnu or a linux-musl. A new linux-gnu?
variable can be used to detect linux-gnu systems.

The patch has been tested on Alpine Linux and is already used for the
downstream Guix package shipped in Alpine Linux's package repository.

* guix/build/syscalls.scm (linux-gnu?): New variable.
* guix/build/syscalls.scm (linux-musl?): New variable.
* guix/build/syscalls.scm (linux?): Truth value on musl or GNU Linux.
* guix/build/syscalls.scm (readdir-procedure): Support musl libc.
* guix/build/syscalls.scm (statfs): Support musl libc.

Signed-off-by: Sören Tempel <soeren@soeren-tempel.net>
---
Changes since v1: Also add special handling for musl libc to the statfs
procedure. Instead of checking the %host-type, it may also be possible to
the lack of statfs64/readdir64 symbols during ./configure time.

 guix/build/syscalls.scm | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

Comments

Ludovic Courtès Sept. 11, 2023, 9:09 p.m. UTC | #1
Hi,

soeren@soeren-tempel.net skribis:

> From: Sören Tempel <soeren@soeren-tempel.net>
>
> This commit allows using Guix on a foreign distro which uses musl libc,
> for example, Alpine Linux. Such a distro is detected via the new
> linux-musl? variable based on the %host-type.
>
> Using the new linux-musl? variable, we can now implement musl-specific
> quirks. The two compatibility problems I encountered in this regard are
> that musl dose not export a readdir64 and statfs64 symbol. On musl,
> these two functions are implemented as CPP macros that expand to
> readdir/statfs. For this reason, a case-distinction was added.
>
> The existing linux? variable is now set to a truth value if the
> host-system is either a linux-gnu or a linux-musl. A new linux-gnu?
> variable can be used to detect linux-gnu systems.
>
> The patch has been tested on Alpine Linux and is already used for the
> downstream Guix package shipped in Alpine Linux's package repository.

[...]

> -(define linux? (string-contains %host-type "linux-gnu"))
> +(define linux-gnu?  (string-contains %host-type "linux-gnu"))
> +(define linux-musl? (string-contains %host-type "linux-musl"))
> +(define linux?      (or linux-gnu? linux-musl?))
>  
>  (define-syntax define-statfs-flags
>    (syntax-rules (linux hurd)
> @@ -905,7 +907,11 @@ (define-c-struct %statfs                          ;<bits/statfs.h>
>    (spare            (array fsword 4)))
>  
>  (define statfs
> -  (let ((proc (syscall->procedure int "statfs64" '(* *))))
> +  (let ((proc (syscall->procedure int (cond
> +                                        (linux-gnu?  "statfs64")
> +                                        (linux-musl? "statfs")
> +                                        (else (error "unknown linux variant")))

I think this is misleading because this has to do with the C library,
not with the kernel (“linux variant”).

For example, GNU/Hurd uses the same C library as GNU/Linux, and both
should use “statfs64”, “readdir64”, etc.  So what we want to check is
whether we’re using the GNU libc or Musl, regardless of the kernel.

Now, instead of checking the libc’s identity, we could check whether
“statfs64” is available, and if not, fall back to “statfs”.

WDYT?

Thanks,
Ludo’.
Sören Tempel Sept. 13, 2023, 10:23 a.m. UTC | #2
Hi Ludovic,

Ludovic Courtès <ludo@gnu.org> wrote:
> I think this is misleading because this has to do with the C library,
> not with the kernel (“linux variant”).
> 
> For example, GNU/Hurd uses the same C library as GNU/Linux, and both
> should use “statfs64”, “readdir64”, etc.

Oh, right! I totally forgot about GNU/Hurd, thanks for pointing that out.

> So what we want to check is whether we’re using the GNU libc or Musl,
> regardless of the kernel.

Keep in mind that—contrary to glibc—musl only supports Linux and not
GNU/Hurd. Therefore, it should be sufficient to simply check for a
linux-musl host and then use statfs/readdir over statfs64/readdir64:

	(let ((proc (syscall->procedure (if linux-musl?
	                                      "readdir"
	                                      "readdir64"))))
	  ........

Would that be acceptable?

> Now, instead of checking the libc’s identity, we could check whether
> “statfs64” is available, and if not, fall back to “statfs”.

You mean using a GNU ./configure check? That would be possible. However,
I think we also need to check somehow that readdir/statfs return values
are struct-layout compatible with the readdir64/statfs64 versions used
by glibc.

Unfortunately, I am not deeply familiar with GNU autotools. Is there a
similar feature-check in the Guile code base already that I could use as
a source of inspiration? Maybe the if expression outlined above would
be sufficient for now and we can improve upon that later?

Greetings,
Sören
Ludovic Courtès Sept. 13, 2023, 8:39 p.m. UTC | #3
Hi,

Sören Tempel <tempel@uni-bremen.de> skribis:

> Ludovic Courtès <ludo@gnu.org> wrote:

[...]

>> So what we want to check is whether we’re using the GNU libc or Musl,
>> regardless of the kernel.
>
> Keep in mind that—contrary to glibc—musl only supports Linux and not
> GNU/Hurd. Therefore, it should be sufficient to simply check for a
> linux-musl host and then use statfs/readdir over statfs64/readdir64:
>
> 	(let ((proc (syscall->procedure (if linux-musl?
> 	                                      "readdir"
> 	                                      "readdir64"))))
> 	  ........
>
> Would that be acceptable?

You could call it ‘musl?’ instead, to (hopefully) convey we’re
interested in the C library specifically.

>> Now, instead of checking the libc’s identity, we could check whether
>> “statfs64” is available, and if not, fall back to “statfs”.
>
> You mean using a GNU ./configure check?

No no, I meant something like:

  (or (false-if-exception (dynamic-func "readdir64" (dynamic-link)))
      (dynamic-func "readdir" (dynamic-link)))

Of course, it’s not as simple as this because we’d rather have it
integrated with ‘syscall->procedure’ (maybe by adding an
#:alternative-name argument for the Musl name?), but you get the idea.

HTH!

Ludo’.
diff mbox series

Patch

diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index d947b010d3..416fdc768c 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -836,7 +836,9 @@  (define-record-type <file-system>
 (define-syntax fsword                             ;fsword_t
   (identifier-syntax long))
 
-(define linux? (string-contains %host-type "linux-gnu"))
+(define linux-gnu?  (string-contains %host-type "linux-gnu"))
+(define linux-musl? (string-contains %host-type "linux-musl"))
+(define linux?      (or linux-gnu? linux-musl?))
 
 (define-syntax define-statfs-flags
   (syntax-rules (linux hurd)
@@ -905,7 +907,11 @@  (define-c-struct %statfs                          ;<bits/statfs.h>
   (spare            (array fsword 4)))
 
 (define statfs
-  (let ((proc (syscall->procedure int "statfs64" '(* *))))
+  (let ((proc (syscall->procedure int (cond
+                                        (linux-gnu?  "statfs64")
+                                        (linux-musl? "statfs")
+                                        (else (error "unknown linux variant")))
+                                      '(* *))))
     (lambda (file)
       "Return a <file-system> data structure describing the file system
 mounted at FILE."
@@ -1232,7 +1238,12 @@  (define closedir*
 
 (define (readdir-procedure name-field-offset sizeof-dirent-header
                            read-dirent-header)
-  (let ((proc (syscall->procedure '* "readdir64" '(*))))
+  (let ((proc (syscall->procedure '*
+                                  (cond
+                                    (linux-gnu?  "readdir64")
+                                    (linux-musl? "readdir")
+                                    (else (error "unknown linux variant")))
+                                  '(*))))
     (lambda* (directory #:optional (pointer->string pointer->string/utf-8))
       (let ((ptr (proc directory)))
         (and (not (null-pointer? ptr))