-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add '-emit-archive' option to mark modules as being part of static libraries #25088
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
Conversation
This isn't even really ready to look at - this cannot generate static libraries yet as |
include/swift/Option/Options.td
Outdated
@@ -368,6 +368,10 @@ def emit_objc_header_path : Separate<["-"], "emit-objc-header-path">, | |||
ArgumentIsPath]>, | |||
MetaVarName<"<path>">, HelpText<"Emit an Objective-C header file to <path>">; | |||
|
|||
def emit_archive : Flag<["-"], "emit-archive">, | |||
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave it to @jrose-apple to decide if this is how this should happen, but if this is going to affect the module, then it should go in FrontendOptions and have the ModuleInterfaceOption
flag added, so it is included in the set of command-line flags that go into a .swiftinterface
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a driver flag as well as a frontend flag, so this is the correct file, but Harlan is correct that it is a ModuleInterfaceOption
, and it certainly does affect the incremental build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If ModuleInterfaceOption
ensures it's automatically serialised, does that mean the IsStaticLibrary
flag I've added elsewhere is redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More specifically: I see that CompilerInstance::getMainModule
copies the frontend arguments to the main module; does that also apply to deserialised modules or are the options_block::IS_STATIC_LIBRARY
and serialization::ExtendedValidationInfo
changes necessary?
The main reasons I put this up were to make sure I was adding the flag in the right place, have the serialisation logic checked, and to have the DLL storage changes looked over. In terms of generating static libraries:
|
Ish - that needs a bit of a tweak to be truly portable. BSD uses a BSD style archive and you need to indicate that (as |
4b7e6c1
to
9fd991d
Compare
I've updated the PR with a minimum-viable invocation of If the implementation looks good, I'll make a start on tests – just want to make sure I'm not testing incorrect behaviour. |
b86c603
to
d82e47a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty reasonable to me, but I suggest breaking up the Driver and Frontend parts into two PRs. We can get static linking working on Linux and macOS first (or even just Linux for now), then move on to Windows.
include/swift/Option/Options.td
Outdated
@@ -368,6 +368,10 @@ def emit_objc_header_path : Separate<["-"], "emit-objc-header-path">, | |||
ArgumentIsPath]>, | |||
MetaVarName<"<path>">, HelpText<"Emit an Objective-C header file to <path>">; | |||
|
|||
def static_library : Flag<["-"], "static">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: the name of the option should match the name of the flag. (It'll get concatenated to OPT_
so it shouldn't collide. Unless you already tried it and I'm wrong?)
lib/Driver/Driver.cpp
Outdated
@@ -1371,10 +1373,15 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, | |||
break; | |||
|
|||
case options::OPT_emit_library: | |||
OI.LinkAction = LinkKind::DynamicLibrary; | |||
OI.LinkAction = Args.hasArg(options::OPT_static_library) ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably worth complaining when using -static
with -emit-executable
.
include/swift/Driver/Action.h
Outdated
assert(K == LinkKind::StaticLibrary); | ||
} | ||
|
||
LinkKind getKind() const { return LinkKind::StaticLibrary; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably don't need this. I appreciate it being passed in to the constructor, though.
|
||
} | ||
if (AR == nullptr) { | ||
if (auto pathAR = llvm::sys::findProgramByName("llvm-ar", None)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we actually want to prefer llvm-ar
like this, and I'm not sure whether this belongs in the default ToolChain either (rather than GenericUnix). On Apple platforms, libtool -static
is what Xcode uses to create static libraries, not ar
.
@cooperp, what's the current recommendation on this? ar
or libtool
for static libraries on Apple platforms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's libtool. Otherwise you tend to have to call ranlib after ar, while the man page for libtool says it can handle both for you: "Libtool with -static is intended to replace ar(5) and ranlib."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@compnerd, is what’s here what we want on both GenericUnix and Windows, or should the behaviour differ? If llvm-ar
is unavailable on Windows should we fall back to LIB.exe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cooperp - thats the trick wrt ar crs
- it creates the index as part of the invocation. With llvm-ar
that also means that we can invoke it as ar --format bsd crs ...
which will create the BSD style archive with the index even on a non-BSD host.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Xcode doesn't ship with llvm-ar
. Please stick to libtool
on Darwin. (In general, please stick to "what Xcode does when you make a static library from a template".)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but it does ship with ar
from cctools, which also supports the crs
mode. The problem is that you lose compatibility with AT&T Unix, which I believe didn't support the s
option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I'll let @cooperp decide what's right here. We already aren't getting code sharing because the Darwin toolchain deliberately isn't a GenericUnix toolchain, on account of Apple doing weird things having more control over the tools it ships.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cooperp, what do you think is best here?
lib/Driver/ToolChains.cpp
Outdated
|
||
if (isLLVMAR) { | ||
switch (getTriple().getOS()) { | ||
case llvm::Triple::Darwin: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting nitpick: no indentation for switch cases.
lib/Driver/Driver.cpp
Outdated
@@ -1368,18 +1368,20 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, | |||
|
|||
switch (OutputModeArg->getOption().getID()) { | |||
case options::OPT_emit_executable: | |||
assert(!Args.hasArg(options::OPT_static) && | |||
"-static may not be used with -emit-executable."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be an assertion; it should be a proper diagnostic somewhere for a user who doesn't know.
I think this is almost ready for tests (and splitting out the frontend parts into a separate PR). However, I'm still not sure about what we want to do for That has some issues for Linux/Windows <-> Darwin cross-compilation; however, since the Linux and Windows archive formats are apparently the same Linux <-> Windows should just work with the default linker. Not sure what to do about the Darwin case – we could maybe use |
Let's worry about cross-compilation later. Using |
The driver portion of this PR has been extracted into #25202 |
@jrose-apple - |
It might be present. It's not installed by default, and I don't think we want it to be. Nor do I think we should automatically look for LLVM variants of tools; it'd be better to just allow overriding them in general. |
Do we currently have a general way of overriding the tools? I'm only aware of I'm also perfectly happy (and would probably prefer) to just drop support from anything other than the system default tools in the PR rather than trying to scope-creep a more general solution. |
Yeah, I was more talking about future expansion. I only care about the system tools. @compnerd, however, has been cultivating cross-compilation stacks for a while now, so I see the tendency to not box ourselves into a situation where we can't support cross-compilation. |
FWIW swiftpm (llbuild) uses ar to create libraries. Should we change that to use libtool on macOS as mentioned above, or is ar an acceptable choice for here too? (Since this was discussed above) |
@troughton Are you still pursuing this? |
Thanks. I can file an SR for somebody to finish this up of you’d like. |
There's already https://bugs.swift.org/browse/SR-10797 filed which was the main blocking piece of work. Once that's fixed (assuming it hasn't been already) I can revisit this patch, but I'll close it for now. |
Following discussion here, this is a draft PR to add a
-emit-archive
option to Swift that controls the linkage of symbols within Swift modules (and potentially more in the future).The core problem is that Windows needs different linkage – DLL import vs. default – for shared vs. static libraries. For Swift, cache whether a module is built as a static or shared library on a per-module basis, and use that to determine what linkage should be applied.
cc @compnerd