Skip to content

Commit 4b4f9f1

Browse files
authored
Add an option for symbol graph to support long module names. (#83782)
Currently symbol graphs are always written in files that contain 1 to 2 module names. It's possible for Swift module names to be very long, so combining 2 of them in file name like `module1@module2...` in the same path component means the name can be too long for some file systems. The new option `-symbol-graph-shorten-output-names` changes the symbol graph output files to use a MD5 hash of the module name(s) as the filename and outputs an additional JSON file with the original names mapped to the real filename. The module names JSON can be used to construct a VFS overlay with the original naming scheme. fix #83723 I considered using vfsoverlay, which seems like a viable solution, but the vfsoverlay options don't seem to apply to any of the outputs from the compiler. When I set an overlay to remap the symbol graph file outputs, the remapped external paths aren't used so the root problem of too long file names remains.
1 parent 59e1474 commit 4b4f9f1

File tree

7 files changed

+119
-11
lines changed

7 files changed

+119
-11
lines changed

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,11 @@ def skip_protocol_implementations : Flag<["-"], "skip-protocol-implementations">
19611961
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
19621962
HelpText<"Skip emitting symbols that are implementations of protocol requirements or inherited from protocol extensions">;
19631963

1964+
def symbol_graph_shorten_output_names : Flag<["-"], "symbol-graph-shorten-output-names">,
1965+
Flags<[SwiftSymbolGraphExtractOption, FrontendOption,
1966+
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
1967+
HelpText<"Shorten the symbol graph output file names by hashing the module name; outputs an additional JSON file with the map of hash to original name">;
1968+
19641969
// swift-api-digester-only options
19651970
def dump_sdk: Flag<["-", "--"], "dump-sdk">,
19661971
Flags<[NoDriverOption, SwiftAPIDigesterOption]>,

include/swift/SymbolGraphGen/SymbolGraphOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ struct SymbolGraphOptions {
7777

7878
/// Whether `AvailabilityPlatforms` is an allow list or a block list.
7979
bool AvailabilityIsBlockList = false;
80+
81+
/// Whether to use shortened, by using a hash of the module names, file names
82+
/// when writing symbol graph files to `OutputDir`.
83+
/// An additional JSON file is written at `OutputDir` that contains a mapping
84+
/// of the shortened file names to the module name(s) in the symbol graph
85+
/// files.
86+
bool ShortenOutputNames = false;
8087
};
8188

8289
} // end namespace symbolgraphgen

lib/Driver/ToolChains.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
733733
context.Args.AddLastArg(Arguments, options::OPT_emit_extension_block_symbols,
734734
options::OPT_omit_extension_block_symbols);
735735
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_minimum_access_level);
736+
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_shorten_output_names);
736737
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_skip_synthesized_members);
737738
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_skip_inherited_docs);
738739
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_pretty_print);
@@ -1272,6 +1273,7 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
12721273
context.Args.AddLastArg(Arguments, options::OPT_emit_extension_block_symbols,
12731274
options::OPT_omit_extension_block_symbols);
12741275
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_minimum_access_level);
1276+
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_shorten_output_names);
12751277

12761278
context.Args.AddLastArg(Arguments, options::OPT_import_bridging_header,
12771279
options::OPT_internal_import_bridging_header);

lib/DriverTool/swift_symbolgraph_extract_main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
185185
Options.SkipInheritedDocs = ParsedArgs.hasArg(OPT_skip_inherited_docs);
186186
Options.SkipProtocolImplementations = ParsedArgs.hasArg(OPT_skip_protocol_implementations);
187187
Options.IncludeSPISymbols = ParsedArgs.hasArg(OPT_include_spi_symbols);
188+
Options.ShortenOutputNames = ParsedArgs.hasArg(OPT_symbol_graph_shorten_output_names);
188189
Options.EmitExtensionBlockSymbols =
189190
ParsedArgs.hasFlag(OPT_emit_extension_block_symbols,
190191
OPT_omit_extension_block_symbols, /*default=*/false);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
22852285
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
22862286
Opts.SkipProtocolImplementations = Args.hasArg(OPT_skip_protocol_implementations);
22872287
Opts.IncludeSPISymbols = Args.hasArg(OPT_include_spi_symbols);
2288+
Opts.ShortenOutputNames = Args.hasArg(OPT_symbol_graph_shorten_output_names);
22882289
Opts.EmitExtensionBlockSymbols =
22892290
Args.hasFlag(OPT_emit_extension_block_symbols,
22902291
OPT_omit_extension_block_symbols, /*default=*/false);

lib/SymbolGraphGen/SymbolGraphGen.cpp

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/Basic/Module.h"
2121
#include "llvm/ADT/STLExtras.h"
2222
#include "llvm/Support/JSON.h"
23+
#include "llvm/Support/MD5.h"
2324
#include "llvm/Support/Path.h"
2425

2526
#include "SymbolGraphASTWalker.h"
@@ -28,28 +29,82 @@ using namespace swift;
2829
using namespace symbolgraphgen;
2930

3031
namespace {
31-
int serializeSymbolGraph(SymbolGraph &SG,
32-
const SymbolGraphOptions &Options) {
32+
33+
/// Utility for managing symbol graph output file names.
34+
class SymbolGraphWriter {
35+
36+
public:
37+
SymbolGraphWriter(const SymbolGraphOptions &Options) : Options(Options) {}
38+
39+
bool
40+
withOutputPath(DiagnosticEngine &Diags, llvm::vfs::OutputBackend &Backend,
41+
StringRef ModuleName,
42+
llvm::function_ref<bool(llvm::raw_pwrite_stream &)> Action) {
43+
SmallString<32> FileName;
44+
if (Options.ShortenOutputNames) {
45+
llvm::MD5 Hash;
46+
Hash.update(ModuleName);
47+
llvm::MD5::MD5Result Result;
48+
Hash.final(Result);
49+
llvm::MD5::stringifyResult(Result, FileName);
50+
} else {
51+
FileName = ModuleName;
52+
}
53+
FileName.append(".symbols.json");
54+
SymbolFileShortPaths.try_emplace(std::string(ModuleName), std::string(FileName));
55+
56+
SmallString<1024> OutputPath(Options.OutputDir);
57+
llvm::sys::path::append(OutputPath, FileName);
58+
return swift::withOutputPath(Diags, Backend, OutputPath, Action);
59+
}
60+
61+
bool finalize(DiagnosticEngine &Diags, llvm::vfs::OutputBackend &Backend) {
62+
if (!Options.ShortenOutputNames) {
63+
return false; // No errors.
64+
}
65+
66+
SmallString<1024> OutputPath(Options.OutputDir);
67+
llvm::sys::path::append(OutputPath, "symbol_modules.json");
68+
return swift::withOutputPath(
69+
Diags, Backend, OutputPath, [&](raw_ostream &OS) {
70+
llvm::json::OStream JSON(OS, Options.PrettyPrint ? 2 : 0);
71+
JSON.object([&] {
72+
// Insert the module to real filename mappings in a deterministic
73+
// order. Enumerating the map returns the keys in order.
74+
JSON.attributeObject("modules", [&] {
75+
for (const auto &[K, V] : SymbolFileShortPaths) {
76+
JSON.attribute(K, V);
77+
}
78+
});
79+
});
80+
return false;
81+
});
82+
}
83+
84+
private:
85+
const SymbolGraphOptions &Options;
86+
std::map<std::string, std::string> SymbolFileShortPaths;
87+
};
88+
89+
int serializeSymbolGraph(SymbolGraph &SG, const SymbolGraphOptions &Options,
90+
SymbolGraphWriter &Writer) {
3391
SmallString<256> FileName;
3492
FileName.append(getFullModuleName(&SG.M));
3593
if (SG.ExtendedModule.has_value()) {
3694
FileName.push_back('@');
3795
// FileName.append(SG.ExtendedModule.value()->getNameStr());
3896
FileName.append(getFullModuleName(SG.ExtendedModule.value()));
3997
} else if (SG.DeclaringModule.has_value()) {
40-
// Treat cross-import overlay modules as "extensions" of their declaring module
98+
// Treat cross-import overlay modules as "extensions" of their declaring
99+
// module
41100
FileName.push_back('@');
42101
// FileName.append(SG.DeclaringModule.value()->getNameStr());
43102
FileName.append(getFullModuleName(SG.DeclaringModule.value()));
44103
}
45-
FileName.append(".symbols.json");
46-
47-
SmallString<1024> OutputPath(Options.OutputDir);
48-
llvm::sys::path::append(OutputPath, FileName);
49104

50-
return withOutputPath(
105+
return Writer.withOutputPath(
51106
SG.M.getASTContext().Diags, SG.M.getASTContext().getOutputBackend(),
52-
OutputPath, [&](raw_ostream &OS) {
107+
FileName, [&](raw_ostream &OS) {
53108
llvm::json::OStream J(OS, Options.PrettyPrint ? 2 : 0);
54109
SG.serialize(J);
55110
return false;
@@ -145,14 +200,18 @@ int symbolgraphgen::emitSymbolGraphForModule(
145200

146201
int Success = EXIT_SUCCESS;
147202

148-
Success |= serializeSymbolGraph(Walker.MainGraph, Options);
203+
SymbolGraphWriter Writer(Options);
204+
Success |= serializeSymbolGraph(Walker.MainGraph, Options, Writer);
149205

150206
for (const auto &Entry : Walker.ExtendedModuleGraphs) {
151207
if (Entry.getValue()->empty()) {
152208
continue;
153209
}
154-
Success |= serializeSymbolGraph(*Entry.getValue(), Options);
210+
Success |= serializeSymbolGraph(*Entry.getValue(), Options, Writer);
155211
}
212+
Success |=
213+
Writer.finalize(Walker.MainGraph.M.getASTContext().Diags,
214+
Walker.MainGraph.M.getASTContext().getOutputBackend());
156215

157216
return Success;
158217
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name EmitShortenedNames -emit-module -emit-module-path %t/EmitShortenedNames.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ -symbol-graph-shorten-output-names
3+
// RUN: %FileCheck %s --input-file %t/9d0ee7243b44e35c186695a49461007b.symbols.json --check-prefix BASE
4+
// RUN: %FileCheck %s --input-file %t/27a36c452b5f5e2b488b7755cecf40c7.symbols.json --check-prefix EXT
5+
// RUN: %FileCheck %s --input-file %t/symbol_modules.json --check-prefix MAP
6+
7+
// now try with the swift-symbolgraph-extract tool directly
8+
9+
// RUN: %empty-directory(%t)
10+
// RUN: %target-build-swift %s -module-name EmitShortenedNames -emit-module -emit-module-path %t/EmitShortenedNames.swiftmodule
11+
// RUN: %target-swift-symbolgraph-extract -module-name EmitShortenedNames -I %t -output-dir %t -symbol-graph-shorten-output-names
12+
// RUN: %FileCheck %s --input-file %t/9d0ee7243b44e35c186695a49461007b.symbols.json --check-prefix BASE
13+
// RUN: %FileCheck %s --input-file %t/27a36c452b5f5e2b488b7755cecf40c7.symbols.json --check-prefix EXT
14+
// RUN: %FileCheck %s --input-file %t/symbol_modules.json --check-prefix MAP
15+
16+
// now try with the swiftc driver
17+
18+
// RUN: %empty-directory(%t)
19+
// RUN: %target-swiftc_driver %s -module-name EmitShortenedNames -emit-module -emit-module-path %t/EmitShortenedNames.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ -symbol-graph-shorten-output-names
20+
// RUN: %FileCheck %s --input-file %t/9d0ee7243b44e35c186695a49461007b.symbols.json --check-prefix BASE
21+
// RUN: %FileCheck %s --input-file %t/27a36c452b5f5e2b488b7755cecf40c7.symbols.json --check-prefix EXT
22+
// RUN: %FileCheck %s --input-file %t/symbol_modules.json --check-prefix MAP
23+
24+
public func foo() {}
25+
26+
extension Sequence {
27+
public func bar() {}
28+
}
29+
30+
// BASE: "precise":"s:18EmitShortenedNames3fooyyF"
31+
// EXT: "precise":"s:ST18EmitShortenedNamesE3baryyF"
32+
// MAP: "EmitShortenedNames":"9d0ee7243b44e35c186695a49461007b.symbols.json",
33+
// MAP: "EmitShortenedNames@Swift":"27a36c452b5f5e2b488b7755cecf40c7.symbols.json"

0 commit comments

Comments
 (0)