El registro de fallos indica que el juego está buscando una función llamada getattrlistbulk
. Como esta función no existe en Mavericks, el juego no sabe qué hacer y se bloquea. Ergo, para que el juego se ejecute, tendremos que darle lo que quiere: una copia del getattrlistbulk
función.
(En otras palabras, tenemos que escribir algo de código. Asegúrate de tener instaladas las herramientas de línea de comandos Xcode de Apple).
getattrlistbulk es un parte del núcleo y no entiendo lo que hace. Pero, ¿y si no tuviera que hacerlo? ¿Y si los juegos de Unity no necesitaran realmente getattrlistbulk
¿para algo importante? Si ese fuera el caso, podría ser que getattrlistbulk
no necesitaría realmente hacer cualquier cosa para que un juego se ejecute, la función sólo tendría que existe .
Sólo hay una forma de averiguarlo. Probemos este código:
#include <sys/attr.h>
int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf, size_t attrBufSize, uint64_t options) {
return 0;
}
Esta copia de getattrlistbulk
siempre devolverá 0
No importa lo que suceda.
Si guarda este código como UnityMavericksWorkarounds.m
puede compilarlo con:
clang -compatibility_version 9999 -o UnityMavericksWorkarounds.dylib -dynamiclib UnityMavericksWorkarounds.m
Ahora, tenemos que hacer que el juego cargue nuestra nueva biblioteca UnityMavericksWorkarounds. Esto debería ser fácil de hacer con el DYLD_INSERT_LIBRARIES
variable de entorno. Ejecutar en el Terminal:
DYLD_INSERT_LIBRARIES=UnityMavericksWorkarounds.dylib Sayonara\ Wild\ Hearts.app/Contents/MacOS/Sayonara\ Wild\ Hearts
...y ver cómo el juego se bloquea exactamente igual que antes:
Dyld Error Message:
Symbol not found: _getattrlistbulk
Referenced from: /Users/USER/Desktop/Sayonara Wild Hearts.app/Contents/MacOS/../Frameworks/UnityPlayer.dylib
Expected in: /usr/lib/libSystem.B.dylib
¿Por qué no puede UnityPlayer.dylib
encontrar nuestro nuevo y elegante getattrlistbulk
¿función?
Veamos de nuevo el informe del accidente. UnityPlayer no espera getattrlistbulk
que esté en cualquier sitio, espera que esté en /usr/lib/libSystem.B.dylib
y por lo tanto no está buscando dentro de nuestra biblioteca UnityMavericksWorkarounds. Esto se debe a un concepto llamado namespaces de dos niveles, sobre el que puede leer más aquí . Y, aunque el namespacing de dos niveles se puede desactivar mediante DYLD_FORCE_FLAT_NAMESPACE=1
Los juegos de Unity no funcionarán sin él.
Probemos otra cosa. ¿Y si hacemos que el juego cargue nuestra biblioteca, UnityMavericksWorkarounds.dylib
en lugar de libSystem.B.dylib
? Apple's install_name_tool
hace que esto sea fácil. Copie UnityMavericksWorkarounds.dylib en la carpeta de la aplicación Contents/Frameworks
y ejecutarlo:
install_name_tool -change /usr/lib/libSystem.B.dylib @executable_path/../Frameworks/UnityMavericksWorkarounds.dylib Sayonara\ Wild\ Hearts.app/Contents/Frameworks/UnityPlayer.dylib
(Sustituir Sayonara\ Wild\ Hearts
con el nombre de su juego).
Ahora, intenta lanzar el juego de nuevo, y...
Application Specific Information:
dyld: launch, loading dependent libraries
Dyld Error Message:
Symbol not found: dyld_stub_binder
Referenced from: /Users/USER/Desktop/Sayonara Wild Hearts.app/Contents/MacOS/Sayonara Wild Hearts
Expected in: /Users/USER/Desktop/Sayonara Wild Hearts.app/Contents/MacOS/../Frameworks/UnityMavericksWorkarounds.dylib
in /Users/USER/Desktop/Sayonara Wild Hearts.app/Contents/MacOS/Sayonara Wild Hearts
Oye, ¡al menos el registro de accidentes ha cambiado esta vez! Probablemente puedes adivinar por qué esto no funcionó. libSystem.B.dylib
es una biblioteca de sistema esencial que contiene muchas, muchas funciones. UnityMavericksWorkarounds sólo contiene getattrlistbulk
. Y así, aunque el juego ahora tiene acceso a getattrlistbulk
¡le falta todo lo demás!
Lo que queremos es que nuestra biblioteca UnityMavericksWorkarounds también proporcione todas las demás funciones de libSystem además de las suyas propias. Podemos hacer esto haciendo libSystem.B.dylib
a sub-biblioteca de nuestro UnityMavericksWorkarounds.dylib
.
Hice esto usando optool :
optool install -c reexport -p /usr/lib/libSystem.B.dylib -t Sayonara\ Wild\ Hearts.app/Contents/Frameworks/UnityMavericksWorkarounds.dylib
(Probablemente hay una forma más limpia de enlazar esto en tiempo de compilación, pero no pude averiguar cómo, y optool funcionó).
Ahora, intenta lanzar el juego de nuevo, y...
Preguntas teóricas frecuentes
(Preguntas de seguimiento que nadie ha hecho, pero que teóricamente podrían).
P: ¿Es el valor de retorno de 0
¿Importante?
A : Sí. Originalmente intenté 1
pero eso hacía que algunos juegos asignaran toda la memoria disponible y se bloquearan cuando no quedaba ninguna.
P: ¿Esto hará que todo ¿Los juegos de Unity funcionan correctamente en Mavericks?
A : No. Que yo sepa, permitirá arrancar cualquier juego de Unity 2018/2019, ¡pero nadie ha dicho nada de que funcione correctamente! Los juegos son complejos, y estos claramente nunca han sido probados en Mavericks antes, por lo que pueden tener otros fallos. Timelie es un ejemplo de un juego que técnicamente funciona con este arreglo, pero tiene problemas gráficos muy graves.
Sin embargo, muchos otros juegos parecen funcionar perfectamente.
P: ¿Es posible reimplantar realmente getattrlistbulk
en lugar de utilizar una función stub?
A : ¿Tal vez? Internet™ dice getattrlistbulk
es un sustituto de getdirentriesattr
. Entonces, en un momento dado lo intenté:
#include <sys/attr.h>
#include <unistd.h>
int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf, size_t attrBufSize, uint64_t options) {
unsigned int count;
unsigned int basep;
unsigned int newState;
return getdirentriesattr(dirfd, &attrList, &attrBuf, attrBufSize, &count, &basep, &newState, options);
}
Esto se escribió comparando el código de ejemplo de getattrlistbulk
y getdirentriesattr
en la documentación para desarrolladores. Funciona (en la medida en que los juegos se ejecutan), pero entonces, también lo hace return 0
Así que realmente no tengo forma de probar el código. En estas circunstancias, return 0
parece más seguro.
P: ¿Pueden darme un resumen?
A : Claro:
- Copie el primer bloque de código de esta respuesta en un archivo llamado
UnityMavericksWorkarounds.m
.
clang -compatibility_version 9999 -o /Path/To/Game.app/Contents/Frameworks/UnityMavericksWorkarounds.dylib -dynamiclib /Path/To/UnityMavericksWorkarounds.m
install_name_tool -change /usr/lib/libSystem.B.dylib @executable_path/../Frameworks/UnityMavericksWorkarounds.dylib /Path/To/Game.app/Contents/Frameworks/UnityPlayer.dylib
- Descargar optool .
/Path/To/optool install -c reexport -p /usr/lib/libSystem.B.dylib -t /Path/To/Game.app/Contents/Frameworks/UnityMavericksWorkarounds.dylib
0 votos
Los comentarios no son para ampliar la discusión; esta conversación ha sido trasladado al chat .
0 votos
La razón subyacente es, probablemente, que las nuevas versiones de Unity se compilan con las nuevas versiones de Xcode, que sólo se dirigen a las nuevas versiones de OS X.
0 votos
@ThorbjørnRavnAndersen Yo habría pensado, sin embargo, que si 10.10 era el objetivo mínimo de despliegue, habría hecho falta mucho más que stubear un método para que los juegos funcionaran.
0 votos
@Wowfunhappy Depende de cuántos métodos utilicen realmente los programadores de Unity.