Subject: [bug#54239] [PATCH v2 1/5] gnu: Add cross-llvm.

From: Pierre Langlois <[email-masked]>
Date: Sat, 05 Mar 2022 14:00:32 +0000

Julien Lepiller <[email-masked]> writes:

> * gnu/packages/llvm.scm (cross-llvm): New variable.
> ---
>  gnu/packages/llvm.scm | 21 +++++++++++++++++++--
>  1 file changed, 19 insertions(+), 2 deletions(-)
>
> diff --git a/gnu/packages/llvm.scm b/gnu/packages/llvm.scm
> index eb949bed1b..d6e9846699 100644
> --- a/gnu/packages/llvm.scm
> +++ b/gnu/packages/llvm.scm
> @@ -18,7 +18,7 @@
>  ;;; Copyright © 2020 Jakub Kądziołka <[email-masked]>
>  ;;; Copyright © 2021 Maxime Devos <[email-masked]>
>  ;;; Copyright © 2020, 2021 Maxim Cournoyer <[email-masked]>
> -;;; Copyright © 2021 Julien Lepiller <[email-masked]>
> +;;; Copyright © 2021, 2022 Julien Lepiller <[email-masked]>
>  ;;; Copyright © 2021 Lars-Dominik Braun <[email-masked]>
>  ;;; Copyright © 2021 Guillaume Le Vaillant <[email-masked]>
>  ;;; Copyright © 2021 Maxim Cournoyer <[email-masked]>
> @@ -74,7 +74,8 @@ (define-module (gnu packages llvm)
>    #:use-module (srfi srfi-1)
>    #:use-module (ice-9 match)
>    #:export (make-lld-wrapper
> -            system->llvm-target))
> +            system->llvm-target
> +            cross-llvm))
>  
>  (define* (system->llvm-target #:optional
>                                (system (or (and=> (%current-target-system)
> @@ -99,6 +100,22 @@ (define* (system->llvm-target #:optional
>               ("i686"        => "X86")
>               ("i586"        => "X86"))))
>  
> +(define (cross-llvm llvm target)
> +  "Return a native LLVM package that targets a different system.  The resulting
> +libraries are running on the host but target a different system by default.
> +This packge can be used to control clang's default target."
> +  (package
> +    (inherit llvm)
> +    (arguments
> +     (substitute-keyword-arguments (package-arguments llvm)
> +      ((#:configure-flags flags)
> +       #~(append
> +           (list
> +             (string-append "-DLLVM_DEFAULT_TARGET_TRIPLE=" #$target)
> +             (string-append "-DLLVM_TARGET_ARCH="
> +                            #$(system->llvm-target (gnu-triplet->nix-system target))))

While playing with trying to use this series to build a WebAssembly
cross-compiler, I /think/ we have a bug here, and also in master, when
it comes to setting LLVM_TARGET_ARCH.

It's a bit confusing though, the documentation is as follows:

--8<---------------cut here---------------start------------->8---
LLVM_TARGET_ARCH:STRING
    LLVM target to use for native code generation. This is required for
    JIT generation. It defaults to “host”, meaning that it shall pick
    the architecture of the machine where LLVM is being built. If you
    are cross-compiling, set it to the target architecture name.
--8<---------------cut here---------------end--------------->8---

It's not clear what naming scheme the variable needs, is it the internal
LLVM target name or the triplet? I think it's architecture part of the
triplet...ish? But instead we pass it the internal target name.

It still works at the moment because whenever LLVM_TARGET_ARCH is used,
the cmake code looks quite permissive and tries to do the right thing by
turning the string lowercase and matching common names (hence the "...ish" :-) ).

https://github.com/llvm/llvm-project/blob/24f88f57de588817bd21e799e2ac1069c025674c/llvm/cmake/config-ix.cmake#L420

So if I try and add WebAssembly into the mix, the architecure name is
wasm32, but the LLVM target is called WebAssembly, and the lowercase
version of it doesn't work :-( 

| nix-system | LLVM target | LLVM target lowercase | Does it match? |
|------------+-------------+-----------------------+----------------|
| aarch64    | AArch64     | aarch64               | Y              |
| armhf      | ARM         | arm                   | Y              |
| mips64el   | Mips        | mips                  | Y              |
| powerpc    | PowerPC     | powerpc               | Y              |
| riscv      | RISCV       | riscv                 | Y              |
| x86_64     | X86         | x86                   | Y              |
| i686       | X86         | x86                   | Y              |
| i586       | X86         | x86                   | Y              |
|------------+-------------+-----------------------+----------------|
| wasm32     | WebAssembly | webassembly           | N :-(          |

I /think/ we might want to use the nix-system instead of the LLVM target
for LLVM_TARGET_ARCH:

--8<---------------cut here---------------start------------->8---
(string-append "-DLLVM_TARGET_ARCH=" #$(gnu-triplet->nix-system target)))
--8<---------------cut here---------------end--------------->8---

But I'm not sure, it might not work for mips64el for example, so we
could need yet-another-mapping.

Given it works as it is today with the current set of supported targets,
we don't necessarily need to fix it now. I'll be happy to take a look
later when eventually adding support for the wasm32-wasi toolchain in
Guix.

Thanks,
Pierre