diff mbox series

[bug#54239,v2,2/5] gnu: Add cross-clang.

Message ID de91f63243153229e558311bb91f688ca8e177fb.1646387919.git.julien@lepiller.eu
State New
Headers show
Series [bug#54239,v2,1/5] gnu: Add cross-llvm. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Julien Lepiller March 4, 2022, 9:59 a.m. UTC
* gnu/packages/llvm.scm (cross-clang): New variable.
---
 gnu/packages/llvm.scm | 144 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 1 deletion(-)

Comments

M March 4, 2022, 7:53 p.m. UTC | #1
Julien Lepiller schreef op vr 04-03-2022 om 10:59 [+0100]:
> +           ((#:configure-flags _)
> +            `(list "-DCLANG_INCLUDE_TESTS=True"

This is a bit fragile.  If the definition of the 'clang' package mad
the #:configure-flags a gexp, then this would fail because of the
'sexp->gexp' optimisation in 'cmake-build-system'.  As such, I
recommend #~(list "-DCLANG_INCLUDE_TESTS=True" ...) here instead of
sexp quasiquoting.

Greetings,
Maxime.
M March 4, 2022, 7:54 p.m. UTC | #2
Julien Lepiller schreef op vr 04-03-2022 om 10:59 [+0100]:
> +                         `((substitute* "lib/Driver/Tools.cpp"
> +                             ;; Patch the 'getLinuxDynamicLinker' function so that
> +                             ;; it uses the right dynamic linker file name.
> +                             (("/lib64/ld-linux-x86-64.so.2")
> +                              (string-append libc ,(glibc-dynamic-linker))))

Do we need something similar for non-x86-64 architectures as well?

Greetings,
Maxime.
M March 4, 2022, 7:56 p.m. UTC | #3
Julien Lepiller schreef op vr 04-03-2022 om 10:59 [+0100]:
> +                        (else
> +                         `((substitute* "lib/Driver/Tools.cpp"
> +                             ;; Patch the 'getLinuxDynamicLinker' function so that
> +                             ;; it uses the right dynamic linker file name.
> +                             (("/lib64/ld-linux-x86-64.so.2")
> +                              (string-append libc ,(glibc-dynamic-linker))))

Shouldn't we use the architecture that the cross-clang is targetting be
passed to 'glibc-dynamic-linker' instead of the architecture that the
cross-clang will run on?

Greetings,
Maxime.
M March 4, 2022, 8 p.m. UTC | #4
Julien Lepiller schreef op vr 04-03-2022 om 10:59 [+0100]:
> +  #:use-module (gnu packages cross-base)

Most of the time, we aren't cross-compiling.  So WDYT of autoloading
this module?  It's rather unusual to do this in (gnu packages ...), but
there does not appear to be any reason for this to be impossible to do.

Another option would be using 'module-ref' like (guix build-system ...)
does.

Greetings,
Maxime.
Julien Lepiller March 5, 2022, 8:30 a.m. UTC | #5
Le Fri, 04 Mar 2022 20:54:22 +0100,
Maxime Devos <maximedevos@telenet.be> a écrit :

> Julien Lepiller schreef op vr 04-03-2022 om 10:59 [+0100]:
> > +                         `((substitute* "lib/Driver/Tools.cpp"
> > +                             ;; Patch the 'getLinuxDynamicLinker'
> > function so that
> > +                             ;; it uses the right dynamic linker
> > file name.
> > +                             (("/lib64/ld-linux-x86-64.so.2")
> > +                              (string-append libc
> > ,(glibc-dynamic-linker))))  
> 
> Do we need something similar for non-x86-64 architectures as well?
> 
> Greetings,
> Maxime.

I don't know about that. This phase is mostly copied from clang itself.
Pierre Langlois March 5, 2022, 4:05 p.m. UTC | #6
Hi,

A couple of comments from me while testing this trying to build a
cross-toolchain with llvm-13.  Hope this is helpful!

Julien Lepiller <julien@lepiller.eu> writes:

> * gnu/packages/llvm.scm (cross-clang): New variable.
> ---
>  gnu/packages/llvm.scm | 144 +++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 143 insertions(+), 1 deletion(-)
>
> diff --git a/gnu/packages/llvm.scm b/gnu/packages/llvm.scm
> index d6e9846699..c277e2ac35 100644
> --- a/gnu/packages/llvm.scm
> +++ b/gnu/packages/llvm.scm
> @@ -54,6 +54,7 @@ (define-module (gnu packages llvm)
>    #:use-module (guix build-system trivial)
>    #:use-module (gnu packages)
>    #:use-module (gnu packages base)
> +  #:use-module (gnu packages cross-base)
>    #:use-module (gnu packages gcc)
>    #:use-module (gnu packages bootstrap)           ;glibc-dynamic-linker
>    #:use-module (gnu packages check)               ;python-lit
> @@ -75,7 +76,9 @@ (define-module (gnu packages llvm)
>    #:use-module (ice-9 match)
>    #:export (make-lld-wrapper
>              system->llvm-target
> -            cross-llvm))
> +            cross-llvm
> +            cross-clang
> +            clang-for-target))
>  
>  (define* (system->llvm-target #:optional
>                                (system (or (and=> (%current-target-system)
> @@ -1023,6 +1026,145 @@ (define-public clang-runtime clang-runtime-13)
>  (define-public clang clang-13)
>  (define-public clang-toolchain clang-toolchain-13)
>  
> +(define* (cross-clang target
> +                      #:key
> +                      (libc (cross-libc target))
> +                      (xgcc (cross-gcc target
> +                              #:xbinutils (cross-binutils target)
> +                              #:libc (cross-libc target)))
> +                      (clang clang))
> +  "Return a cross-clang compiler for target."
> +  (define cross-clang-aux
> +    (mlambda (target libc xgcc clang)
> +      (package
> +        (inherit clang)
> +        (name (string-append "clang-cross-" target))
> +        (version (package-version clang))
> +        ;; Support the same variables as clang, even in cross-compilation context.
> +        ;; Clang does not make a difference between native and cross-compilation.
> +        (search-paths
> +          (list
> +            (search-path-specification
> +              (variable "CROSS_LIBRARY_PATH")
> +              (files '("lib")))
> +            (search-path-specification
> +              (variable "CROSS_C_INCLUDE_PATH")
> +              (files '("include")))
> +            (search-path-specification
> +              (variable "CROSS_CPLUS_INCLUDE_PATH")
> +              (files '("include/c++" "include")))))
> +        (native-search-paths '())
> +        (arguments
> +         (substitute-keyword-arguments (package-arguments clang)
> +           ((#:configure-flags _)
> +            `(list "-DCLANG_INCLUDE_TESTS=True"
> +                   (string-append "-DGCC_INSTALL_PREFIX="
> +                                  (assoc-ref %build-inputs "cross-gcc-lib"))
> +                   (string-append "-DC_INCLUDE_DIRS="
> +                                  (assoc-ref %build-inputs "target-libc")
> +                                  "/include")))
> +           ((#:phases phases)
> +            `(modify-phases ,phases
> +               (add-after 'unpack 'add-missing-libdir
> +                 (lambda _
> +                   ;; cross-gcc installs its libraries in <target>/lib instead of
> +                   ;; lib.
> +                   (substitute* "lib/Driver/ToolChain.cpp"
> +                     (("\"-L\"\\) \\+ LibPath\\)\\);")
> +                      ,(string-append "\"-L\") + LibPath));
> +  CmdArgs.push_back(Args.MakeArgString(StringRef(\"-L\") + "
> +                                     "StringRef(GCC_INSTALL_PREFIX) + StringRef(\"/"
> +                                     target "/lib\")));
> +  CmdArgs.push_back(Args.MakeArgString(StringRef(\"-rpath=\") + "
> +                                     "StringRef(GCC_INSTALL_PREFIX) + StringRef(\"/"
> +                                     target "/lib\")));")))))
> +               (add-after 'unpack 'support-cross-include-path
> +                 (lambda _
> +                   (substitute* "lib/Driver/ToolChains/Clang.cpp"
> +                     (("C_INCLUDE_PATH") "CROSS_C_INCLUDE_PATH")
> +                     (("CPLUS_INCLUDE_PATH") "CROSS_CPLUS_INCLUDE_PATH"))))
> +               (add-after 'unpack 'support-cross-library-path
> +                 (lambda _
> +                   ;; LIBRARY_PATH is only supported for native builds, but we still
> +                   ;; need it (or CROSS_LIBRARY_PATH to be precise) when
> +                   ;; cross-compiling
> +                   (substitute* "lib/Driver/ToolChains/CommonArgs.cpp"
> +                     (("LIBRARY_PATH\"")
> +                      "LIBRARY_PATH\");
> +  } else {
> +    addDirectoryList(Args, CmdArgs, \"-L\", \"CROSS_LIBRARY_PATH\""))))

Testing this with llvm-13, this substitution doesn't look quite right
and causes the build to fail, they might have removed braces between
versions:
https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/Driver/ToolChains/CommonArgs.cpp#L236

Doing a blame points to this commit, which suggest it's changed with
LLVM 10 release I believe.

https://github.com/llvm/llvm-project/commit/7dbdc8de183e7aa2dc0a9c3a4f473142ddd460bf,

> +               (replace 'set-glibc-file-names
> +                 (lambda* (#:key inputs #:allow-other-keys)
> +                   (let ((libc (assoc-ref inputs "target-libc"))
> +                         (compiler-rt (assoc-ref inputs "clang-runtime"))

Quick question, compiler-rt here is the host's runtime right?  Do we not
need to cross-compile it as well?

It's not always clear to me what is part of compiler-rt vs libc vs
libgcc, it could be target-dependent.  For example when trying to target
WebAssembly, I needed a cross-compiled compiler-rt to provide the
libclang_rt.builtins-wasm32.a library.

> +                         (gcc (assoc-ref inputs "cross-gcc")))
> +                     (setenv "LIBRARY_PATH"
> +                             (string-append
> +                               (assoc-ref inputs "libc") "/lib:" (getenv "LIBRARY_PATH")))
> +                     ,@(cond
> +                        ((version>=? version "6.0")
> +                         `(;; Link to libclang_rt files from clang-runtime.
> +                           (substitute* "lib/Driver/ToolChain.cpp"
> +                             (("getDriver\\(\\)\\.ResourceDir")
> +                              (string-append "\"" compiler-rt "\"")))
> +
> +                           ;; Make "LibDir" refer to <glibc>/lib so that it
> +                           ;; uses the right dynamic linker file name.
> +                           (substitute* "lib/Driver/ToolChains/Linux.cpp"
> +                             (("(^[[:blank:]]+LibDir = ).*" _ declaration)
> +                              (string-append declaration "\"" libc "/lib\";\n"))
> +
> +                             ;; Make clang look for libstdc++ in the right
> +                             ;; location.
> +                             (("LibStdCXXIncludePathCandidates\\[\\] = \\{")
> +                              (string-append
> +                               "LibStdCXXIncludePathCandidates[] = { \"" gcc
> +                               "/include/c++\","))
> +
> +                             ;; Make sure libc's libdir is on the search path, to
> +                             ;; allow crt1.o & co. to be found.
> +                             (("@GLIBC_LIBDIR@")
> +                              (string-append libc "/lib")))))
> +                        (else
> +                         `((substitute* "lib/Driver/Tools.cpp"
> +                             ;; Patch the 'getLinuxDynamicLinker' function so that
> +                             ;; it uses the right dynamic linker file name.
> +                             (("/lib64/ld-linux-x86-64.so.2")
> +                              (string-append libc ,(glibc-dynamic-linker))))
> +
> +                           ;; Link to libclang_rt files from clang-runtime.
> +                           ;; This substitution needed slight adjustment in 3.8.
> +                           ,@(if (version>=? version "3.8")
> +                                 '((substitute* "lib/Driver/Tools.cpp"
> +                                     (("TC\\.getDriver\\(\\)\\.ResourceDir")
> +                                      (string-append "\"" compiler-rt "\""))))
> +                                 '((substitute* "lib/Driver/ToolChain.cpp"
> +                                     (("getDriver\\(\\)\\.ResourceDir")
> +                                      (string-append "\"" compiler-rt "\"")))))
> +
> +                           ;; Make sure libc's libdir is on the search path, to
> +                           ;; allow crt1.o & co. to be found.
> +                           (substitute* "lib/Driver/ToolChains.cpp"
> +                             (("@GLIBC_LIBDIR@")
> +                              (string-append libc "/lib")))))))))))))
> +        (inputs
> +         `(("target-libc" ,libc)
> +           ("cross-gcc-lib" ,xgcc "lib")
> +           ("cross-gcc" ,xgcc)
> +           ,@(package-inputs clang)))
> +        (propagated-inputs
> +          (modify-inputs (package-propagated-inputs clang)
> +            (replace "llvm"
> +              (cross-llvm
> +                (car (assoc-ref (package-propagated-inputs clang) "llvm"))
> +                target)))))))
> +  (cross-clang-aux target libc xgcc clang))
> +
> +(define* (clang-for-target #:optional (clang clang))
> +  (if (%current-target-system)
> +      (cross-clang (%current-target-system) #:clang clang)
> +      clang))
> +
>  (define-public llvm-for-rocm
>    (package
>      ;; Actually based on LLVM 13 as of v4.3, but llvm-12 works just fine.
diff mbox series

Patch

diff --git a/gnu/packages/llvm.scm b/gnu/packages/llvm.scm
index d6e9846699..c277e2ac35 100644
--- a/gnu/packages/llvm.scm
+++ b/gnu/packages/llvm.scm
@@ -54,6 +54,7 @@  (define-module (gnu packages llvm)
   #:use-module (guix build-system trivial)
   #:use-module (gnu packages)
   #:use-module (gnu packages base)
+  #:use-module (gnu packages cross-base)
   #:use-module (gnu packages gcc)
   #:use-module (gnu packages bootstrap)           ;glibc-dynamic-linker
   #:use-module (gnu packages check)               ;python-lit
@@ -75,7 +76,9 @@  (define-module (gnu packages llvm)
   #:use-module (ice-9 match)
   #:export (make-lld-wrapper
             system->llvm-target
-            cross-llvm))
+            cross-llvm
+            cross-clang
+            clang-for-target))
 
 (define* (system->llvm-target #:optional
                               (system (or (and=> (%current-target-system)
@@ -1023,6 +1026,145 @@  (define-public clang-runtime clang-runtime-13)
 (define-public clang clang-13)
 (define-public clang-toolchain clang-toolchain-13)
 
+(define* (cross-clang target
+                      #:key
+                      (libc (cross-libc target))
+                      (xgcc (cross-gcc target
+                              #:xbinutils (cross-binutils target)
+                              #:libc (cross-libc target)))
+                      (clang clang))
+  "Return a cross-clang compiler for target."
+  (define cross-clang-aux
+    (mlambda (target libc xgcc clang)
+      (package
+        (inherit clang)
+        (name (string-append "clang-cross-" target))
+        (version (package-version clang))
+        ;; Support the same variables as clang, even in cross-compilation context.
+        ;; Clang does not make a difference between native and cross-compilation.
+        (search-paths
+          (list
+            (search-path-specification
+              (variable "CROSS_LIBRARY_PATH")
+              (files '("lib")))
+            (search-path-specification
+              (variable "CROSS_C_INCLUDE_PATH")
+              (files '("include")))
+            (search-path-specification
+              (variable "CROSS_CPLUS_INCLUDE_PATH")
+              (files '("include/c++" "include")))))
+        (native-search-paths '())
+        (arguments
+         (substitute-keyword-arguments (package-arguments clang)
+           ((#:configure-flags _)
+            `(list "-DCLANG_INCLUDE_TESTS=True"
+                   (string-append "-DGCC_INSTALL_PREFIX="
+                                  (assoc-ref %build-inputs "cross-gcc-lib"))
+                   (string-append "-DC_INCLUDE_DIRS="
+                                  (assoc-ref %build-inputs "target-libc")
+                                  "/include")))
+           ((#:phases phases)
+            `(modify-phases ,phases
+               (add-after 'unpack 'add-missing-libdir
+                 (lambda _
+                   ;; cross-gcc installs its libraries in <target>/lib instead of
+                   ;; lib.
+                   (substitute* "lib/Driver/ToolChain.cpp"
+                     (("\"-L\"\\) \\+ LibPath\\)\\);")
+                      ,(string-append "\"-L\") + LibPath));
+  CmdArgs.push_back(Args.MakeArgString(StringRef(\"-L\") + "
+                                     "StringRef(GCC_INSTALL_PREFIX) + StringRef(\"/"
+                                     target "/lib\")));
+  CmdArgs.push_back(Args.MakeArgString(StringRef(\"-rpath=\") + "
+                                     "StringRef(GCC_INSTALL_PREFIX) + StringRef(\"/"
+                                     target "/lib\")));")))))
+               (add-after 'unpack 'support-cross-include-path
+                 (lambda _
+                   (substitute* "lib/Driver/ToolChains/Clang.cpp"
+                     (("C_INCLUDE_PATH") "CROSS_C_INCLUDE_PATH")
+                     (("CPLUS_INCLUDE_PATH") "CROSS_CPLUS_INCLUDE_PATH"))))
+               (add-after 'unpack 'support-cross-library-path
+                 (lambda _
+                   ;; LIBRARY_PATH is only supported for native builds, but we still
+                   ;; need it (or CROSS_LIBRARY_PATH to be precise) when
+                   ;; cross-compiling
+                   (substitute* "lib/Driver/ToolChains/CommonArgs.cpp"
+                     (("LIBRARY_PATH\"")
+                      "LIBRARY_PATH\");
+  } else {
+    addDirectoryList(Args, CmdArgs, \"-L\", \"CROSS_LIBRARY_PATH\""))))
+               (replace 'set-glibc-file-names
+                 (lambda* (#:key inputs #:allow-other-keys)
+                   (let ((libc (assoc-ref inputs "target-libc"))
+                         (compiler-rt (assoc-ref inputs "clang-runtime"))
+                         (gcc (assoc-ref inputs "cross-gcc")))
+                     (setenv "LIBRARY_PATH"
+                             (string-append
+                               (assoc-ref inputs "libc") "/lib:" (getenv "LIBRARY_PATH")))
+                     ,@(cond
+                        ((version>=? version "6.0")
+                         `(;; Link to libclang_rt files from clang-runtime.
+                           (substitute* "lib/Driver/ToolChain.cpp"
+                             (("getDriver\\(\\)\\.ResourceDir")
+                              (string-append "\"" compiler-rt "\"")))
+
+                           ;; Make "LibDir" refer to <glibc>/lib so that it
+                           ;; uses the right dynamic linker file name.
+                           (substitute* "lib/Driver/ToolChains/Linux.cpp"
+                             (("(^[[:blank:]]+LibDir = ).*" _ declaration)
+                              (string-append declaration "\"" libc "/lib\";\n"))
+
+                             ;; Make clang look for libstdc++ in the right
+                             ;; location.
+                             (("LibStdCXXIncludePathCandidates\\[\\] = \\{")
+                              (string-append
+                               "LibStdCXXIncludePathCandidates[] = { \"" gcc
+                               "/include/c++\","))
+
+                             ;; Make sure libc's libdir is on the search path, to
+                             ;; allow crt1.o & co. to be found.
+                             (("@GLIBC_LIBDIR@")
+                              (string-append libc "/lib")))))
+                        (else
+                         `((substitute* "lib/Driver/Tools.cpp"
+                             ;; Patch the 'getLinuxDynamicLinker' function so that
+                             ;; it uses the right dynamic linker file name.
+                             (("/lib64/ld-linux-x86-64.so.2")
+                              (string-append libc ,(glibc-dynamic-linker))))
+
+                           ;; Link to libclang_rt files from clang-runtime.
+                           ;; This substitution needed slight adjustment in 3.8.
+                           ,@(if (version>=? version "3.8")
+                                 '((substitute* "lib/Driver/Tools.cpp"
+                                     (("TC\\.getDriver\\(\\)\\.ResourceDir")
+                                      (string-append "\"" compiler-rt "\""))))
+                                 '((substitute* "lib/Driver/ToolChain.cpp"
+                                     (("getDriver\\(\\)\\.ResourceDir")
+                                      (string-append "\"" compiler-rt "\"")))))
+
+                           ;; Make sure libc's libdir is on the search path, to
+                           ;; allow crt1.o & co. to be found.
+                           (substitute* "lib/Driver/ToolChains.cpp"
+                             (("@GLIBC_LIBDIR@")
+                              (string-append libc "/lib")))))))))))))
+        (inputs
+         `(("target-libc" ,libc)
+           ("cross-gcc-lib" ,xgcc "lib")
+           ("cross-gcc" ,xgcc)
+           ,@(package-inputs clang)))
+        (propagated-inputs
+          (modify-inputs (package-propagated-inputs clang)
+            (replace "llvm"
+              (cross-llvm
+                (car (assoc-ref (package-propagated-inputs clang) "llvm"))
+                target)))))))
+  (cross-clang-aux target libc xgcc clang))
+
+(define* (clang-for-target #:optional (clang clang))
+  (if (%current-target-system)
+      (cross-clang (%current-target-system) #:clang clang)
+      clang))
+
 (define-public llvm-for-rocm
   (package
     ;; Actually based on LLVM 13 as of v4.3, but llvm-12 works just fine.