Swift 语言中的“@_silgen_name”是什么?

What is '@_silgen_name' in Swift language?

在阅读 Swift 2.2 中的 Darwin 库时,我发现了以下代码。

@warn_unused_result
@_silgen_name("_swift_Darwin_sem_open2")
internal func _swift_Darwin_sem_open2(
  name: UnsafePointer<CChar>,
  _ oflag: CInt
) -> UnsafeMutablePointer<sem_t>

第二行的'@_silgen_name'是什么?

我从 here 中找到了以下信息,但我想要更详细的信息,例如 Apple Developer Library。

If it’s just a specific set of Swift functions you want to call from C, you can use the @_silgen_name attribute to override the mangled name, and/or make them @convention(c) to use the C calling convention.

@_silgen_name 最近刚从 @asmname (see the following commit) 重命名,提交消息如下:

This reflects the fact that the attribute's only for compiler-internal use, and isn't really equivalent to C's asm attribute, since it doesn't change the calling convention to be C-compatible.

因此,作为一般的 Swift 开发人员,人们不会遇到此属性,除非将 Swift 移植到其他平台。

现在,@_silgen_name 是 class SILGenNameAttr 的属性(宏),带有某些选项,其中后者是 Swifts [=31= 的一部分])

// Schema for DECL_ATTR:
//
// - Attribute name.
// - Class name without the 'Attr' suffix (ignored for
// - Options for the attribute, including:
//    * the declarations the attribute can appear on
//    * whether duplicates are allowed
//    * whether the attribute is considered a decl modifier or not (no '@')
// - Unique attribute identifier used for serialization.  This
//   can never be changed.
//
// SIMPLE_DECL_ATTR is the same, but the class becomes
// SimpleDeclAttr<DAK_##NAME>.
//

DECL_ATTR(_silgen_name, SILGenName,
          OnFunc | OnConstructor | OnDestructor | LongAttribute |
          UserInaccessible, 0)

我们在swift/AST/Attr.h中找到SILGeneNameAttr的声明:

/// Defines the @_silgen_name attribute.
class SILGenNameAttr : public DeclAttribute {
public:
  SILGenNameAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
    : DeclAttribute(DAK_SILGenName, AtLoc, Range, Implicit),
      Name(Name) {}

  SILGenNameAttr(StringRef Name, bool Implicit)
    : SILGenNameAttr(Name, SourceLoc(), SourceRange(), /*Implicit=*/true) {}

  /// The symbol name.
  const StringRef Name;

  static bool classof(const DeclAttribute *DA) {
    return DA->getKind() == DAK_SILGenName;
  }
};

综上所述;它与为 C 函数提供 Swift 接口有关。您很可能很难在开发人员库中找到有关 SILGenNameAttr 的任何详细信息,并且可以将其视为未记录的功能。


最后,您可能会对以下与 Russ Bishop 的谈话感兴趣:

The Toolbox: Here there be dragons (34:20)

I would not ship this in a production application under any circumstances. But if you’re feeling adventurous, here they are.

@asmname is an attribute to decorate a function. You definitely need to understand the ABI to use this one. Swift will not help you marshall the parameters very much. The compiler is not going to be very forgiving, so you have to make sure that you’ve manipulated your parameters into a format it’s compatible with. The following code shows how to declare it. Give the function attribute, @asmname, and the string symbol; then function its arguments in return type. The compiler will not complain if you get the arguments wrong or return type incorrectly. It only expects that that symbol exists, and when it jumps to it, it better take those arguments and have that return type.

@asmname("dispatch_get_current_queue") func _get_current_queue() -> dispatch_queue_t

Q&A (37:08)

Q: Obviously not all of these are documented by Apple, so what’s your process of discovering all these behaviors?

Russ: I’ll look at the documentation first, but you’re right that there is a lot of stuff that isn’t in there. If you go to the Swift REPL and use the flag — I think it’s something like -deprecated-integrated-repl — you can ask it to print the Swift module and all the bits that Xcode doesn’t show you. If you dig into the toolchain directory Xcode, you can also find stuff in libswiftCore and libswiftRuntime.

JP: If you’re interested in doing some more unsafe things with Swift, you can do a code search in GitHub for @asmname and language “Swift”, and you’ll see a bunch of really bad but interesting stuff.

来自 Bishops 博客的年龄稍大的 post:

...

First off notice the @asmname attribute. This is the equivalent of DllImport or extern. It tells Swift that we are going to link in some library that defines a function with the given name and matching the given arguments. "Just trust me Swift, I know what I'm doing". Hint: You had better know what you're doing.

简而言之, @_silgen_name 定义共享库中显示的函数名称。

Glibc.swift 表示已定义 _swift_Glibc_open。

你可以通过nm /usr/lib/swift/linux/libswiftGlibc.so这样看。

00000000000016f0 t _swift_Glibc_fcntl
0000000000001700 t _swift_Glibc_fcntlPtr
00000000000016b0 t _swift_Glibc_open
00000000000016c0 t _swift_Glibc_openat
00000000000016d0 t _swift_Glibc_sem_open2
00000000000016e0 t _swift_Glibc_sem_open4