内联如何与外部库一起使用? (Swift)

How does inlining work with external libraries? (Swift)

属性@inline(__always) 强制编译器内联特定函数。外部库提供的代码如何内联到一个项目中?编译器是否真的从库的可执行文件中复制代码段?

据我所知,@inline(__always) 意味着函数(或类似函数)始终是内联的,无论如何。这意味着它的符号在编译模块中公开,因此它们可以被使用该模块的项目内联。因此 "always".

这主要是一个未记录的属性,我能找到的唯一官方参考是在一些 stdlib 开发者的 internal  documentation, not even describing its behavior directly. The best unofficial documentation I can find is Vandad Nahavandipoor's disassembly-confirmed investigation into its behavior 中,它没有试图确认您关注的跨模块用例。


Swift4.2,@inlinable and @usableFromInline were introduced完成这个故事。

我的理解:

  • @inline(__always) 强制函数(等)每次内联,无论它们在哪里声明或使用
  • @inlinable 允许将模块中的函数(等)内联到该模块中的调用代码中,或调用使用该模块的代码,如果编译器认为有必要的话
  • 如果编译器认为有必要,
  • @usableFromInline 允许将模块内部的函数(等)内联到 @inlinable 调用也在该模块中的代码中。不像@inlinable,这些必须internal;他们不能public

根据Swift.org:

inlinable

Apply this attribute to a function, method, computed property, subscript, convenience initializer, or deinitializer declaration to expose that declaration’s implementation as part of the module’s public interface. The compiler is allowed to replace calls to an inlinable symbol with a copy of the symbol’s implementation at the call site.

Inlinable code can interact with public symbols declared in any module, and it can interact with internal symbols declared in the same module that are marked with the usableFromInline attribute. Inlinable code can’t interact with private or fileprivate symbols.

This attribute can’t be applied to declarations that are nested inside functions or to fileprivate or private declarations. Functions and closures that are defined inside an inlinable function are implicitly inlinable, even though they can’t be marked with this attribute.

usableFromInline

Apply this attribute to a function, method, computed property, subscript, initializer, or deinitializer declaration to allow that symbol to be used in inlinable code that’s defined in the same module as the declaration. The declaration must have the internal access level modifier. A structure or class marked usableFromInline can use only types that are public or usableFromInline for its properties. An enumeration marked usableFromInline can use only types that are public or usableFromInline for the raw values and associated values of its cases.

Like the public access level modifier, this attribute exposes the declaration as part of the module’s public interface. Unlike public, the compiler doesn’t allow declarations marked with usableFromInline to be referenced by name in code outside the module, even though the declaration’s symbol is exported. However, code outside the module might still be able to interact with the declaration’s symbol by using runtime behavior.

Declarations marked with the inlinable attribute are implicitly usable from inlinable code. Although either inlinable or usableFromInline can be applied to internal declarations, applying both attributes is an error.