diff mbox series

[v3] llvm/mesa/rust: simplify llvm-config handling

Message ID 20260612034643.3215188-1-Deepesh.Varatharajan@windriver.com
State Under Review
Headers show
Series [v3] llvm/mesa/rust: simplify llvm-config handling | expand

Commit Message

Varatharajan, Deepesh June 12, 2026, 3:46 a.m. UTC
From: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>

Replace PATH-based llvm-config discovery with explicit sysroot-native
resolution and simplify the target llvm-config wrapper to act as a pure
pass-through while preserving Yocto alternate path handling.

The previous implementation relied on:

* `which -a llvm-config | sed -n 2p`
   which is unreliable in cross-build environments because it only
   searches executables present in $PATH. Native sysroot tools
   (e.g. recipe-sysroot-native llvm-config) are not guaranteed to be
   exposed via PATH, so they may not be discovered at all.

* `echo $base_libdir | sed -n '/lib64/p'`
   which depends on a BitBake variable that may be empty or unset
   in certain build contexts, leading to incorrect libdir selection.

Update the wrapper to:

* Use an @LLVM_CONFIG_PATH@ placeholder that is replaced during the
  build with the appropriate native llvm-config path.
* Detect libdir using filesystem inspection rather than variable
  parsing.
* Preserve `YOCTO_ALTERNATE_EXE_PATH` and
  `YOCTO_ALTERNATE_LIBDIR` handling.
* Delegate all arguments directly to the native llvm-config.

Update rust and mesa recipes to replace the placeholder with the native
llvm-config path during target and nativesdk builds.

Also remove the native llvm-config copy logic and lib/lib64 symlink
workarounds, relying instead on explicit native tool resolution.

Signed-off-by: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>
---
 ...unwind.pc.in-and-llvm-config-scripts.patch | 52 +++----------------
 meta/recipes-devtools/rust/rust_1.96.0.bb     | 52 ++++++-------------
 meta/recipes-graphics/mesa/mesa.inc           | 16 ++++++
 3 files changed, 39 insertions(+), 81 deletions(-)

Comments

Richard Purdie June 12, 2026, 8:39 a.m. UTC | #1
On Thu, 2026-06-11 at 20:46 -0700, Deepesh.Varatharajan@windriver.com wrote:
> From: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>
> 
> Replace PATH-based llvm-config discovery with explicit sysroot-native
> resolution and simplify the target llvm-config wrapper to act as a pure
> pass-through while preserving Yocto alternate path handling.
> 
> The previous implementation relied on:
> 
> * `which -a llvm-config | sed -n 2p`
>    which is unreliable in cross-build environments because it only
>    searches executables present in $PATH. Native sysroot tools
>    (e.g. recipe-sysroot-native llvm-config) are not guaranteed to be
>    exposed via PATH, so they may not be discovered at all.

We always configure PATH to contain the cross scripts and native
sysroot. Is there something which is reconfiguring PATH to skip the
native sysroot?

> * `echo $base_libdir | sed -n '/lib64/p'`
>    which depends on a BitBake variable that may be empty or unset
>    in certain build contexts, leading to incorrect libdir selection.
> 
> Update the wrapper to:
> 
> * Use an @LLVM_CONFIG_PATH@ placeholder that is replaced during the
>   build with the appropriate native llvm-config path.
> * Detect libdir using filesystem inspection rather than variable
>   parsing.
> * Preserve `YOCTO_ALTERNATE_EXE_PATH` and
>   `YOCTO_ALTERNATE_LIBDIR` handling.
> * Delegate all arguments directly to the native llvm-config.
> 
> Update rust and mesa recipes to replace the placeholder with the native
> llvm-config path during target and nativesdk builds.
> 
> Also remove the native llvm-config copy logic and lib/lib64 symlink
> workarounds, relying instead on explicit native tool resolution.
> 
> Signed-off-by: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>
> ---
>  ...unwind.pc.in-and-llvm-config-scripts.patch | 52 +++----------------
>  meta/recipes-devtools/rust/rust_1.96.0.bb     | 52 ++++++-------------
>  meta/recipes-graphics/mesa/mesa.inc           | 16 ++++++
>  3 files changed, 39 insertions(+), 81 deletions(-)
> 
> diff --git a/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch b/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
> index eeb802732b..72ffdc6c1f 100644
> --- a/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
> +++ b/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
> @@ -8,6 +8,7 @@ These are added by OE project
>  Upstream-Status: Inappropriate [ OE-Specific ]
>  
>  Signed-off-by: Khem Raj <raj.khem@gmail.com>
> +Signed-off-by: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>
>  ---
>   libunwind/libunwind.pc.in          |  9 ++++++
>   llvm/tools/llvm-config/llvm-config | 52 ++++++++++++++++++++++++++++++
> @@ -35,56 +36,19 @@ new file mode 100644
>  index 000000000000..6a0dd54b8eab
>  --- /dev/null
>  +++ b/llvm/tools/llvm-config/llvm-config
> -@@ -0,0 +1,52 @@
> +@@ -0,0 +1,15 @@
>  +#!/bin/bash
>  +#
> -+# Wrapper script for llvm-config. Supplies the right environment variables
> -+# for the target and delegates to the native llvm-config for anything else. This
> -+# is needed because arguments like --ldflags, --cxxflags, etc. are set by the
> -+# native compile rather than the target compile.
> ++# The llvm-config wrapper will act as a pure pass-through to the native llvm-config
> ++# while preserving Yocto-specific environment variables used for alternate executable
> ++# and library path resolution.
>  +#
>  +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
> -+NEXT_LLVM_CONFIG="$(which -a llvm-config | sed -n 2p)"
> ++NEXT_LLVM_CONFIG="@LLVM_CONFIG_PATH@"

As I understand it, this is always being configured to point at the
llvm-config in the native sysroot?

I think this script is only ever installed into STAGING_BINDIR_CROSS?

If that is the case, could we just set this to a relative path to
SCRIPT_DIR, which would then always point at the right places without
needing to be adjusted each time?

>  +export YOCTO_ALTERNATE_EXE_PATH="${YOCTO_ALTERNATE_EXE_PATH:="$(readlink -f "$SCRIPT_DIR/../llvm-config")"}"
> -+if [ -n "$( echo $base_libdir | sed -n '/lib64/p')" ]; then
> ++if [ -d "$(readlink -f "$SCRIPT_DIR/../../lib64")" ]; then
>  +    export YOCTO_ALTERNATE_LIBDIR="${YOCTO_ALTERNATE_LIBDIR:="/lib64"}"
>  +else
>  +    export YOCTO_ALTERNATE_LIBDIR="${YOCTO_ALTERNATE_LIBDIR:="/lib"}"
>  +fi
> -+if [[ $# == 0 ]]; then
> -+  exec "$NEXT_LLVM_CONFIG"
> -+fi
> -+
> -+remain=""
> -+output=""
> -+for arg in "$@"; do
> -+  case "$arg" in
> -+    --cppflags)
> -+      output="${output} ${CPPFLAGS}"
> -+      ;;
> -+    --cflags)
> -+      output="${output} ${CFLAGS}"
> -+      ;;

Can you remind me, how does the native llvm-config provide the target
cflags? Is that triggered by setting the YOCTO_ALTERNATE_LIBDIR above?

Cheers,

Richard
diff mbox series

Patch

diff --git a/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch b/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
index eeb802732b..72ffdc6c1f 100644
--- a/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
+++ b/meta/recipes-devtools/clang/clang/0026-llvm-Add-libunwind.pc.in-and-llvm-config-scripts.patch
@@ -8,6 +8,7 @@  These are added by OE project
 Upstream-Status: Inappropriate [ OE-Specific ]
 
 Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Signed-off-by: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com>
 ---
  libunwind/libunwind.pc.in          |  9 ++++++
  llvm/tools/llvm-config/llvm-config | 52 ++++++++++++++++++++++++++++++
@@ -35,56 +36,19 @@  new file mode 100644
 index 000000000000..6a0dd54b8eab
 --- /dev/null
 +++ b/llvm/tools/llvm-config/llvm-config
-@@ -0,0 +1,52 @@
+@@ -0,0 +1,15 @@
 +#!/bin/bash
 +#
-+# Wrapper script for llvm-config. Supplies the right environment variables
-+# for the target and delegates to the native llvm-config for anything else. This
-+# is needed because arguments like --ldflags, --cxxflags, etc. are set by the
-+# native compile rather than the target compile.
++# The llvm-config wrapper will act as a pure pass-through to the native llvm-config
++# while preserving Yocto-specific environment variables used for alternate executable
++# and library path resolution.
 +#
 +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
-+NEXT_LLVM_CONFIG="$(which -a llvm-config | sed -n 2p)"
++NEXT_LLVM_CONFIG="@LLVM_CONFIG_PATH@"
 +export YOCTO_ALTERNATE_EXE_PATH="${YOCTO_ALTERNATE_EXE_PATH:="$(readlink -f "$SCRIPT_DIR/../llvm-config")"}"
-+if [ -n "$( echo $base_libdir | sed -n '/lib64/p')" ]; then
++if [ -d "$(readlink -f "$SCRIPT_DIR/../../lib64")" ]; then
 +    export YOCTO_ALTERNATE_LIBDIR="${YOCTO_ALTERNATE_LIBDIR:="/lib64"}"
 +else
 +    export YOCTO_ALTERNATE_LIBDIR="${YOCTO_ALTERNATE_LIBDIR:="/lib"}"
 +fi
-+if [[ $# == 0 ]]; then
-+  exec "$NEXT_LLVM_CONFIG"
-+fi
-+
-+remain=""
-+output=""
-+for arg in "$@"; do
-+  case "$arg" in
-+    --cppflags)
-+      output="${output} ${CPPFLAGS}"
-+      ;;
-+    --cflags)
-+      output="${output} ${CFLAGS}"
-+      ;;
-+    --cxxflags)
-+      output="${output} ${CXXFLAGS}"
-+      ;;
-+    --ldflags)
-+      output="${output} ${LDFLAGS}"
-+      ;;
-+    --shared-mode)
-+      output="${output} shared"
-+      ;;
-+    --link-shared)
-+      break
-+      ;;
-+    *)
-+      remain="${remain} ${arg}"
-+      ;;
-+  esac
-+done
-+
-+if [ "${remain}" != "" ]; then
-+      output="${output} "$("$NEXT_LLVM_CONFIG" ${remain})
-+fi
-+
-+echo "${output}"
++exec "$NEXT_LLVM_CONFIG" "$@"
diff --git a/meta/recipes-devtools/rust/rust_1.96.0.bb b/meta/recipes-devtools/rust/rust_1.96.0.bb
index 3eb2a36406..8b0f1d1459 100644
--- a/meta/recipes-devtools/rust/rust_1.96.0.bb
+++ b/meta/recipes-devtools/rust/rust_1.96.0.bb
@@ -31,7 +31,7 @@  PV .= "${@bb.utils.contains('RUST_CHANNEL', 'stable', '', '-${RUST_CHANNEL}', d)
 
 export FORCE_CRATE_HASH = "${BB_TASKHASH}"
 
-RUST_ALTERNATE_EXE_PATH ?= "${STAGING_BINDIR}/llvm-config"
+RUST_ALTERNATE_EXE_PATH = "${STAGING_BINDIR_CROSS}/llvm-config"
 RUST_ALTERNATE_EXE_PATH_NATIVE = "${STAGING_BINDIR_NATIVE}/llvm-config"
 
 # We don't want to use bitbakes vendoring because the rust sources do their
@@ -192,37 +192,22 @@  python do_configure() {
     bb.build.exec_func("setup_cargo_environment", d)
 }
 
-# llvm-config expects static/dynamic libraries to be in the 'lib' directory rather than 'lib64' when
-# multilibs enabled. Since we are copying the natively built llvm-config into the target sysroot
-# and executing it there, it will default to searching in 'lib', as it is unaware of the 'lib64'
-# directory. To ensure llvm-config can locate the necessary libraries, create a symlink from 'lib'
-do_compile:append:class-target() {
-    # Ensure llvm-config can find static libraries in multilib setup
-    lib64_dir="${STAGING_DIR_TARGET}/usr/lib64"
-    lib_dir="${STAGING_DIR_TARGET}/usr/lib"
-
-    if [ -d "$lib64_dir" ]; then
-        # If lib does not exist, symlink it to lib64
-        if [ ! -e "$lib_dir" ]; then
-            ln -s lib64 "$lib_dir"
-        fi
-
-        # Only do per-file symlinking if lib is a real directory (not symlink)
-        if [ -d "$lib_dir" ] && [ ! -L "$lib_dir" ]; then
-            for lib64_file in "${lib64_dir}"/libLLVM*.a "${lib64_dir}"/libLLVM*.so*; do
-                if [ -e "$lib64_file" ]; then
-                    lib_name=$(basename "${lib64_file}")
-                    target_link="${lib_dir}/${lib_name}"
-
-                    if [ ! -e "${target_link}" ]; then
-                        ln -s "../lib64/${lib_name}" "${target_link}"
-                    fi
-                fi
-            done
-        fi
+replace_llvm_config_path() {
+    if [ -f "${STAGING_BINDIR_CROSS}/llvm-config" ]; then
+        sed -i \
+            's#@LLVM_CONFIG_PATH@#${RUST_ALTERNATE_EXE_PATH_NATIVE}#g' \
+            ${RUST_ALTERNATE_EXE_PATH}
     fi
 }
 
+do_compile:append:class-target() {
+    replace_llvm_config_path
+}
+
+do_compile:append:class-nativesdk() {
+    replace_llvm_config_path
+}
+
 rust_runx () {
     echo "COMPILE ${PN}" "$@"
 
@@ -236,14 +221,6 @@  rust_runx () {
 
     export RUSTFLAGS="${RUST_DEBUG_REMAP} -Clink-arg=-lz -Clink-arg=-lzstd"
 
-    # Copy the natively built llvm-config into the target so we can run it. Horrible,
-    # but works!
-    if [ ${RUST_ALTERNATE_EXE_PATH_NATIVE} != ${RUST_ALTERNATE_EXE_PATH} -a ! -f ${RUST_ALTERNATE_EXE_PATH} ]; then
-        mkdir -p `dirname ${RUST_ALTERNATE_EXE_PATH}`
-        cp ${RUST_ALTERNATE_EXE_PATH_NATIVE} ${RUST_ALTERNATE_EXE_PATH}
-        patchelf --remove-rpath ${RUST_ALTERNATE_EXE_PATH}
-    fi
-
     oe_cargo_fix_env
 
     python3 src/bootstrap/bootstrap.py ${@oe.utils.parallel_make_argument(d, '-j %d')} "$@" --verbose
@@ -263,6 +240,7 @@  do_compile () {
 
 do_test_compile[dirs] = "${B}"
 do_test_compile () {
+    replace_llvm_config_path
     rust_runx build src/tools/remote-test-server --target "${RUST_TARGET_SYS}"
 }
 
diff --git a/meta/recipes-graphics/mesa/mesa.inc b/meta/recipes-graphics/mesa/mesa.inc
index 15dad6eedd..f40fed5ebc 100644
--- a/meta/recipes-graphics/mesa/mesa.inc
+++ b/meta/recipes-graphics/mesa/mesa.inc
@@ -51,6 +51,22 @@  ANY_OF_DISTRO_FEATURES = "opencl opengl vulkan"
 
 PLATFORMS ??= "${@bb.utils.filter('PACKAGECONFIG', 'x11 wayland', d)}"
 
+replace_llvm_config_path() {
+    if [ -f "${STAGING_BINDIR_CROSS}/llvm-config" ]; then
+        sed -i \
+            's#@LLVM_CONFIG_PATH@#${STAGING_BINDIR_NATIVE}/llvm-config#g' \
+            ${STAGING_BINDIR_CROSS}/llvm-config
+    fi
+}
+
+do_configure:prepend:class-target() {
+    replace_llvm_config_path
+}
+
+do_configure:prepend:class-nativesdk() {
+    replace_llvm_config_path
+}
+
 # set the MESA_BUILD_TYPE to either 'release' (default) or 'debug'
 # by default the upstream mesa sources build a debug release
 # here we assume the user will want a release build by default