Skip to content

clang-tools: Improve wrapper script, add tests#354755

Merged
doronbehar merged 2 commits intoNixOS:stagingfrom
Patryk27:improve-clang-tools
Jan 5, 2026
Merged

clang-tools: Improve wrapper script, add tests#354755
doronbehar merged 2 commits intoNixOS:stagingfrom
Patryk27:improve-clang-tools

Conversation

@Patryk27
Copy link
Member

@Patryk27 Patryk27 commented Nov 9, 2024

clang-tools invokes clangd through a wrapper script whose sole purpose is to extend CPATH and CPLUS_INCLUDE_PATH envs, so that clangd is later able to find built-in and stdlib headers.

This script does two things wrong:

  1. We extend CPATH et al with entries from both @clang@/nix-support/libc-cflags and @clang@/resource-root/include, which is kind of a self-made problem, since clangd already has some header auto-detection logic which we (used to) circumvent (for more details, see the diff).

  2. We extend CPATH et al unconditionally, breaking the --query-driver option. I'm not sure what's the perfect solution here, but skipping this logic when we detect --query-driver should be good enough. I mean, ideally we wouldn't be playing with CPATH etc. whatsoever, but well.

Closes #351962
Closes #348791
Closes #345704

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added the 6.topic: llvm/clang Issues related to llvmPackages, clangStdenv and related label Nov 9, 2024
@Patryk27
Copy link
Member Author

Patryk27 commented Nov 9, 2024

Note that I'm not sure how to test --query-driver, my fix is just a hunch - cc @iniw, @lukash, could you play with it?

@ofborg ofborg bot added 11.by: package-maintainer This PR was created by a maintainer of all the package it changes. 10.rebuild-darwin: 11-100 This PR causes between 11 and 100 packages to rebuild on Darwin. 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-linux: 1001-2500 This PR causes many rebuilds on Linux and should target the staging branches. labels Nov 9, 2024
@iniw
Copy link
Contributor

iniw commented Nov 10, 2024

I'm not sure how great of a fix this is. --query-driver doesn't actually do anything all that special, it's only a glob that acts as a whitelist for which programs clangd is allowed to execute to find the appropriate headers. For example, mine is set to **, meaning all paths are allowed, because I only work on projects that I trust. Anyways, my point is that changing behavior depending on the existence of that flag is not ideal, IMO.

My question is: why do we even need the wrapper's shenanigans in the first place? clangd is very good at finding out about system headers and compiler's resource directories given just a compile_commands.json - why do we need anything else? Is the goal for the wrapped package to still find nixos's system headers when a compile_commands.json isn't found? If that's the case I'd prefer just dropping support for that entirely and instead document the fact that nixpkg's clangd will only properly work when given a valid compile_commands.json, which is already required anyways when working with third-party libraries and/or custom compile options such as C++ version, etc.

EDIT: Forgot to mention, the fix did work.

@iniw
Copy link
Contributor

iniw commented Nov 10, 2024

And as mentioned in the other issue raised on this matter, a clangd dev does seem to agree that adding these implicit paths is at the very least unusual.
clangd/clangd#2181 (comment)

@lukash
Copy link

lukash commented Nov 11, 2024

Thanks for your work on this, @Patryk27.

To me the --query-driver detection also seems sketchy, as @iniw said, it's just a mask. The check will fail at least in the case where the --query-driver won't match the actual compiler that's used. Might work to an extent when the user knows what they're doing, but still will be quirky. There's likely no robust mechanism to achieve what NixOS needs in clangd.

Being ignorant of the circumstances, what's in @clang@/nix-support/libc-cflags (and the C++ equivalent thereof) and why is it needed?

Is there an easy way to test the PR? I have a copy of the clang-tools default.nix I made some time ago and hacked the wrapper, that works. But since then the way that default.nix is called has changed and simple drop-in of the code isn't working for me (I'm calling it like this in a flake: my-clang-tools = nixpkgs.legacyPackages.${system}.callPackage ../clang-tools/clang-tools.nix {llvmPackages = pkgs.llvmPackages_18;};). I'll try to figure it out when I have some time, but not sure when that'll be.

@lukash
Copy link

lukash commented Nov 30, 2024

Well I copy-pasted the code from the PR and hacked at it until it "worked".

clangd seems to work well and the change to install its headers to the place it's looking for them is definitely correct. The workaround with --query-driver seems to improve the situation in general. It is strictly better for most cases and for the case of using --query-driver but not having the actual compiler match, the user has the possibility to fix it by correcting the --query-driver. Current state has broken cases with no workarounds for the user.

So IMO it'd be good to merge it, but a note explaining the workaround with the --query-driver detection should be definitely included in the wrapper script.

With the (hacked up) PR code, though, I'm not able to run clang-format from the package:

$ clang-format
/nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clang-format: line 44: /nix/store/nzyxg89vqxhdw884n50c2p5k1vrgibka-clang-unwrapped-with-lib/bin/clang-format: No such file or directory

$ which clang-format
/nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clang-format

$ ls -l /nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clang-format
lrwxrwxrwx 1 root root 6 led  1  1970 /nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clang-format -> clangd

$ ls -l /nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clangd
-r-xr-xr-x 1 root root 1499 led  1  1970 /nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clangd

$ cat /nix/store/cb77k2bnkb1fvr25pb9chv3baj1x6x1x-clang-tools-18.1.8/bin/clangd
#!/nix/store/1xhds5s320nfp2022yjah1h7dpv8qqns-bash-5.2p32/bin/sh

buildcpath() {
  local path after

  while (( $# )); do
    case $1 in
        -isystem)
            shift
            path=$path${path:+':'}$1
            ;;

        -idirafter)
            shift
            after=$after${after:+':'}$1
            ;;
    esac

    shift
  done

  echo $path${after:+':'}$after
}

# When user passes `--query-driver`, avoid extending `CPATH` et al, since we
# don't want to "infect" user-specified toolchain and headers with our stuff.
extendcpath=true

for arg in "$@"; do
  if [[ "${arg}" == \-\-query\-driver* ]]; then
    extendcpath=false
  fi
done

if [ "$extendcpath" = true ]; then
  export CPATH=${CPATH}${CPATH:+':'}$(buildcpath ${NIX_CFLAGS_COMPILE} \
                                                 $(</nix/store/nr95z75f3hj5z7a0bddqpx9wjm47mvbd-clang-wrapper-17.0.6/nix-support/libc-cflags))

  export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}${CPLUS_INCLUDE_PATH:+':'}$(buildcpath ${NIX_CFLAGS_COMPILE} \
                                                                                        $(</nix/store/nr95z75f3hj5z7a0bddqpx9wjm47mvbd-clang-wrapper-17.0.6/nix-support/libcxx-cxxflags) \
                                                                                        $(</nix/store/nr95z75f3hj5z7a0bddqpx9wjm47mvbd-clang-wrapper-17.0.6/nix-support/libc-cflags))
fi

exec -a "$0" /nix/store/nzyxg89vqxhdw884n50c2p5k1vrgibka-clang-unwrapped-with-lib/bin/$(basename $0) "$@"

$ ls /nix/store/nzyxg89vqxhdw884n50c2p5k1vrgibka-clang-unwrapped-with-lib/bin/
clangd

As you can see, clang-format is a symlink to clangd, which is a script, which calls $(basename $0) (being clang-format) from some unwrapped directory which doesn't contain the binary. I don't think I've broken this in my hacked up version.

Also note that paths passed to the CPATH / CPLUS_INCLUDE_PATH directories are somehow pointing to some clang-tools version 17 store paths. But this may be something I've caused by my crude use of the PR code.

@Patryk27
Copy link
Member Author

Patryk27 commented Dec 1, 2024

I don't think I've broken this in my hacked up version.

You're right, my patch breaks this (including other tools like clang-move) - I'm looking into it now.

As for the overall approach to the fix, I'm not 100% sold on it either - I just cobbled together something that works better than the current approach; I'm not sure why we need the CPATH and CPLUS_INCLUDE_PATH thingies 🤔

@Patryk27
Copy link
Member Author

Patryk27 commented Dec 1, 2024

Alright, I pushed a new commit that uses a bit less hacky approach - clang-format etc. should work as well now. Let me know what you think!

I'm also open to other approaches, just don't have any other idea myself.

(btw, I'll squash the commits later - I've pushed it as a separate commit to make it easier to review)

@github-actions github-actions bot removed the 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. label Dec 1, 2024
@ofborg ofborg bot added the 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. label Dec 2, 2024
@lukash
Copy link

lukash commented Dec 8, 2024

Just loaded the changes, both clangd and clang-format seem to work, I'll report back if I find an issue. Thank you!

Regarding an overall better / "correct" approach, ideally you could work with clangd upstream to figure out a proper solution. FWIW they were very helpful in my bugreports. But I guess someone would need to analyze the situation on Nix side and approach them with a clear description of the situation and what Nix needs... I can chime in especially with the arm compilation side, but lack a general in-depth insight.

@iniw
Copy link
Contributor

iniw commented Dec 17, 2024

I'm personally happy with the changes here. Would like to see this merged :)

Copy link
Member

@alyssais alyssais left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please squash the commits and update the commit message for the new approach? Otherwise this is quite hard to review.

@Patryk27 Patryk27 force-pushed the improve-clang-tools branch from d8d241b to 3264fa9 Compare January 23, 2025 17:47
@github-actions github-actions bot removed the 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. label Jan 23, 2025
Copy link
Member

@alyssais alyssais left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit message doesn't explain anything at the moment. The details you put in the PR body would be a good start, but the addition of the lib symlink also requires explanation.

@Patryk27 Patryk27 force-pushed the improve-clang-tools branch from 3264fa9 to fd38da8 Compare January 25, 2025 10:22
@iniw
Copy link
Contributor

iniw commented Oct 7, 2025

clangd 21 has a new BuiltinHeaders option that, when used alongside the unwrapped package, forms a better solution than my previous -resource-dir hack. So the workaround is to essentially:

  • Use llvmPackages_21.clang-unwrapped
  • Add the following to your .clangd:
CompileFlags:
  BuiltinHeaders: QueryDriver

@nixpkgs-ci nixpkgs-ci bot removed the 11.by: package-maintainer This PR was created by a maintainer of all the package it changes. label Nov 2, 2025
@Patryk27
Copy link
Member Author

ping ping 👀

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-in-distress/3604/124

Patryk27 added a commit to Patryk27/nixpkgs-committers that referenced this pull request Dec 28, 2025
Hi,

I'd like to nominate myself - I've been submitting pull requests since 2020, started by packaging [netris](NixOS/nixpkgs#85382) and then went on to improving [LXD](NixOS/nixpkgs#89540), [packaging](NixOS/nixpkgs#91182) and [maintaining](https://github.com/NixOS/nixpkgs/pulls?q=author%3APatryk27+pcloud) pCloud (which, amazingly enough, required fixing a bug in [patchelf](NixOS/patchelf#544) itself!), and overall I've been implementing various quality of live improvements [here](NixOS/nixpkgs#207466) and [there](NixOS/nixpkgs#354755).

I've given [a talk about my Nix-driven blog](https://www.youtube.com/watch?v=_7wqXN-7ebw&t=6695s) during NixCon 2024 in Berlin, so it's possible we've already met irl!

Outside of Nix, I'm the maintainer of Rust's [AVR backend](rust-lang/rust#131651), with commits and merging rights to [LLVM](https://github.com/llvm/llvm-project/pulls?q=author%3APatryk27) - just adding as an extra "in case it helps" mention 😇 

Couple of weeks ago I decided to shift my priorities from working on custom projects to helping the communities I'm a part of more - having committer access to nixpkgs would allow me to make a greater impact as I intend to focus on reviewing and merging both ongoing and stale pull requests, since it seems there's always not enough people willing to review stuff!

Thanks, Patryk :-)
Copy link
Contributor

@doronbehar doronbehar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a clang user, but I came after the "PRs in distress post", so I cannot review the changes to wrapper script and I haven't read thoroughly the comments. However these are my 2 cents:

It could be easier to review this if the changes were a bit more decoupled to these commits:

  1. clang-tools: use finalAttrs
  2. clang-tools: add passthru.tests
  3. clang-tools: improve wrapper script & installPhase

In the 1st commit, I'd also remove the usage of ${finalAttrs.unwrapped} and the unwrapped argument to mkDerivation, in favor of simply ${clang-unwrapped} - it will be easier to figure out how to override it by looking at the expression.

@Patryk27
Copy link
Member Author

Patryk27 commented Dec 28, 2025

@doronbehar thanks for taking a look!

In the 1st commit, I'd also remove the usage of ${finalAttrs.unwrapped} and the unwrapped argument to mkDerivation, in favor of simply ${clang-unwrapped}

In that case what should exactly remain in that commit? 🤔 (i.e. what would use those finalAttrs)

@doronbehar
Copy link
Contributor

In that case what should exactly remain in that commit? 🤔 (i.e. what would use those finalAttrs)

Haha you are right :) If you have nothing to use finalAttrs with then maybe drop this commit.

@Patryk27 Patryk27 force-pushed the improve-clang-tools branch from 1db896b to c198984 Compare January 2, 2026 18:28
@Patryk27
Copy link
Member Author

Patryk27 commented Jan 2, 2026

Okie, done!

Eventually I've decided to leave the finalAttrs pattern as suggested previously - seems that most packages use it; other than that I've split the changes into separate commits.

@nixpkgs-ci nixpkgs-ci bot requested review from alyssais and emilazy January 2, 2026 18:36
@nixpkgs-ci nixpkgs-ci bot added 10.rebuild-linux: 101-500 This PR causes between 101 and 500 packages to rebuild on Linux. 11.by: package-maintainer This PR was created by a maintainer of all the package it changes. and removed 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-linux: 1001-2500 This PR causes many rebuilds on Linux and should target the staging branches. labels Jan 2, 2026
Copy link
Contributor

@doronbehar doronbehar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good I guess. Since there are many people who have reviewed this, and no body seems to have a strong objection, I think this should be good to go after the last small fix requested. Please write a message here if you think something in the PR is wrong.

@Patryk27 Patryk27 force-pushed the improve-clang-tools branch from c198984 to 6a3f89d Compare January 4, 2026 18:03
@doronbehar doronbehar force-pushed the improve-clang-tools branch from 6a3f89d to 0951974 Compare January 5, 2026 13:54
@doronbehar
Copy link
Contributor

In the last force push I only made the runCommand & writeText arguments be added in the 2nd commit that adds the passthru.tests - as only then they are needed. I am sorry I did this myself, I just felt bad how much this PR has been waiting.

@doronbehar doronbehar enabled auto-merge January 5, 2026 13:56
@doronbehar doronbehar added this pull request to the merge queue Jan 5, 2026
Merged via the queue into NixOS:staging with commit 217f825 Jan 5, 2026
25 checks passed
@Patryk27
Copy link
Member Author

Patryk27 commented Jan 5, 2026

I am sorry I did this myself, I just felt bad how much this PR has been waiting.

No problemo, thank you so much for taking a look and merging this!

@Patryk27 Patryk27 deleted the improve-clang-tools branch January 5, 2026 16:40
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/dev-shell-flake-clangd-cant-find-gnu-stubs-32-h/51067/2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: llvm/clang Issues related to llvmPackages, clangStdenv and related 10.rebuild-darwin: 101-500 This PR causes between 101 and 500 packages to rebuild on Darwin. 10.rebuild-linux: 101-500 This PR causes between 101 and 500 packages to rebuild on Linux. 11.by: package-maintainer This PR was created by a maintainer of all the package it changes. 12.approvals: 1 This PR was reviewed and approved by one person. 12.approved-by: package-maintainer This PR was reviewed and approved by a maintainer listed in any of the changed packages.

Projects

None yet

9 participants