Pregunta

Tengo tres archivos de encabezado en mi proyecto que describen los objetos Rational, Complex, y RubyObject.Las dos primeras son las plantillas.Todos pueden ser interconverted mediante copia de los constructores, que se definen en los archivos de encabezado — excepto para aquellos que construir Rational y Complex de const RubyObject&s, que se definen en un archivo de código fuente.

Nota: Esas definiciones están ahí por necesidad.Si todos ir en el encabezado, se obtiene dependencia circular.

Hace un tiempo, me encontré con algunos sin resolver errores de símbolos con los dos copiar constructores definidos en el archivo de origen.Yo era capaz de incluir en el archivo de origen de la siguiente función

void nm_init_data() {
    nm::RubyObject obj(INT2FIX(1));
    nm::Rational32 x(obj);
    nm::Rational64 y(obj);
    nm::Rational128 z(obj);
    volatile nm::Complex64 a(obj);
    volatile nm::Complex128 b(obj);
}

y, a continuación, llame nm_init_data() desde la biblioteca de punto de entrada en la principal fuente de archivo.Hacerlo forzada de estos símbolos para ser conectadas correctamente.

Por desgracia, recientemente he actualizado GCC y los errores son parte de atrás.De hecho, esto parece ocurrir de una manera ligeramente diferente lugar con GCC 4.6 (por ejemplo, Travis-CI).

Pero no es una versión específica de la cuestión (como lo había pensado antes).Lo vemos en Travis CI basada en Ubuntu sistema, que se ejecuta GCC 4.6.Pero no la vemos en una máquina de Ubuntu con GCC 4.8.1 o 4.8.2.Pero nosotros ¿ lo ve en un equipo Mac OS X con 4.8.2 — y no la misma máquina con 4.7.2.La desactivación de la optimización no parecen ayudar a cualquiera.

Si me quedo nm en mi biblioteca, el símbolo es, sin duda indefinido:

$ nm tmp/x86_64-darwin13.0.0/nmatrix/2.0.0/nmatrix.bundle |grep RationalIsEC1ERKNS
                 U __ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
00000000004ca460 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache
00000000004ca458 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache_0

No estoy seguro de por qué hay dos entradas definidas por el que están subordinados a los undefined symbol, pero también no sé tanto como me gustaría, sobre compiladores.

También se ve como el constructor de copia es una undefined symbol para cada versión de la Rational plantilla:

__ZN2nm8RationalIiEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIxEC1ERKNS_10RubyObjectE

"Bueno, eso es extraño", pensé."Complex64 y Complex128 también son llamados en la que nm_init_data la función, pero ambos de ellos resolver correctamente y que no se enumeran en el nm -u la producción". Así que he intentado añadir volatile antes de la copia Racional de la construcción, además, pensando que tal vez el compilador de optimización de algo que no queremos optimizado.Pero que no se fije bien, lamentablemente.Esto hizo que, con una salvedad:

void nm_init_data() {
  volatile VALUE t = INT2FIX(1);
  volatile nm::RubyObject obj(t);
  volatile nm::Rational32 x(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational64 y(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational128 z(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex64 a(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex128 b(const_cast<nm::RubyObject&>(obj));
}

La advertencia es que ahora me sale exactamente el mismo error, pero para el Complejo de los objetos en su lugar.Argh!

dyld: lazy symbol binding failed: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

dyld: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

Esto es completamente absurdo.Aquí están las definiciones de estas funciones, en el mismo archivo de origen como el nm_init_data() función:

namespace nm {
  template <typename Type>
  Complex<Type>::Complex(const RubyObject& other) {
    // do some things
  }

  template <typename Type>
  Rational<Type>::Rational(const RubyObject& other) {
    // do some other things
  }
} // end of namespace nm

Sugerencia: Una cosa que vale la pena mencionar es que el error no se produce cuando nm_init_data() se llama (es decir, cuando se carga la biblioteca).Ocurre mucho más tarde, durante otra llamada a estos molestos funciones.

¿Cómo puedo solucionar este problema de una vez por todas, y otros como él?

¿Fue útil?

Solución

Usted reclamar el siguiente, que lo dudo.

Esas definiciones están ahí por necesidad.Si todos van en los encabezados, se obtiene dependencia circular.

En la mayoría de los casos se pueden resolver dichas circulares enredo por la separación de su código en un adicional .ch archivo, que se incluye junto con la definición de la clase que contiene las definiciones de plantilla en cualquier lugar necesario.

Si el código tiene una real dependencia circular, no podía compilar.Por lo general, si sus dependencias parecen ser circular, usted tiene que mirar más de cerca y bajar a nivel de método y comprobar cuál de ellos se requieren ambos tipos de compilar.

Así que podría ser que sus tipos de uso de cada uno de los otros, y luego compilar todo en uno .archivo cpp (por ejemplo,a través de los tres .hpp incluye).O sólo hay puntero a otro tipo, a continuación, utilice adelante las declaraciones para asegurar, que todas las plantillas están resueltos.O de terceros, usted tiene algún método que dependen de avance y algunos de los que dependen hacia atrás, a continuación, poner la clase en un archivo, los otros tipo en otro, y que están bien de nuevo.

Además, parece que se debe utilizar una declaración forward para su falta de elementos.Yo esperaría algo como lo siguiente después de la definición de la función.E. g.:

template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other);

Otros consejos

Rational, Complex...son plantillas

copia de constructores...se definen en los archivos de encabezado — excepto para aquellos que construir Rational y Complex de const RubyObject&s, que se definen en un archivo de código fuente.

Y ahí radica el problema.Desde Rational y Complex son plantillas, todos sus métodos deben estar disponibles en el archivo de encabezado.

Si no, entonces usted podría ser a veces capaz de salirse con la suya, dependiendo del orden en que se dicen las cosas y el orden en el que las cosas están vinculadas, pero a menudo obtendrá errores extraños acerca de undefined symbols, que es exactamente lo que está sucediendo aquí.

Simplemente mover las definiciones de Rational(const RubyObject&) y Complex(const RubyObject&) en las respectivas cabeceras y todo debería funcionar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top