Skip to content

clangd language support, SDK-resolved LLVM toolset, Clean/Rebuild fixes - #4

Merged
wasabii merged 6 commits into
mainfrom
clangd
Oct 6, 2026
Merged

wasabii merged 6 commits into
mainfrom
clangd

Conversation

@wasabii

@wasabii wasabii commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Second in a stack on top of #3 (vsix-review-fixes).

clangd language support

  • Compile commands from the SDK. GetClangCompileCommands computes each source file's clang command line without compiling, so design-time builds can run it; CoreCompile runs the same commands. Argument expansion moved into a shared ClangArguments, which also fixes response-file quoting (an argument with a space broke the whole command line).
  • Target identifiers as configurations. Like TargetFrameworks in .NET, each entry in TargetIdentifiers is its own configured project with its own design-time build (TargetIdentifier is a variant dimension; Configuration and Platform come from Configurations/Platforms). Builds clear TargetIdentifier so Build/Clean/Rebuild cover every target.
  • Language client. ClangdLanguageClient attaches to the Clang content types (only files opened from Clang projects have them). A proxy between VS and clangd:
    • gives clangd every file's command, and updates it when a design-time build changes it;
    • provides VS's project-context dropdown (one context per project and target identifier) and switches clangd's command for a file when the user picks another;
    • gives headers the command of the nearest source file in each project.
  • Colouring. Removed the bundled Objective-C grammars that shadowed VS's built-in ones; .cppm/.ixx/.hxx/.ipp map onto VS's C++ grammar.

LLVM toolset resolved by the SDK

  • ResolveLlvmToolset finds clang, clang++, llvm-ar and clangd from one installation: PATH plus the usual places per platform (LLVM and VS Clang tools on Windows, Homebrew on macOS, /usr/lib/llvm-N on Linux). An installation with the whole suite is preferred over clang alone.
  • LlvmToolsPath names a single directory for every tool. ClangPath, ClangCxxPath, LlvmArPath, ClangdPath and LinkerPath override individual tools. ClangToolPath/ClangToolExe and LlvmArToolPath/LlvmArToolExe still work.
  • A missing tool or a bad override is reported with guidance (ICLANG1001–1003) and fails the build only where that tool is needed. clang also reports its resource directory, which is passed to clangd so it uses that compiler's builtin headers.
  • Projects with C++/Objective-C++ sources now link with clang++. Linking with clang omitted the C++ standard library on non-MSVC targets. LinkWithClangCxx overrides the choice.
  • UseClangTasks=false works again (it was compiling only two of the task sources and never expanded them).

Graceful handling in Visual Studio

  • clangd comes only from the SDK (ClangdPath); the extension no longer searches for it.
  • Toolset problems appear as Error List warnings with the SDK's guidance. Opening one opens the project file, and they clear once corrected.
  • Without a usable clangd, activation waits and an info bar explains why and how to fix it. When a design-time build later reports one, clangd starts and gets the documents already open. A project on an older SDK gets a message to update.
  • Clang projects no longer get a ProjectGuid written into the project file.

Clean / Rebuild

  • Builds recorded nothing in FileListAbsolute.txt, so Clean deleted nothing. Builds now record their files, and orphaned objects from removed sources are deleted.
  • Added Rebuild (with BeforeRebuild/AfterRebuild) for single-target projects. Multi-target Rebuild had each inner build only clean; now each target rebuilds itself.
  • Clean also removes the outputs the SDK knows it produces.

Testing

  • New IKVM.Clang.Sdk.Tasks.Tests: 10 toolset-resolution tests using stand-in tool directories (added to CI).
  • New CleanTests in IKVM.Clang.Sdk.Tests: Build/Clean/Rebuild for single and multi-target projects, plus orphan removal. These pass locally.
  • clangd harness against clangd 23.1.2, outside VS: default commands, contexts, switching to wasm and back, headers, and command updates all pass.
  • Visual Studio 18.10, in an experimental hive:
    • project load with both targets;
    • the context dropdown switching targets;
    • hover with project defines;
    • Build/Rebuild/Clean Solution;
    • a broken LlvmToolsPath: Error List warnings, info bar, and the SDK's build error;
    • recovery after fixing the project, without a restart;
    • the project file left unchanged on load.
  • Not runnable here: the existing CanBuildTestProject cases. The Windows cases need ext/ikvm-native-sdk/win, and the emscripten case needs EMSDK.
  • Not tested: linking a C++ executable (no MSVC runtime libraries on this machine); clang++ is verified as the selected link driver.

@wasabii
wasabii added this pull request to stack #5 October 6, 2026 16:20
Base automatically changed from vsix-review-fixes to main October 6, 2026 23:28
GetClangCompileCommands returns the command line of each source file
(CommandLine as a JSON array, WorkingDirectory, TargetIdentifier) without
building anything, so design-time builds can run it. CoreCompile now runs
those same commands. A ClangCompileCommand rule adds the target to the
project subscription service.

Argument expansion moves into ClangArguments, shared by ExeTask and the new
ClangCompileCommand task. This also fixes response file quoting: an argument
containing white space put its opening quote at the start of the whole file,
breaking any command with a path containing a space.
Target identifiers become a configuration dimension, as target frameworks
are in .NET projects: with ProjectConfigurationsDeclaredDimensions, providers
supply Configuration (from Configurations), Platform (from Platforms) and
TargetIdentifier (from TargetIdentifiers, a variant dimension), so every
target identifier of the active configuration is loaded as its own
configured project with its own design-time build.

ClangCompileCommandSubscriber follows the active configuration group and
collects each configured project's GetClangCompileCommands results into
ClangCompileDatabase.

ClangdLanguageClient starts clangd for the Clang content types, which now
derive from the language server base type. ClangdProxy sits between Visual
Studio and clangd and:
- sends clangd every file's compile command once initialized, and again when
  a design-time build changes it;
- advertises and answers textDocument/_vs_getProjectContexts, listing one
  context per project and target identifier;
- switches the command clangd uses for a file when a request names another
  context;
- gives headers the command of the nearest source file of each project.

Grammars: drop the bundled Objective-C grammars, which shadowed Visual
Studio's fuller built-in ones, and map .cppm, .ixx, .hxx and .ipp onto the
built-in C++ grammar.
- Load every configured project of the active configuration group. The
  group of configured projects only holds those already loaded, so only the
  active target identifier was being followed and offered as a context.
- Clear TargetIdentifier for real builds of multi-target projects (a build
  global properties provider, as .NET does for TargetFramework) so Build
  runs the cross-targeting build for every target identifier, not just the
  active one.
- The SDK now resolves the compiler: ResolveClangTools finds clang
  (ClangToolPath, PATH, the LLVM installation, Visual Studio's Clang tools)
  and llvm-ar from the same installation, and asks clang for its resource
  directory. Builds use the resolved tools, and compile commands carry the
  compiler's full path and ResourceDirectory.
- clangd is given the SDK compiler's resource directory, so it uses that
  compiler's builtin headers, and the clangd beside the SDK's compiler is
  preferred.
- Pass the c modifier to llvm-ar so creating an archive is not reported as
  a build warning.
- IKVM_CLANG_CLANGD_TRACE names a file to trace the messages between Visual
  Studio and clangd, the configuration dimensions and the compile commands
  collected from projects.
…hout it

SDK:
- ResolveLlvmToolset finds clang, clang++, llvm-ar and clangd together.
  LlvmToolsPath names one directory to take every tool from; ClangPath,
  ClangCxxPath, LlvmArPath, ClangdPath and LinkerPath override single tools.
  Otherwise the tools come from one installation: PATH and the platform's
  usual places (LLVM and Visual Studio's Clang tools on Windows, Homebrew on
  macOS, /usr/lib/llvm-N on Linux), preferring an installation with the
  whole suite over clang alone, and taking the other tools from clang's
  directory first. ClangToolPath/ClangToolExe and LlvmArToolPath/
  LlvmArToolExe still work.
- A tool that cannot be found, or an override naming a missing file, is
  reported with guidance (ICLANG1001-1003) and fails the build only where
  that tool is needed. Design-time builds still produce compile commands.
- Projects with C++ or Objective-C++ sources link with clang++, so the C++
  standard library is linked (clang alone omits it for non-MSVC targets);
  LinkWithClangCxx overrides. LinkerPath is passed as --ld-path.
- GetLlvmToolset, with an LlvmToolset rule, reports the toolset and its
  problems to Visual Studio.
- UseClangTasks=false works again: every inline task is compiled from all
  the task sources (with Evaluate="true"), which keep their usings inside
  the namespace so they can be joined.
- IKVM.Clang.Sdk.Tasks.Tests covers the resolution rules.

Extension:
- clangd comes from the SDK (ClangdPath); ClangdLocator is gone.
- Toolset problems appear as Error List warnings with the SDK's guidance;
  opening one opens the project file. They clear once corrected.
- Without a usable clangd, activation waits and an info bar explains why
  and how to correct it. When a design-time build reports one, clangd
  starts and is given the documents already open. A project whose SDK
  does not report its toolset gets a message saying to update it.
Visual Studio's default project GUID storage writes a ProjectGuid property
into every project it opens. The solution already records the GUID, so a
storage provider for Clang projects keeps it in memory instead, while still
using a GUID a project file already has. The .NET project system does the
same.
- Builds recorded nothing in FileListAbsolute.txt: the files written were
  collected into items that were never combined, so Clean deleted nothing
  and outputs that were no longer produced were never removed.
- Single-target projects had no Rebuild target; it now runs BeforeRebuild,
  Clean, Build and AfterRebuild.
- Rebuild of a multi-target project depended on Clean and Build, which
  share the dispatch to the inner builds, so it only cleaned. It now has
  each inner build rebuild itself.
- Clean also removes the outputs the SDK knows it produces (object files,
  the library or executable and its symbols, copied headers and the copies
  in the output directory), so outputs that were never recorded go too.
- CleanTests cover Build, Clean and Rebuild for one and several target
  identifiers, and the removal of the object file of a deleted source.
@wasabii
wasabii merged commit f5ed855 into main Oct 6, 2026
1 check passed
@wasabii
wasabii deleted the clangd branch October 6, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant