Swift: макрос для __ атрибута __ ((раздел))
Это своего рода странный и не-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 теперь открыт с открытым исходным кодом; Я потратил его впустую; но я не могу прочитать все это, глядя на трюки, которые могут даже не быть там.
Ответы
Ответ 1
Вот ответ на ваш вопрос о препроцессоре (и макросах).
У Swift нет препроцессора, поэтому написание волшебства так же элегантно, как MAGIC (someidentifier) невозможно. Я не хочу, чтобы это было слишком уродливо.
В проекте Swift есть препроцессор (но AFAIK, он не распространяется с помощью двоичного файла Swift).
Из swift-users
списка рассылки:
Что такое файлы .swift.gyb?
Его препроцессор Swift команда написала так, что, когда им нужно было построить, скажем, десять почти одинаковых варианты Int, им не пришлось бы буквально копировать и вставлять те же код десять раз. Если вы откроете один из этих файлов, вы увидите, что theyre в основном Swift, но с некоторыми смежными парами кода, написанными на Python.
Это не так красиво, как макросы C, но, IMHO, является более мощным.
Вы можете увидеть доступные команды с помощью команды ./swift/utils/gyb --help
после клонирования Swift git repo.
$ 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.
Для более сложных примеров найдите *.swift.gyb
файлы в @apple/swift/stdlib/public/core.