Skip to content

Conversation

@cachemeifyoucan
Copy link

Prototype for gmodule support by switching splitDwarf references to CASIDs of the module/PCH

Also teach dsymutil to support reading from CAS as a prototype for lldb support.

Choose a reason for hiding this comment

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

This would potentially fit better into llvm-project/lldb/packages/Python/lldbsuite/

Copy link
Author

Choose a reason for hiding this comment

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

This is a compiler launcher type of script and requires a just built clang (because it needs clang-scan-deps next to it). I don't what is a good way to hack into lldbsuite or driven from makefile. Let me know if you have any good idea.

@cachemeifyoucan
Copy link
Author

@adrian-prantl @benlangmuir Ping for review

@cachemeifyoucan
Copy link
Author

@swift-ci please test llvm

@cachemeifyoucan
Copy link
Author

@swift-ci please test llvm

@cachemeifyoucan cachemeifyoucan force-pushed the casify-module branch 4 times, most recently from 479c33e to 5c6f640 Compare September 29, 2025 17:08
@cachemeifyoucan
Copy link
Author

@swift-ci please test llvm

@cachemeifyoucan cachemeifyoucan force-pushed the casify-module branch 2 times, most recently from 11bba2c to 55c97e3 Compare October 6, 2025 22:13
Copy link

@benlangmuir benlangmuir left a comment

Choose a reason for hiding this comment

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

LGTM for the clang changes. Someone else should review the LLDB and dsymutil code.

/// Check debug info is correct.
// RUN: %clang %t/tu.o -o %t/a.out
// RUN: dsymutil -cas %t/cas %t/a.out -o %t/a.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
// RUN: dsymutil %t/a.out -o %t/a2.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty

Choose a reason for hiding this comment

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

Does this being dsymutil and not %dsymutil mean we might pick up the system one? Since there is also a dsymutil aspect to this, could that be problematic in CI?

Copy link
Author

Choose a reason for hiding this comment

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

Tools are always in the path.

NOTE: this is not the only test that calls dsymutil in clang tests and dsymutil wasn't even a build dependency for tests (added in this PR).


def cas : Separate<["-", "--"], "cas">,
MetaVarName<"<path>">,
HelpText<"Specify CAS directory to load CAS references from.">,

Choose a reason for hiding this comment

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

Does this imply that there can only be one CAS per build?
Is that realistic? What if people use static archives and combine objects from different projects?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, it has to be one CAS per build. It is a requirement for module imports and there is no way you can configure otherwise.

If you have multiple builds and uses some products from other build, the second CAS has to ingest everything from previous builds.

WithColor::note() << "create CAS using configuration: " << Config->first
<< "'\n";
return DB->first;
}

Choose a reason for hiding this comment

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

It would be good to find a way to mock this up in a dsymutil-only test that doesn't depend on clang.

Copy link
Author

Choose a reason for hiding this comment

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

Let me know if you have good ways to do it. It is very hard to do it since it needs to construct both object files (which can be committed) but also module files and CAS contents.

Choose a reason for hiding this comment

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

Usually we check in binary files for dsymutil tests. We only need to resolve a single URL to test it. Is there maybe room for a null CAS plugin where the llvmcas:// URL is a filename directly?

// START CAS
FileSpec ModuleListProperties::GetCASOnDiskPath() const {
const uint32_t idx = ePropertyCASOnDiskPath;
return GetPropertyAtIndexAs<FileSpec>(idx, {});

Choose a reason for hiding this comment

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

How would these settings be communicated to LLDB in the typical use-case?
What if a debug session contains multiple dylibs built against different CAS storage? (I.e., in each project's DerivedData/)

Copy link
Author

@cachemeifyoucan cachemeifyoucan Oct 16, 2025

Choose a reason for hiding this comment

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

See ConfigureCASStorage().

This option provides a global overwrite. If no global setting available, it will search for a CAS configuration from the path of the debugging binary upwards to find a CAS configuration file.

@cachemeifyoucan
Copy link
Author

Create PR on stable branch (so test is available) if you like to review over there: #11714

if (!DB) {
WithColor::error() << "failed to open CAS: " << toString(DB.takeError())
<< "\n";
return EXIT_FAILURE;

Choose a reason for hiding this comment

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

Can we add tests that check the error handling when:

  • no config file is found
  • the cas in the config file is corrupted/incompatible/...
  • the url cannot be resolved in the cas

# RUN: %lldb %t/main -s %t/lldb.script 2>&1 | FileCheck %s
# CHECK: loading module 'Bottom' using CASID
# CHECK: loading module 'Top' using CASID
# CHECK: top = (x = 1)

Choose a reason for hiding this comment

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

Like in the dsymutil patch, it would be important to also test at least the most common error paths (config file doesn't exist, build dir has been removed, CAS is using different file storage format,...)

@adrian-prantl
Copy link

Conceptually this looks good, thanks!

@cachemeifyoucan
Copy link
Author

@adrian-prantl Can you take a look again?

Not all error conditions can be tested or checked due to the limitation of CAS interface. We will not know things like version mismatch. Also all CAS checks are done before checking file system, so we cannot throw messages when CAS lookup failed. I tried best to log/healthcheck most of the CAS loads so we can tell if the CAS read is successful or not with additional logging.

@cachemeifyoucan
Copy link
Author

Everything should be addressed, except a standalone dsymutil test case. I need to think how to write that.

Teach clang to encode CASID as splitDwarfFilename for gmodule when
clang caching is enabled. This allows the outputs from compiler do not
contain paths to the clang module files, thus allows distributed caching
without the need of a unified clang module cache directory path.
Teach dsymutil how to use CAS and how to load clang modules from CAS
when building dSYM when gmodule is used.
Teach lldb to load clang modules when gmodule + clang caching is used.
Teach SwiftASTContext to load clang module dependencies from CAS instead
of FileSystem.
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.

3 participants