我想在Swift中做一些类似于目前在Objective-C/C++中所做的事情,所以我首先来描述这个。
我有一些现有的C代码定义了一个宏,当在代码中的任何地方使用表达式时,将在编译时将一个条目插入到二进制文件的表中。换句话说,用户写这样的东西:
#include "magic.h" void foo(bool b) { if (b) { printf("%d\n",MAGIC(xyzzy)); } }
并感谢定义
#define MAGIC(Name) \ []{ static int __attribute__((used,section("DATA,magical"))) Name; return Name; }()
编译时实际发生的是一个名为xyzzy(modulo name-mangling)的静态变量被创建并分配到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
通过getsectbynamefromheader()的魔力,我可以加载魔法部分的符号表,扫描它,并通过用户代码中的某个点找出(通过拆除我找到的每个符号),他称之为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); }
这是有用的,但它有一些额外的打字,不能在表达式内联(不是那么重要,如果我们不能在Swift无法制作MAGIC宏),我担心Swift编译器可能会优化它。
所以,这里有三个问题,所有关于如何使Swift做Swift不想做的事情:宏,属性和创建符合编译器优化的符号。
我知道@asmname,但我不认为这有助于我,因为我已经可以处理我自己的孤儿了。
我知道Swift有“泛型”,但他们似乎更接近于Java泛型而不是C模板;在这种情况下,我不认为它们可以用来代替宏。
我知道Swift编译器is now open-source的代码;我已经白费了一点点但是我看不到所有的东西寻找可能甚至不在的技巧。
Swift has no preprocessor,so spelling the magic as elegantly as MAGIC(someidentifier) is impossible. I don’t want it to be too ugly,though.
Swift项目有一个预处理器(但是,AFAIK,它不是用Swift的二进制文件分发的)。
从swift-users邮件列表中:
It’s a preprocessor the Swift
team wrote so that when they needed to build,say,ten nearly-identical
variants of Int,they wouldn’t have to literally copy and paste the same
code ten times. If you open one of those files,you’ll see that they’re
mainly Swift code,but with some lines of code intermixed that are written in Python.
它不像C宏一样美丽,但是,IMHO更强大。
在克隆Swift的git repo后,您可以使用./swift/utils/gyb –help命令查看可用的命令。
$ swift/utils/gyb --help
使用等(TL; DR)…
Example template: - Hello - %{ x = 42 def succ(a): return a+1 }% I can assure you that ${x} < ${succ(x)} % if int(y) > 7: % for i in range(3): y is greater than seven! % end % else: y is less than or equal to seven % end - The End. - When run with "gyb -Dy=9",the output is - Hello - I can assure you that 42 < 43 y is greater than seven! y is greater than seven! y is greater than seven! - The End. -
我的GYB使用示例可在GitHub.Gist。
对于更复杂的示例,请在@apple/swift/stdlib/public/core中查找* .swift.gyb文件。