Skip to content

Ask clang what a target triple means instead of guessing from its text - #7

Merged
wasabii merged 14 commits into
mainfrom
clang-target-info
Oct 10, 2026
Merged

wasabii merged 14 commits into
mainfrom
clang-target-info

Conversation

@wasabii

@wasabii wasabii commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

A target triple is whatever clang makes of it, so the SDK no longer reads
meaning into the string. A new ResolveClangTarget task asks clang, in
parallel: how it normalizes the triple, which macros it predefines for it,
and, by compiling an empty file, which object file format it produces.

  • Output names follow the object format: COFF is named as on Windows,
    Mach-O as on Apple, everything else as on Linux. UEFI, for one, now gets
    .obj and .lib, though its triple says nothing of Windows.
  • The MSVC environment, which decides whether a .pdb is expected, is told
    by clang defining _MSC_VER.
  • ClangTargetTriple, ClangObjectFormat and ClangTargetIsMsvc are set for
    the rest of the build, and GetOutputItem reports the first two. Setting
    ClangObjectFormat or ClangTargetIsMsvc in the project overrides clang.
  • A triple clang cannot build for fails the build with ICLANG3001 and what
    clang said; Clean and design-time builds still work.
  • Answers are kept in memory for the build process and in obj/ for later
    builds, keyed on the compiler, its timestamp and size, and the triple.
  • The naming properties are now set by the ResolveClangTarget target
    rather than at evaluation, and the string-matching ClangTargetOS is gone.
  • The executable test exits through ExitProcess, so the loader's threads
    no longer keep it running past the test's wait.

Stack created with GitHub Stacks CLI • Give Feedback 💬

wasabii added 13 commits October 6, 2026 10:01
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.
- Compile with a new ClangCompile task: sources build in parallel, and a
  source is rebuilt when it, a header it includes (from clang's -MD
  dependency file) or its command line changes.
- Relink executables and shared libraries when a referenced library or the
  link command changes; recreate archives so removed sources drop out.
- Build references for the referencing project's target identifier, and
  report an error when a host build references a project with several.
- Copy the shared libraries an executable needs, including ones reached
  through static libraries, next to it.
- Build for the host when no target identifier is given.
- Only name debug symbols that are produced, only copy headers marked
  CopyToIncludeDirectory, and stop adding /subsystem to every link.
- Tests for each of these.
- Release builds pass -O2 and define NDEBUG. Optimization sets the level
  (per project or per file), and DefineNDEBUG turns the definition off.
- PositionIndependentCode defaults to true on ELF targets, so static
  libraries can be linked into shared ones. Windows does not take -fPIC,
  Apple platforms are always position independent, and on WebAssembly it
  selects dynamic linking, so it stays off there.
- The README's property table now describes TargetIdentifier and the
  Subsystem default as they are.
Clang already chooses for each target: on for Linux, Android, Apple and
Windows, off for bare metal and FreeBSD. PositionIndependentCode now
passes -fPIC when true and -fno-pic when false, and nothing otherwise.
A target triple is whatever clang makes of it, so the SDK no longer reads
meaning into the string. A new ResolveClangTarget task asks clang, in
parallel: how it normalizes the triple, which macros it predefines for it,
and, by compiling an empty file, which object file format it produces.

- Output names follow the object format: COFF is named as on Windows,
  Mach-O as on Apple, everything else as on Linux. UEFI, for one, now gets
  .obj and .lib, though its triple says nothing of Windows.
- The MSVC environment, which decides whether a .pdb is expected, is told
  by clang defining _MSC_VER.
- ClangTargetTriple, ClangObjectFormat and ClangTargetIsMsvc are set for
  the rest of the build, and GetOutputItem reports the first two. Setting
  ClangObjectFormat or ClangTargetIsMsvc in the project overrides clang.
- A triple clang cannot build for fails the build with ICLANG3001 and what
  clang said; Clean and design-time builds still work.
- Answers are kept in memory for the build process and in obj/ for later
  builds, keyed on the compiler, its timestamp and size, and the triple.
- The naming properties are now set by the ResolveClangTarget target
  rather than at evaluation, and the string-matching ClangTargetOS is gone.
- The executable test exits through ExitProcess, so the loader's threads
  no longer keep it running past the test's wait.
@wasabii
wasabii added this pull request to stack #5 October 6, 2026 17:49
@wasabii
wasabii force-pushed the clang-target-info branch 2 times, most recently from df9e665 to ece15f8 Compare October 6, 2026 23:29
@wasabii
wasabii marked this pull request as ready for review October 6, 2026 23:31
Base automatically changed from sdk-build-fixes to main October 7, 2026 12:31
@wasabii
wasabii force-pushed the clang-target-info branch 2 times, most recently from 025610f to 15592bc Compare October 7, 2026 12:39
# Conflicts:
#	src/IKVM.Clang.Sdk.Tests/BuildTests.cs
#	src/IKVM.Clang.Sdk.Tests/ReferenceTests.cs
#	src/IKVM.Clang.Sdk.Tests/TestProjects.cs
#	src/IKVM.Clang.Sdk/targets/IKVM.Clang.Core.targets
#	src/IKVM.Clang.Sdk/targets/IKVM.Clang.NoTasks.targets
#	src/IKVM.Clang.Sdk/targets/IKVM.Clang.Tasks.targets
@wasabii
wasabii merged commit 9c75bad into main Oct 10, 2026
1 check passed
@wasabii
wasabii deleted the clang-target-info branch October 10, 2026 17:25
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