Swift:__attribute的宏__((section))

Quu*_*one 23 metaprogramming mach-o swift swift2

这是一个奇怪的,非Swift-thonic的问题,所以请耐心等待.
我想在Swift中做类似于我目前在Objective-C/C++中所做的事情,所以我将从描述它开始.

我有一些现有的C++代码定义了一个宏,当在代码中的任何地方使用表达式时,它会在编译时将一个条目插入到二进制文件的表中.换句话说,用户写这样的东西:

#include "magic.h"

void foo(bool b) {
    if (b) {
        printf("%d\n", MAGIC(xyzzy));
    }
}
Run Code Online (Sandbox Code Playgroud)

并感谢定义

#define MAGIC(Name) \
  []{ static int __attribute__((used, section("DATA,magical"))) Name; return Name; }()
Run Code Online (Sandbox Code Playgroud)

在编译时实际发生的是创建一个名为(modulo name-mangling)的静态变量xyzzy并将其分配到magical我的Mach-O二进制文件的特殊部分中,因此运行nm -m foo.o转储符号会显示如下内容:

0000000000000098 (__TEXT,__eh_frame) non-external EH_frame0
0000000000000050 (__TEXT,__cstring) non-external L_.str
0000000000000000 (__TEXT,__text) external __Z3foob
00000000000000b0 (__TEXT,__eh_frame) external __Z3foob.eh
0000000000000040 (__TEXT,__text) non-external __ZZ3foobENK3$_0clEv
00000000000000d8 (__TEXT,__eh_frame) non-external __ZZ3foobENK3$_0clEv.eh
0000000000000054 (__DATA,magical) non-external [no dead strip] __ZZZ3foobENK3$_0clEvE5xyzzy
                 (undefined) external _printf
Run Code Online (Sandbox Code Playgroud)

通过魔术getsectbynamefromheader(),然后我可以加载该magical部分的符号表,扫描它,并找出(通过解码我找到的每个符号),在用户代码的某个点,他调用MAGIC(xyzzy).找到了!


我可以在Swift中复制整个工作流程的后半部分 - 从getsectbynamefromheader()部分开始.但是,第一部分让我难过.

  • Swift没有预处理器,所以拼写魔法尽可能优雅MAGIC(someidentifier).不过,我不希望它太难看.

  • 据我所知,Swift没有办法在给定的部分插入符号 - 没有相应的__attribute__((section)).不过,这是可以的,因为我的计划中没有任何内容需要专门的部分; 那部分只是让后半部分更容易.

  • 据我所知,在Swift中将符号放入符号表的唯一方法是通过本地结构定义.像这样的东西:

    func foo(b: Bool) -> Void {
        struct Local { static var xyzzy = 0; };
        println(Local.xyzzy);
    }
    
    Run Code Online (Sandbox Code Playgroud)

这是有效的,但它有点额外的输入,并且无法在表达式中内联完成(如果我们无法MAGIC在Swift中创建一个宏那么重要),我担心Swift编译器可能会优化它.


所以,这里有三个问题,关于如何让Swift做一些Swift不想做的事情:宏,属性和创建符合编译器优化的符号.

我知道@asmname但是我认为这对我没有帮助,因为我已经可以自己处理demangling了.

我知道Swift有"泛型",但它们似乎更接近Java泛型而不是C++模板; 在这种特殊情况下,我认为它们不能用作宏的替代品.

我知道Swift编译器的代码现在是开源的 ; 我撇去了一些徒劳的东西; 但我无法通读所有寻找甚至可能不存在的技巧.

tie*_*tie 2

这是有关预处理器(和宏)的问题的答案。

\n\n
\n

Swift 没有预处理器,因此像 MAGIC(someidentifier) 一样优雅地拼写魔法是不可能的。不过我不想让它变得太难看。

\n
\n\n

Swift 项目有一个预处理器(但是,据我所知,它不随 Swift 的二进制文件一起分发)。

\n\n

来自swift-users邮件列表:

\n\n

什么是 .swift.gyb 文件?

\n\n
\n

它\xe2\x80\x99 是 Swift\n 团队编写的一个预处理器,这样当他们需要构建十个几乎相同\n 的 Int 变体时,\xe2\x80\x99 就不必逐字复制并粘贴相同的\n代码十次。如果您打开这些文件之一,您\xe2\x80\x99将看到它们\xe2\x80\x99主要是Swift代码,但混合了一些用Python编写的代码行。

\n
\n\n

它不像 C 宏那么漂亮,但是,恕我直言,它更强大。 \n./swift/utils/gyb --help克隆 Swift 的 git 存储库后,您可以使用 command 查看可用命令。

\n\n
$ swift/utils/gyb --help\n
Run Code Online (Sandbox Code Playgroud)\n\n

用法等(TL;DR)...

\n\n
Example template:\n\n      - Hello -\n    %{\n         x = 42\n         def succ(a):\n             return a+1\n    }%\n\n    I can assure you that ${x} < ${succ(x)}\n\n    % if int(y) > 7:\n    %    for i in range(3):\n    y is greater than seven!\n    %    end\n    % else:\n    y is less than or equal to seven\n    % end\n\n      - The End. -\n\nWhen run with "gyb -Dy=9", the output is\n\n      - Hello -\n\n    I can assure you that 42 < 43\n\n    y is greater than seven!\n    y is greater than seven!\n    y is greater than seven!\n\n      - The End. -\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的 GYB 使用示例可以在GitHub.Gist上找到。

\n\n

对于更复杂的示例,请在@apple/swift/stdlib/public/core中查找*.swift.gyb文件。

\n