Это своего рода странный и не-Swift-тонический вопрос, так что несите меня. Я хочу сделать в Swift что-то вроде того, что я сейчас делаю в Objective-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) создается и выделяется в специальный раздел 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); }
Это работает, но это немного лишний ввод текста и не может быть сделано inline в выражении (не то, что будет иметь значение, если мы не сможем сделать макрос MAGIC
в Swift в любом случае) м беспокоился, что компилятор Swift может его оптимизировать.
Итак, здесь три вопроса, все о том, как заставить Swift делать то, что Swift не хочет делать: макросы, атрибуты и создание символов, которые устойчивы к оптимизации компилятора.
Я знаю @asmname
, но я не думаю, что это помогает мне, так как я уже могу справиться с деманлингом самостоятельно.
Я знаю, что у Swift есть "generics", но они, похоже, ближе к Java-генераторам, чем к шаблонам С++; Я не думаю, что они могут использоваться в качестве замены макросов в этом конкретном случае.
Я знаю, что код для компилятора Swift теперь открыт с открытым исходным кодом; Я потратил его впустую; но я не могу прочитать все это, глядя на трюки, которые могут даже не быть там.