The problem I see with this is embeddability and code duplication.
Programmatically setting up a link with common options for the target
platform should be trivial, this complicates that by requiring manual
setup of the process.
I was discussing this problem with Chandler, in addition to how to
share option parsing code with Clang. The general idea is to have a
tablegen file for canonical options (e.g. cc1 options in Clang). Then
each specific (ld64, gnu-ld, link.exe) driver would get a td file that
mapped each option to one or more canonical options either by a common
mapping operation, or calling a custom function.
- Michael Spencer
Ok. We need the non-command-line-parse part of main() to be available for use by clients that are embedding linker functionality into other programs, and tablegen could be a nice way to manage the options. Then my modified proposal is:
1) llvm provides utilities to make command line parsing easy, possibly tablegen based. For embedded linking, it should be easy to programmatically set these options and the defaults should all be reasonable.
2) lld/Core providing utilities for managing search paths (for finding input files).
3) Each platform has a link() function which:
3a) is called by the static linker's main() after command line options are parsed
3b) uses the options to set up the ResolverOptions
3c) calls Core/Resolver
3d) calls appropriate Passes (may depend on command line options)
3e) calls its platform executable writer, which can access the parsed command line options.
One design point I think is important is to encapsulate the parsed command line options into some class/struct/namespace. It should not be a bunch of global variables (like llvm::opt<> leads to). If you want to embed a compiler and linker into one program, you don't want conflicting global variables.
+1 to this last point in particular. It's important to be able to serialize that state. For example, we'll want to be able to dump out a human-readable version to help debug problems where such a combined program fails to link, but we want to reproduce the problem manually w/ a standalone linker. Being able to dump the intermediate files and a state description for the linker should allow us to generate a recipe for "run the linker w/ these options on these files and you'll see the same behavior the combined program is getting).
Well since we have that YAML parser handy…
I definitely think that there should be a ‘–recipe=foo.yaml’ commandline option, which in a straightforward and transparent way calls down into
ExecuteRecipe("foo.yaml"), or similar. There can be a couple overloads for ExecuteRecipe, one taking an in-memory YAML structure, etc. The different drivers can then basically amount to something like
It might pay to put an extra layer between YAML and the libraries, which is basically a TableGen’d “schema” for the data in the human-readable YAML, with a 1-1 correspondence so it is easy to go back and forth between them for debugging; the goal of this extra layer would be to make it more natural (and faster) to pass around in the libraries since it is just “regular C++”, and not some YAML node.