{
  lib,
  stdenv,
  runCommand,
  writeText,
  clang-unwrapped,
  clang,
  libcxxClang,
  llvm_meta,
  # enableLibcxx will use the c++ headers from clang instead of gcc.
  # This shouldn't have any effect on platforms that use clang as the default compiler already.
  enableLibcxx ? false,
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "clang-tools";
  version = lib.getVersion clang-unwrapped;
  dontUnpack = true;
  clang = if enableLibcxx then libcxxClang else clang;

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin

    for script in ${clang-unwrapped.python}/share/clang/* ${clang-unwrapped.python}/bin/*; do
      if [[ -x "$script" ]]; then
        ln -s $script $out/bin/$(basename "$script" .py)
      fi
    done

    for toolPath in ${clang-unwrapped}/bin/clangd ${clang-unwrapped}/bin/clang-*; do
      toolName=$(basename "$toolPath")

      # Compilers have their own derivations, no need to include them here
      if [[ $toolName == "clang-cl" || $toolName == "clang-cpp" || $toolName =~ ^clang\-[0-9]+$ ]]; then
        continue
      fi

      cp $toolPath $out/bin/$toolName-unwrapped
      substituteAll ${./wrapper} $out/bin/$toolName
      chmod +x $out/bin/$toolName
    done

    # clangd etc. find standard header files by looking at the directory the
    # tool is located in and appending `../lib` to the search path. Since we
    # are copying the binaries, they expect to find `$out/lib` present right
    # within this derivation, containing `stddef.h` and so on.
    #
    # Note that using `ln -s` instead of `cp` in the loop above wouldn't avoid
    # this problem, since it's `clang-unwrapped` which separates libs into a
    # different output in the first place - here we are merely "merging" the
    # directories back together, as expected by the tools.
    ln -s ${clang-unwrapped.lib}/lib $out/lib

    runHook postInstall
  '';

  passthru.tests =
    let
      src = writeText "main.cpp" ''
        #include <iostream>

        int main() {
          std::cout << "Hi!";
        }
      '';

    in
    {
      smokeOk = runCommand "clang-tools-test-smoke-ok" { } ''
        ${finalAttrs.finalPackage}/bin/clangd  --check=${src}
        touch $out
      '';
      smokeErr = runCommand "clang-tools-test-smoke-err" { } ''
        (${finalAttrs.finalPackage}/bin/clangd --query-driver='**' --check=${src} 2>&1 || true) \
            | grep 'use of undeclared identifier'

        touch $out
      '';
      environmentErr = runCommand "clang-tools-test-environment-err" { } ''
         (CLANGD_FLAGS="--query-driver='**'" ${finalAttrs.finalPackage}/bin/clangd --check=${src} 2>&1 || true) \
            | grep 'use of undeclared identifier'

        touch $out
      '';
    };

  meta = llvm_meta // {
    description = "Standalone command line tools for C++ development";
    maintainers = with lib.maintainers; [ patryk27 ];
  };
})
