这是一个奇怪的,非Swift-thonic的问题,所以请耐心等待.
我想在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; }()
在编译时实际发生的是创建一个名为(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
通过魔术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); }
这是有效的,但它有点额外的输入,并且无法在表达式中内联完成(如果我们无法MAGIC
在Swift中创建一个宏那么重要),我担心Swift编译器可能会优化它.
所以,这里有三个问题,关于如何让Swift做一些Swift不想做的事情:宏,属性和创建符合编译器优化的符号.
我知道@asmname
但是我认为这对我没有帮助,因为我已经可以自己处理demangling了.
我知道Swift有"泛型",但它们似乎更接近Java泛型而不是C++模板; 在这种特殊情况下,我认为它们不能用作宏的替代品.
我知道Swift编译器的代码现在是开源的 ; 我撇去了一些徒劳的东西; 但我无法通读所有寻找甚至可能不存在的技巧.