2012-06-18 8 views
10

Con respecto a esta técnica Q & Una de Apple:http://developer.apple.com/library/mac/#qa/qa1490/_index.html¿Por qué es necesario el marcador del vinculador -ObjC para vincular categorías en bibliotecas estáticas? (LLVM)

Creo que el compilador podría marcar llamadas a los métodos definidos en las categorías en tiempo de compilación (se sabe que se han definido en una categoría y no el clase principal porque el prototipo estaba en una sección @interface Class (Category)), por lo que podría crear una tabla en los archivos de objeto de "métodos de categoría externos". Luego, el enlazador, después de hacer su enlace normal, debería poder concatenar/fusionar y procesar las tablas de "métodos de categoría externos" de todos los objetos y buscar símbolos coincidentes en categorías de clase correspondientes de todos los marcos/bibliotecas/objetos vinculados, luego puede tirar de los que aún no estaban 'en' el objetivo.

Debe haber algo que me falta, pero ¿qué es? ¿Por qué esto no es posible?

Respuesta

14

El vinculador trata las bibliotecas estáticas como una gran colección antigua de piezas aleatorias de las que extraerá piezas individuales para cumplir con las solicitudes de símbolos del resto de la unidad de enlace.

I.e. si el programa principal llama _foo y _foo sólo aparece en la biblioteca estática, entonces _foo, junto con los símbolos dependientes, será arrastrado.

Sin embargo, cuando se llama a un método en una categoría, no hay ninguna referencia símbolo específico debido al dinamismo de Objective-C.

La bandera -ObjC le dice al vinculador que, debido a esto, debe tomar todas las categorías de la biblioteca estática y colocarlas en el binario principal.


Es un poco confuso y la suposición es que el compilador debe ser más inteligentes acerca de esto (y, ciertamente, debería dar asistencia a nivel herramientas dev). Es importante recordar algunas cosas:

  • Cualquier cosa declarada en un archivo de cabecera es más o menos el tiempo perdido por el enlazador alrededor de los rollos. Los símbolos son creados por unidades de compilación, no por archivos de encabezado. Los archivos de encabezado generan la promesa de que un símbolo se creará concretamente más adelante o se cumplirá mediante el enlace, pero no se puede crear un símbolo en sí mismo (o la unidad de compilación de cada uno - cada .o - terminaría con una copia de el símbolo y la hilaridad se producirían en el momento del enlace).

  • Objective-C es completamente dinámico. Cuando dice [(id)foo bar];, el único requisito es que bar se haya definido en algún lugar anterior. No importa si realmente se implementa (hasta el tiempo de ejecución de todos modos).

  • Las categorías no tienen que tener @implementations correspondiente; una categoría puede usarse para declarar que pueden existir métodos y, de hecho, antes de agregar @optional a @protocol, era común usar una categoría en NSObject (ewwwwww) sin @implementation para decir "Oye, este método opcional podría existir en tiempo de ejecución ".

  • La compilación y el enlace son procesos completamente independientes. La compilación se trata de expandir el código y convertirlo en bibliotecas de bytes ejecutables. El enlace consiste en tomar esas bibliotecas y ponerlas juntas en algo que realmente se pueda ejecutar, incluida la resolución de todas las dependencias entre bibliotecas.El compilador no sabe realmente cómo se puede vincular algo y el vinculador no tiene ninguna información sobre dónde podrían haber sido definidas las cosas (que no daban los símbolos).

Resultado final?

El vinculador no tiene suficiente información para resolver las dependencias.

+0

Pero el compilador sabe que vio una llamada a un método que se definió en una categoría, por lo que * podría * crear una referencia de símbolo específica para usar en tiempo de enlace; de ​​esto se trata mi pregunta. Quiero entender esto un poco más profundo que lo que ya se describió en las Preguntas y Respuestas Técnicas vinculadas. – jhabbott

+0

Gran respuesta, una pregunta. ¿Qué es suficiente para hacer que el compilador vincule un símbolo de una lib estática? Simplemente '# import' o simplemente definiendo una variable' MyClass c; ', ¿o tienes que llamar a un método en tu clase' [c myMethod] '? ¿Qué pasa si la clase solo está referenciada en el constructor de interfaz? – Robert

+1

@Robert, el vinculador necesita ver un símbolo que se resuelve mediante el enlace directo con la biblioteca. Si es un símbolo resuelto dinámicamente en tiempo de ejecución, no contará (como IB). No necesariamente tiene que ser una llamada a un método, pero ese es el mecanismo más fácil de usar. Es decir. '[Clase MyClass];', por ejemplo. – bbum

Cuestiones relacionadas