RFC: auto-linking IR proposal

Hi all,

We plan to add some auto-linking support for Mach-O, and need a scheme for encoding this information in the LLVM IR. We would like the same scheme to be able to support Microsoft’s #pragma comment(lib,…) and #pragma comment(library, …) features eventually.

The current proposal is as follows:

Hi all,

We plan to add some auto-linking support for Mach-O, and need a scheme for
encoding this information in the LLVM IR. We would like the same scheme to
be able to support Microsoft's #pragma comment(lib,...) and #pragma
comment(library, ...) features eventually.

The current proposal is as follows:

--

#1. Extend module-level metadata flags (llvm.module.flags) to support two
new behaviors:

llvm::Module::Append - The value must be a list. Module flags with
equivalent unique IDs and this behavior will be appended in the order that
they are linked.

llvm::Module::AppendUnique - The value must be a list. As with
llvm::Module::Append, module flags with equivalent unique IDs are appended
in the order that they are linked. However, identical MDNodes will only
appear once in the list (at the earliest seen position).

#2. Define a new "known" module level flag metadata "Linker Options" which
is a list of lists of metadata strings corresponding to linker options. This
metadata flag will use the llvm::Module::AppendUnique option.

The options are expected to be linker specific (thus target specific), we
make no attempt to encode the intent of the options at the IR level. The
frontend is responsible for selecting appropriate options based on the
target.

The module level linker will only unique option lists, any diagnosis of
otherwise redundant or conflicting options is expected to be handled by the
linker.

Example metadata for a module which is expected to link against libz and the
Cocoa framework::

  !0 = metadata !{ i32 6, "Linker Options",
     metadata !{
        !metadata { metadata !"-lz" },
        !metadata { metadata !"-framework", metadata !"Cocoa" } } }
  !llvm.module.flags = !{ !0 }

--

We have debated whether or not there is value in adopting a more strict
schema for the metadata (i.e., declare intent more explicitly by encoding
things like static library vs dynamic library vs framework library instead
of using target-specific linker options). However, as we have no expectation
that the compiler will want to inspect this data, it seems like this adds
complexity (and reduces flexibility) for no benefit. It does, however, have
the downside that the frontend needs to participate (and have target linker
knowledge) in order to use the appropriate options.

Other points of discussion:

#1. On Mach-O, the linker will expect and enforce that each list of options
corresponds to a single library. This will not be enforced (nor is it
enforceable) at the IR level, and other targets wouldn't have this
restriction (Visual Studio supports inclusion of some arbitrary flags).

#2. On Microsoft, #pragma comment(linker, ...) will map naturally to this
format. How #pragma comment(lib, ...) gets handled will probably depend on
the details of how this is encoded in the COFF object files, which I am not
yet familiar with.

On COFF #pragma comment(lib, ...) just gets turned into a linker flag
in the .drectve section.

#3. We make no attempt to encode ordering information amongst the options,
which limits the utility for linking against static libraries. The current
expectation is that this feature be used for system libraries where the
order of the options is not important. A schema that would allow encoding
dependencies amongst libraries to be auto-linked would be substantially more
complicated and is outside the scope of this proposal.

What do you mean by amongst the options? #pragma comment(lib, ...)
requires that the options are added in the order they occur in the
source file. This should be trivial to implement in the metadata.

Please let me know if you have an opinion on this works, particularly if you
want to chime in on how this might interact with ELF or COFF.

- Daniel

I don't know of any ELF implementation that currently supports this in
general, but adding it should't be too hard.

Go does automatic linking, but it now has its own object file format
that handles it. gccgo for ELF seems to produce .go_export sections
and <package>..import symbols which are both specific to Go.

- Michael Spencer

Hi Michael,

Thanks for the feedback.

Hi Daniel,

Nice to meet you.

My understanding of the Microsoft #pragma comment(lib, ...) semantics is that
each specified library will be converted into a directive that starts with
"/DEFAULTLIB" in the COFF .drectve section. To demonstrate, the following patch
produces directives that work with Visual Studio 2010 using the now-deprecated
dependent library feature (commits r168779 and r168694).

/* beginning of patch */

Index: /home/ygao/LLVM/llvm/lib/Target/X86/X86AsmPrinter.cpp

Hi Gao,

Thanks for the extra information…

Hi Daniel,

My understanding of the Microsoft #pragma comment(lib, ...) semantics is that
each specified library will be converted into a directive that starts with
"/DEFAULTLIB" in the COFF .drectve section. To demonstrate, the following patch
produces directives that work with Visual Studio 2010 using the now-deprecated
dependent library feature (commits r168779 and r168694).

Is that feature now-deprecated? The documentation here:
http://msdn.microsoft.com/en-us/library/7f0aews7.aspx
only talks about the "exestr" comment type being deprecated.
I see that the /defaultlib flag itself to the linker is deprecated, but it isn't clear to me that that means the dependent library feature is also deprecated.

To clarify, at one point LLVM IR had a way to list dependent libraries in the form of
deplibs = [ "blah.lib", "foo.lib" ]

This feature was later removed in llvm commit r168694, which is what I referred to as being deprecated. i.e., I was not saying that the MSVC defaultlib flag is being deprecated.

- Gao.

Hi Daniel,

>> My understanding of the Microsoft #pragma comment(lib, ...) semantics
is that
>> each specified library will be converted into a directive that starts
with
>> "/DEFAULTLIB" in the COFF .drectve section. To demonstrate, the
following patch
>> produces directives that work with Visual Studio 2010 using the
now-deprecated
>> dependent library feature (commits r168779 and r168694).

> Is that feature now-deprecated? The documentation here:
> http://msdn.microsoft.com/en-us/library/7f0aews7.aspx
> only talks about the "exestr" comment type being deprecated.
> I see that the /defaultlib flag itself to the linker is deprecated, but
it isn't clear to me that that means the dependent library feature is also
deprecated.

To clarify, at one point LLVM IR had a way to list dependent libraries in
the form of
deplibs = [ "blah.lib", "foo.lib" ]

This feature was later removed in llvm commit r168694, which is what I
referred to as being deprecated. i.e., I was not saying that the MSVC
defaultlib flag is being deprecated.

Ah, yes! I had completely forgotten about that.

Unlike that feature, which had some semantics the IR would try to handle
(it could be used to reference libraries of bitcode the IR linker would try
and handle), the expectation is that the IR layers will not inspect or
otherwise manipulate the Linker Options flags other than to merge them
following the module flags behavior.

- Daniel