Comstackción de una biblioteca externa de C ++ para usar con el proyecto de iOS

Soy completamente nuevo en el uso de bibliotecas C ++, así que agradezco que esto sea un poco específico para mi caso (hágamelo saber y puedo proporcionar más detalles).

Tengo una biblioteca externa de C ++ que estoy tratando de usar con un proyecto de iOS. La biblioteca sigue un patrón de configuración, creación y creación para generar un archivo de biblioteca .a. Cuando bash agregar este archivo de biblioteca a Xcode, aparece el siguiente error:

ignorando el archivo /Users/Developer/iOS/TestProj/libpresage.a, el archivo se creó para el archivo que no es la architecture que se está vinculando (i386):

/Users/Developer/iOS/TestProj/libpresage.a

En función de esta pregunta , intenté convertir la Arquitectura activa activa solo en NO, y recibo el mismo error. Esto me hace sospechar que he comstackdo la biblioteca para la architecture incorrecta.

Ejecutar lipo -info en el archivo .a da:

archivo de entrada libpresage.a no es un archivo grueso Archivo no graso: libpresage.a

es architecture: x86_64

Dado que esto no es armv7s, armv7 o arm64, bash comstackr la biblioteca C ++ de nuevo con los siguientes parámetros:

1) Prueba

./configure CC="gcc -arch armv7s" \ CXX="g++ -arch armv7s" \ CPP="gcc -E" CXXCPP="g++ -E" 

Error al comstackr, obtengo:

 ld: library not found for -lcrt1.3.1.o clang: error: linker command failed with exit code 1 (use -v to see invocation) 

2) Prueba

 ./configure CC="gcc -arch arm64" \ CXX="g++ -arch arm64" \ CPP="gcc -E" CXXCPP="g++ -E" 

Error al comstackr, obtengo:

ld: warning: ld: warning: ignorando el archivo /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib, falta la architecture requerida arm64 en file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib (2 rebanadas) haciendo caso omiso del archivo /Applications/Xcode.app/Contents/ Desarrollador / Plataformas / MacOSX.platform / Desarrollador / SDKs / MacOSX10.10.sdk / usr / lib / libstdc ++. Dylib, falta la architecture requerida arm64 en el archivo /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer /SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib (2 rebanadas)

ld: los ejecutables dynamics principales deben vincularse con libSystem.dylib para la architecture arm64 clang: error: el comando del enlazador falló con el código de salida 1 (use -v para ver la invocación)

¿Hay algo obvio que me estoy perdiendo?

EDITAR:

Gracias por las respuestas, así que me las he arreglado para tener la biblioteca en Xcode como un objective de comstackción personalizado, apuntando el comando ‘make’ a las bibliotecas MakeFile. Esta construcción bien.

Mis pasos desde aquí:

  • Agregue una dependencia desde mi objective de la aplicación iOS de Objective C al objective de comstackción personalizado.
  • Haga referencia a la biblioteca y cree un contenedor Objective C ++.
  • Esto parece correcto hasta que necesito llamar a la biblioteca externa de C ++, luego aparece el error al comstackr:

Símbolos no definidos para la architecture armv7: “Presage :: Presage (PresageCallback *)”, referenciado de: – [PresageBridge init] en PresageBridge.o “Presage :: ~ Presage ()”, referenciado de: – [PresageBridge init] en PresageBridge. o ld: símbolos que no se encuentran para la architecture armv7 clang: error: el comando del enlazador falló con el código de salida 1 (use -v para ver la invocación)

  • Mi envoltorio objective de C ++ (que vincula el encabezado de la biblioteca de C ++ externa presage.h):

     #import "PresageBridge.h" #include "presage.h" @implementation PresageBridge - (instancetype)init { if(self = [super init]) { Presage hello(&callback); } return self; } 
  • Basado en el código anterior, no parece que me falta el encabezado, y lo que es interesante es que también he intentado crear una instancia de otras clases en la biblioteca externa y parecen estar funcionando, lo que sugiere que Xcode puede ‘t vincular presage.h correctamente por alguna razón.

Así que he usado muchas bibliotecas C ++ de terceros en mis proyectos iOS. Hay diferentes estrategias que la gente usa para esto. Como algunos ya han citado, puede incluir el código directamente en el proyecto, crear la lib estática con Xcode o comstackrla. En el caso de bibliotecas multiplataforma C ++ que usan el sistema de configuración y comstackción GNU, prefiero la línea de comando. Solo necesita comstackrlo una vez y solo tiene que volver a visitarlo si necesita actualizar la versión o agregar una nueva porción de architecture.

El enfoque generalizado que desea es:

  • Calcule los argumentos de configuración correctos para usar para construir cada porción. Normalmente, solo necesitas concentrarte en hacer funcionar uno de los arms e i386. El rest es fácil si tienes esto hecho. En algunos casos, realmente necesita modificar el archivo de configuración para agregar el host o hacer otros ajustes.

  • Una vez que puedes construir todas las rebanadas, quieres ejecutar lipo para construir un binario gordo.

La mejor manera de lidiar con esto es crear un script de comstackción que hará todo el trabajo por usted. De esta manera, es más fácil rehacer. Lo que es más importante, puede reutilizar el script o permutarlo para comstackr otras librerías externas.

Hay muchas maneras de construir el script. Aqui hay uno. Tengo varias variaciones de este tipo de script. Este script se usó para construir cURL. Funcionó más o menos para presagiar con muy poca mod (es decir, cambiar curl a presage). Tenga en cuenta que no lo probé en Xcode (es decir, vinculándolo y ejecutándolo). Descubrí que tenía que deshabilitar sqlite, sino que creaba elementos de herramientas que no se comstackban correctamente. Si lo necesita, puede resolver esa parte.

Hay muchas maneras en que podrías hacerlo más resbaladizo. Por ejemplo, usando una matriz para almacenar todas las architectures. Esto es solo fuerza bruta.

Los puntos clave del script son:

  1. Obteniendo el último SDK
  2. Construyendo cada rebanada
  3. Luego corriendo lipo

Tenga en cuenta que debería funcionar sin necesidad, sin embargo, YMMV. Esté preparado para tener que depurarlo si es necesario. Por ejemplo, no he confirmado el tipo de host, pero en general eso es lo que siempre he usado. Desea poner esto en el directorio de presagio (el mismo directorio donde se configura). Cuando termina, todas las architectures están en el directorio de salida. La lib universal está en el directorio de presagios.

Recuerde también que es su responsabilidad vincular correctamente en la biblioteca universal y tener la ruta de búsqueda de los archivos de encabezado definida correctamente.

 #!/bin/bash PLATFORMPATH="/Applications/Xcode.app/Contents/Developer/Platforms" TOOLSPATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin" export IPHONEOS_DEPLOYMENT_TARGET="8.0" pwd=`pwd` findLatestSDKVersion() { sdks=`ls $PLATFORMPATH/$1.platform/Developer/SDKs` arr=() for sdk in $sdks do arr[${#arr[@]}]=$sdk done # Last item will be the current SDK, since it is alpha ordered count=${#arr[@]} if [ $count -gt 0 ]; then sdk=${arr[$count-1]:${#1}} num=`expr ${#sdk}-4` SDKVERSION=${sdk:0:$num} else SDKVERSION="8.0" fi } buildit() { target=$1 hosttarget=$1 platform=$2 if [[ $hosttarget == "x86_64" ]]; then hostarget="i386" elif [[ $hosttarget == "arm64" ]]; then hosttarget="arm" fi export CC="$(xcrun -sdk iphoneos -find clang)" export CPP="$CC -E" export CFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION" export AR=$(xcrun -sdk iphoneos -find ar) export RANLIB=$(xcrun -sdk iphoneos -find ranlib) export CPPFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION" export LDFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk" mkdir -p $pwd/output/$target ./configure --prefix="$pwd/output/$target" --disable-shared --disable-sqlite --host=$hosttarget-apple-darwin make clean make make install } findLatestSDKVersion iPhoneOS buildit armv7 iPhoneOS buildit armv7s iPhoneOS buildit arm64 iPhoneOS buildit i386 iPhoneSimulator buildit x86_64 iPhoneSimulator LIPO=$(xcrun -sdk iphoneos -find lipo) $LIPO -create $pwd/output/armv7/lib/libpresage.a $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a 

Teniendo en cuenta que eres nuevo con las bibliotecas C ++, supongo que necesitarás investigar un poco más.

Sin embargo, trataré de delinear algunos pasos que debes tener en cuenta:

  • debe asegurarse de comstackr para la misma architecture tanto la biblioteca estática (.a) como el proyecto.
  • de su error, necesita comstackr su biblioteca estática para i386 O cambiar su proyecto a x86_64 (la diferencia entre estas architectures es un poco más compleja, pero por ahora digamos que i386 significa escritorio de 32 bits mientras que x86_64 significa escritorio de 64 bits)
  • las architectures de arm son para iPhone, no para su MacOS (¡por eso no puede encontrar bibliotecas con architecture de arm dentro de la carpeta MacOSX)!

Hay múltiples formas de abordar estos problemas.

Para la primera, sugeriría incluir en su espacio de trabajo la biblioteca estática y agregarla como dependencia a su objective de comstackción. Para esto, necesitas entender las comstackciones de XCode.

Supongo que en realidad estás tratando de hacer una aplicación de teléfono, por lo que para la tercera opción necesitas configurar tu comstackción de g ++ para buscar en el iPhoneSDK de XCode al enlazar los objectives de los arms (cuidar iPhoneOS.plataforma) para esto.

Hacer una comstackción de arm solo funcionará en iPhones. Si desea que funcione en el simulador, deberá vincular su biblioteca estática a las bibliotecas dentro de la plataforma iPhoneSimulator.platform.

Si desea que su biblioteca estática funcione tanto para iPhones como para el simulador de iPhone, deberá crear una lib lib (básicamente una biblioteca que contenga símbolos para ambas plataformas)

Si te faltan estas plataformas, puedes descargarlas de XCode (pero creo que están ahí)

Como puede ver, las cosas se volverán cada vez más complejas a lo largo del camino, por lo que recomiendo usar XCode para comstackr la biblioteca estática (todavía es posible con g ++).

Creo que los siguientes conceptos serían útiles para investigar:

  • arm, x86, x86_64
  • biblioteca estática
  • enlace estático
  • fat lib (biblioteca universal)
  • Espacio de trabajo XCode con múltiples proyectos

Espero que esto ayude :).

Esto es lo que funcionó para mí en Xcode 9 para dispositivos iOS (iPhone X):
1) Compile dylib con estos indicadores establecidos de la siguiente manera:
a) “Directorio de instalación”: @ executable_path / Frameworks b) “Ruta de búsqueda de Runpath”: @ executable_path / Frameworks
Ver la imagen a continuación:
configuración dylib en Xcode 9

2) En el proyecto Xcode donde se usa / vincula el dylib:
a) “Ruta de búsqueda de Runpath”:
@ executable_path / Frameworks
b) En “Build Phase-> Embed Libraries”, asegúrese de seleccionar “Destination” como “Ejecutables” y Subpath como “Frameworks”, “Code sign on copy” marcado:
Configuración de la aplicación de iOS vinculante

Este método se prueba y se usa con Xcode 9.2 y iPhone X.

David

C ++ funciona en iOS, solo puede agregarlo a su proyecto. O si realmente desea tener su biblioteca dinámica, puede comstackrla con Xcode y especificar su architecture de destino.

Establezca su architecture de nuevo en el valor predeterminado y luego pruebe lo siguiente. 1. En Fases de comstackción-> Enlace binario con bibliotecas, agregue bibliotecas libz.dylib y libxml2.dylib a su proyecto. 2. En BuildSettings-> Rutas de búsqueda, establezca Buscar siempre rutas de usuario en Sí y, en Rutas de búsqueda de marcos, agregue la ruta correcta de su infraestructura. Use terminal para obtener la ruta correcta de su marco. 3. Intente configurar su “Fuente de comstackción como” en C ++ o use el golpe y la prueba y verifique con todas las opciones. Fuente Complier Como también está en BuildSettings. Use cmd + f para buscarlo.

Pruébalos y házmelo saber, también cuéntame sobre el framework o SDK que intentas usar en tu proyecto.

El script de Mobile Ben es excelente, aparte de la línea final, codifica un nombre de archivo de biblioteca en el script. El siguiente es un reemplazo para el último comando lipo y utiliza dinámicamente lipo fusiona cada archivo de biblioteca creado después de la comstackción.

Cambiar la línea de Mobile Ben:

 $LIPO -create $pwd/output/armv7/lib/libpresage.a $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a 

a:

 for t in `ls $pwd/output/armv7/lib/*.a` ; do export LIB=`basename $t` export ARCHSTRING="" for a in `ls $pwd/output` do export ARCSTRING="$ARCSTRING $pwd/output/$a/lib/$LIB " done $LIPO -create $ARCSTRING -output $LIB done 

Nota: No quería editar la respuesta de Mobile Ben con la nueva funcionalidad de código, y agregar esto como un formato perdido de comentario.