Подтвердить что ты не робот

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 теперь открыт с открытым исходным кодом; Я потратил его впустую; но я не могу прочитать все это, глядя на трюки, которые могут даже не быть там.

4b9b3361

Ответ 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.