Skip to content

Add a new driver tool/mode to print the synthesized Swift interface for a module. #76872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ class Driver {
APIDigester, // swift-api-digester
CacheTool, // swift-cache-tool
ParseTest, // swift-parse-test
SynthesizeInterface, // swift-synthesize-interface
};

class InputInfoMap;
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Option/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace options {
DoesNotAffectIncrementalBuild = (1 << 8),
AutolinkExtractOption = (1 << 9),
ModuleWrapOption = (1 << 10),
// 1 << 11 was previously `SwiftIndentOption`
SwiftSynthesizeInterfaceOption = (1 << 11),
ArgumentIsPath = (1 << 12),
ModuleInterfaceOption = (1 << 13),
SupplementaryOutput = (1 << 14),
Expand Down
66 changes: 43 additions & 23 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def SupplementaryOutput : OptionFlag;
// The option should be accepted by swift-symbolgraph-extract.
def SwiftSymbolGraphExtractOption : OptionFlag;

// The option should be accepted by swift-synthesize-interface.
def SwiftSynthesizeInterfaceOption : OptionFlag;
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be ideal if we could unify InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface with something like this.

Because right now if these two get out-of-sync, I imagine this tool may produce outputs that would differ from what the compiler would actually do during compilation.

Copy link
Member Author

Choose a reason for hiding this comment

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

I might be missing the connection here, since the primary goal for this mode is to print the synthesized Swift decls for a C/Obj-C/C++ module. What's the failure case you're thinking of? Someone using this with a .swiftinterface file on the search path and having it output something different than the interface that would result from compiling it, someone seeing a mismatch between the textual interface and the synthesized interface of an already compiled .swiftmodule, or something else?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think my mind went in the direction of using a tool like this for Swift code.
It is much less of a concern for C/Obj-C/C++ modules, you're correct.

Someone using this with a .swiftinterface file on the search path and having it output something different than the interface that would result from compiling it, someone seeing a mismatch between the textual interface and the synthesized interface of an already compiled .swiftmodule, or something else?

These are the kinds of failure scenarios I was thinking of, yes.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think my mind went in the direction of using a tool like this for Swift code.
It is much less of a concern for C/Obj-C/C++ modules, you're correct.

Since this tool has a similar interface to swift-symbolgraph-extract, it doesn't take any Swift source files as inputs; it just takes the command line arguments needed to set up the search paths of the compiler instance, and then the module specified by -module-name will be loaded through the standard mechanisms.

However, using it to dump the interface of an already compiled .swiftmodule would still be useful. I tested a couple of the cases you were concerned about, and they fail with the expected diagnostics. For example, if I compile a .swiftinterface and .swiftmodule for iOS and then try to run swift-synthesize-interface with -target arm64-apple-macosx14.0 using either the binary module or the textual interface on the search path, I get the following error:

<unknown>:0: error: module 'Module' was created for incompatible target arm64-apple-ios15.0-simulator

Does that address your concerns?

Copy link
Member Author

Choose a reason for hiding this comment

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

@artemcm Friendly ping—are there any other cases you think I should consider?


// The option should be accepted by swift-api-digester.
def SwiftAPIDigesterOption : OptionFlag;

Expand Down Expand Up @@ -215,15 +218,17 @@ def driver_mode : Joined<["--"], "driver-mode=">, Flags<[HelpHidden]>,

def help : Flag<["-", "--"], "help">,
Flags<[FrontendOption, AutolinkExtractOption, ModuleWrapOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Display available options">;
def h : Flag<["-"], "h">, Alias<help>;
def help_hidden : Flag<["-", "--"], "help-hidden">,
Flags<[HelpHidden, FrontendOption]>,
HelpText<"Display available options, including hidden options">;

def v : Flag<["-"], "v">,
Flags<[DoesNotAffectIncrementalBuild, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
Flags<[DoesNotAffectIncrementalBuild, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Show commands to run and use verbose output">;
def version : Flag<["-", "--"], "version">, Flags<[FrontendOption]>,
HelpText<"Print version information and exit">;
Expand All @@ -236,26 +241,30 @@ def parseable_output : Flag<["-"], "parseable-output">,

def windows_sdk_root : Separate<["-"], "windows-sdk-root">,
Flags<[ArgumentIsPath, FrontendOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Windows SDK Root">, MetaVarName<"<root>">;
def windows_sdk_version : Separate<["-"], "windows-sdk-version">,
Flags<[FrontendOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Windows SDK Version">, MetaVarName<"<version>">;
def visualc_tools_root : Separate<["-"], "visualc-tools-root">,
Flags<[ArgumentIsPath, FrontendOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"VisualC++ Tools Root">, MetaVarName<"<root>">;
def visualc_tools_version : Separate<["-"], "visualc-tools-version">,
Flags<[FrontendOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"VisualC++ ToolSet Version">, MetaVarName<"<version>">;

// Android Options

def sysroot : Separate<["-"], "sysroot">,
Flags<[ArgumentIsPath, FrontendOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption]>,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Native Platform sysroot">, MetaVarName<"<sysroot>">;

// Standard Options
Expand All @@ -265,26 +274,26 @@ def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>,
def o : JoinedOrSeparate<["-"], "o">,
Flags<[FrontendOption, AutolinkExtractOption, ModuleWrapOption,
NoInteractiveOption, ArgumentIsPath, SwiftAPIDigesterOption,
CacheInvariant]>,
SwiftSynthesizeInterfaceOption, CacheInvariant]>,
HelpText<"Write output to <file>">, MetaVarName<"<file>">;

def j : JoinedOrSeparate<["-"], "j">, Flags<[DoesNotAffectIncrementalBuild]>,
HelpText<"Number of commands to execute in parallel">, MetaVarName<"<n>">;

def sdk : Separate<["-"], "sdk">,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption]>,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Compile against <sdk>">, MetaVarName<"<sdk>">;

def swift_version : Separate<["-"], "swift-version">,
Flags<[FrontendOption, ModuleInterfaceOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption]>,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Interpret input according to a specific Swift language version number">,
MetaVarName<"<vers>">;

def language_mode : Separate<["-"], "language-mode">,
Flags<[FrontendOption, ModuleInterfaceOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption]>,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Interpret input according to a specific Swift language mode">,
MetaVarName<"<mode>">,
Alias<swift_version>;
Expand All @@ -306,17 +315,20 @@ def e : Separate<["-"], "e">, Flags<[NewDriverOnlyOption]>,
HelpText<"Executes a line of code provided on the command line">;

def F : JoinedOrSeparate<["-"], "F">,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Add directory to framework search path">;
def F_EQ : Joined<["-"], "F=">, Flags<[FrontendOption, ArgumentIsPath]>,
Alias<F>;

def Fsystem : Separate<["-"], "Fsystem">,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption]>,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Add directory to system framework search path">;

def I : JoinedOrSeparate<["-"], "I">,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
Flags<[FrontendOption, ArgumentIsPath, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Add directory to the import search path">;
def I_EQ : Joined<["-"], "I=">, Flags<[FrontendOption, ArgumentIsPath]>,
Alias<I>;
Expand Down Expand Up @@ -492,7 +504,8 @@ def localization_path : Separate<["-"], "localization-path">,

def module_cache_path : Separate<["-"], "module-cache-path">,
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Specifies the module cache path">;

def enable_library_evolution : Flag<["-"], "enable-library-evolution">,
Expand Down Expand Up @@ -556,11 +569,11 @@ def library_level_EQ : Joined<["-"], "library-level=">,

def module_name : Separate<["-"], "module-name">,
Flags<[FrontendOption, ModuleInterfaceOption,
SwiftSymbolGraphExtractOption]>,
SwiftSymbolGraphExtractOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Name of the module to build">;
def project_name : Separate<["-"], "project-name">,
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
SwiftSymbolGraphExtractOption]>,
SwiftSymbolGraphExtractOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Name of the project this module to build belongs to">;

def module_name_EQ : Joined<["-"], "module-name=">, Flags<[FrontendOption]>,
Expand Down Expand Up @@ -787,7 +800,8 @@ def enable_experimental_cxx_interop :

def cxx_interoperability_mode :
Joined<["-"], "cxx-interoperability-mode=">,
Flags<[FrontendOption, ModuleInterfaceOption, SwiftSymbolGraphExtractOption]>,
Flags<[FrontendOption, ModuleInterfaceOption, SwiftSymbolGraphExtractOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Enables C++ interoperability; pass 'default' to enable or 'off' to disable">;

def experimental_c_foreign_reference_types :
Expand Down Expand Up @@ -1381,7 +1395,9 @@ def num_threads : Separate<["-"], "num-threads">,
def Xfrontend : Separate<["-"], "Xfrontend">, Flags<[HelpHidden]>,
MetaVarName<"<arg>">, HelpText<"Pass <arg> to the Swift frontend">;

def Xcc : Separate<["-"], "Xcc">, Flags<[FrontendOption, SwiftSymbolGraphExtractOption]>,
def Xcc : Separate<["-"], "Xcc">,
Flags<[FrontendOption, SwiftSymbolGraphExtractOption,
SwiftSynthesizeInterfaceOption]>,
MetaVarName<"<arg>">,
HelpText<"Pass <arg> to the C/C++/Objective-C compiler">;

Expand All @@ -1393,13 +1409,16 @@ def Xllvm : Separate<["-"], "Xllvm">,
MetaVarName<"<arg>">, HelpText<"Pass <arg> to LLVM.">;

def resource_dir : Separate<["-"], "resource-dir">,
Flags<[FrontendOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption, HelpHidden, ArgumentIsPath]>,
Flags<[FrontendOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption,
HelpHidden, ArgumentIsPath]>,
MetaVarName<"</usr/lib/swift>">,
HelpText<"The directory that holds the compiler resource files">;

def target : Separate<["-"], "target">,
Flags<[FrontendOption, ModuleWrapOption, ModuleInterfaceOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption]>,
Flags<[FrontendOption, ModuleWrapOption, ModuleInterfaceOption,
SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
SwiftSynthesizeInterfaceOption]>,
HelpText<"Generate code for the given target <triple>, such as x86_64-apple-macos10.9">, MetaVarName<"<triple>">;
def target_legacy_spelling : Joined<["--"], "target=">,
Flags<[FrontendOption]>, Alias<target>;
Expand All @@ -1416,7 +1435,8 @@ def target_variant : Separate<["-"], "target-variant">,
" variant target triple in addition to the main -target triple">;

def clang_target : Separate<["-"], "clang-target">,
Flags<[FrontendOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
Flags<[FrontendOption, SwiftSymbolGraphExtractOption,
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
HelpText<"Separately set the target we should use for internal Clang instance">;

def disable_clang_target : Flag<["-"], "disable-clang-target">,
Expand Down
2 changes: 2 additions & 0 deletions lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ void Driver::parseDriverKind(ArrayRef<const char *> Args) {
.Case("swift-api-digester", DriverKind::APIDigester)
.Case("swift-cache-tool", DriverKind::CacheTool)
.Case("swift-parse-test", DriverKind::ParseTest)
.Case("swift-synthesize-interface", DriverKind::SynthesizeInterface)
.Default(std::nullopt);

if (Kind.has_value())
Expand Down Expand Up @@ -3117,6 +3118,7 @@ void Driver::printHelp(bool ShowHidden) const {
case DriverKind::APIDigester:
case DriverKind::CacheTool:
case DriverKind::ParseTest:
case DriverKind::SynthesizeInterface:
ExcludedFlagsBitmask |= options::NoBatchOption;
break;
}
Expand Down
1 change: 1 addition & 0 deletions lib/DriverTool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(driver_sources_and_options
swift_cache_tool_main.cpp
swift_indent_main.cpp
swift_symbolgraph_extract_main.cpp
swift_synthesize_interface_main.cpp
swift_parse_test_main.cpp)

set(driver_common_libs
Expand Down
8 changes: 8 additions & 0 deletions lib/DriverTool/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ extern int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
extern int swift_symbolgraph_extract_main(ArrayRef<const char *> Args, const char *Argv0,
void *MainAddr);

/// Run 'swift-synthesize-interface'
extern int swift_synthesize_interface_main(ArrayRef<const char *> Args,
const char *Argv0, void *MainAddr);

/// Run 'swift-api-digester'
extern int swift_api_digester_main(ArrayRef<const char *> Args,
const char *Argv0, void *MainAddr);
Expand Down Expand Up @@ -387,6 +391,10 @@ static int run_driver(StringRef ExecName,
argv[0], (void *)(intptr_t)getExecutablePath);
case Driver::DriverKind::SymbolGraph:
return swift_symbolgraph_extract_main(TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], (void *)(intptr_t)getExecutablePath);
case Driver::DriverKind::SynthesizeInterface:
return swift_synthesize_interface_main(
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
(void *)(intptr_t)getExecutablePath);
case Driver::DriverKind::APIDigester:
return swift_api_digester_main(
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
Expand Down
Loading