这是一个奇怪的,不是斯威夫特式的问题,所以请耐心等待 我想在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
的静态变量(模名称修改)并将其分配到我的Mach的特殊magical
部分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);
}
虽然有效,但它有点额外打字,并且无法在表达式中内联完成(如果我们无法生成{{1,那就不重要了无论如何,在Swift中都有宏),我担心Swift编译器可能会优化它。
所以,这里有三个问题,关于如何让Swift做Swift不想做的事情:宏,属性和创建符合编译器优化的符号。
我知道MAGIC
但我不认为它对我有帮助,因为我已经可以自己解决这个问题。
我知道Swift有#34; generics",但它们似乎更接近Java泛型而不是C ++模板;在这种特殊情况下,我不认为它们可以用作宏的替代品。
我知道Swift编译器is now open-source的代码;我徒劳地撇去了一些东西;但是我无法通过所有来阅读它甚至可能不存在的技巧。
答案 0 :(得分:2)
以下是关于预处理器(和宏)的问题的答案。
Swift没有预处理器,因此像MAGIC(someidentifier)一样优雅地拼写魔法是不可能的。不过,我不希望它过于丑陋。
Swift项目有一个预处理器(但是,AFAIK,它没有随Swift的二进制文件一起发布)。
来自swift-users
邮件列表:
这是Swift的预处理器 团队写作,以便当他们需要建立,比如,十几乎相同 Int的变体,他们不必逐字复制和粘贴相同的 代码十次。如果你打开其中一个文件,你会发现它们是 主要是Swift代码,但有一些代码行混合在一起,用Python编写。
它没有C宏那么漂亮,但是,恕我直言,更强大。
克隆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. -
我在GitHub.Gist上提供了GYB使用示例。
有关更复杂的示例,请在@apple/swift/stdlib/public/core中查找*.swift.gyb
个文件。