swift swift2 metaprogramming mach-o

Swift: macro para__attribute__((sección))



swift2 metaprogramming (1)

Aquí está la respuesta a su pregunta sobre el preprocesador (y las macros).

Swift no tiene preprocesador, por lo que es imposible deletrear la magia con tanta elegancia como MAGIC (algún identificador). Aunque no quiero que sea demasiado feo.

El proyecto Swift tiene un preprocesador (pero, AFAIK, no se distribuye con el binario de Swift).

De la lista de correo swift-users :

¿Qué son los archivos .swift.gyb?

Es un preprocesador que el equipo Swift escribió para que cuando necesitaran construir, digamos, diez variantes casi idénticas de Int, no tendrían que copiar y pegar literalmente el mismo código diez veces. Si abres uno de esos archivos, verás que son principalmente código Swift, pero con algunas líneas de código entremezcladas que están escritas en Python.

No es tan hermoso como las macros C, pero, en mi humilde opinión, es más poderoso. Puede ver los comandos disponibles con ./swift/utils/gyb --help command después de clonar el repositorio git de Swift.

$ swift/utils/gyb --help

uso, etc (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. -

Mi ejemplo de uso de GYB está disponible en GitHub.Gist .

Para ejemplos más complejos, busque archivos *.swift.gyb en @apple/swift/stdlib/public/core .

Esta es una pregunta un tanto extraña y poco tónica, así que tengan paciencia.
Quiero hacer en Swift algo parecido a lo que estoy haciendo actualmente en Objective-C / C ++, así que comenzaré describiendo eso.

Tengo algún código C ++ existente que define una macro que, cuando se usa en una expresión en cualquier parte del código , insertará una entrada en una tabla en el binario en el momento de la compilación. En otras palabras, el usuario escribe algo como esto:

#include "magic.h" void foo(bool b) { if (b) { printf("%d/n", MAGIC(xyzzy)); } }

y gracias a la definición.

#define MAGIC(Name) / []{ static int __attribute__((used, section("DATA,magical"))) Name; return Name; }()

lo que realmente sucede en el momento de la compilación es que se crea una variable estática llamada xyzzy (modulo name-mangling) y se asigna en la sección magical especial de mi binario Mach-O, de modo que ejecutar nm -m foo.o para volcar los símbolos muestre algo mucho como esto:

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

A través de la magia de getsectbynamefromheader() , luego puedo cargar la tabla de símbolos para la sección magical , escanearla y descubrir (al desmantelar cada símbolo que encuentro) que en algún punto del código del usuario, llama MAGIC(xyzzy) . ¡Eureka!

Puedo replicar la segunda mitad de ese flujo de trabajo en Swift, comenzando con la parte getsectbynamefromheader() . Sin embargo, la primera parte me ha dejado perplejo.

  • Swift no tiene preprocesador, por lo que es imposible deletrear la magia con tanta elegancia como MAGIC(someidentifier) . Aunque no quiero que sea demasiado feo.

  • Por lo que sé, Swift no tiene forma de insertar símbolos en una sección determinada, no hay equivalente de __attribute__((section)) . Sin embargo, esto está bien, ya que nada en mi plan requiere una sección dedicada; Esa parte hace que la segunda mitad sea más fácil.

  • Que yo sepa, la única manera de obtener un símbolo en la tabla de símbolos en Swift es a través de una definición de estructura local. Algo como esto:

    func foo(b: Bool) -> Void { struct Local { static var xyzzy = 0; }; println(Local.xyzzy); }

Eso funciona, pero es un poco de escritura extra, y no se puede hacer en línea en una expresión (no es que eso importe si no podemos hacer una macro MAGIC en Swift de todos modos), y me preocupa que el Swift compilador podría optimizarlo lejos.

Entonces, hay tres preguntas aquí, todas sobre cómo hacer que Swift haga cosas que Swift no quiere hacer: macros, atributos y creación de símbolos resistentes a la optimización del compilador.

Soy consciente de @asmname pero no creo que me ayude, ya que puedo lidiar con el desenredo por mi cuenta.

Soy consciente de que Swift tiene "genéricos", pero parecen estar más cerca de los genéricos de Java que de las plantillas de C ++; No creo que puedan utilizarse como sustituto de las macros en este caso en particular.

Soy consciente de que el código para el compilador Swift ahora es de código abierto ; He echado un vistazo a los fragmentos en vano; pero no puedo leerlo todo en busca de trucos que tal vez ni siquiera estén allí.