Rust: Compatibilidad con el código de bits de la tienda de aplicaciones de Apple

Creado en 24 ago. 2016  ·  89Comentarios  ·  Fuente: rust-lang/rust

Bitcode es el futuro de la distribución de aplicaciones de Apple y ahora no lo admitimos. Hacerlo es complicado porque Apple elige cualquier versión de LLVM que quiera y la actualiza según sus caprichos. No podemos acoplar nuestro LLVM al de ellos porque tenemos nuestras propias necesidades y no podemos ser obligados a actualizar cuando Apple lo decida.

Aquí hay algunas opciones:

  • Enviamos una cadena de herramientas completamente separada para apuntar al código de bits de Apple. Esto es bastante feo.
  • Cambiamos rustc para cargar dinámicamente LLVM, creamos un paquete rust-llvm y un paquete rust-llvm-apple opcional, y hacemos que rustc cargue el LLVM de apple para manejar su código de bits.
  • Creamos una caja rustc_llvm_apple y solo vinculamos dos LLVM completos en rustc en todo momento. Esto probablemente no volaría
  • Creamos una compilación de rustc llamada rustc-apple y la enviamos en un paquete rustc-apple opcional. Es exactamente como rustc, excepto que en lugar de enlazar con rustc_llvm, enlaza con rustc_llvm_apple. Cuando rustc recibe una solicitud para emitir un código de bits, simplemente difiere completamente del binario rustc-apple. De hecho, me gusta bastante esta solución.
  • Podríamos investigar un desinfectante de código de bits para traducir nuestro código de bits al de ellos. Creo que la probabilidad de éxito aquí es baja debido al mantenimiento. Creo que RenderScript hace esto.

Creo que las soluciones de carga dinámica LLVM y defer-to-alternate-rustc son las más prometedoras.

CC https://users.rust-lang.org/t/ios-rust-integration/6928/4

cc @bluejekyll

A-LLVM A-rustbuild C-enhancement E-hard O-ios T-compiler T-dev-tools

Comentario más útil

Logré vincular rustc nightly-2019-09-05 aarch64-apple-ios and rustflags = "-C lto -Z embed-bitcode" staticlib con la aplicación clang-1100.0.33.5 (Xcode 11 beta 7) and -fembed-bitcode . El código fuente es https://github.com/saturday06/rust-ios-bitcode-test .

Todos 89 comentarios

Cambiamos rustc para cargar dinámicamente LLVM, creamos un paquete rust-llvm y un paquete rust-llvm-apple opcional, y hacemos que rustc cargue el LLVM de apple para manejar su código de bits.

La carga dinámica de LLVM ciertamente no es una opción. La API de LLVM es menos estable que su código de bits y, si construimos contra LLVM xy, entonces tener LLVM xz en lugar de xy casi seguramente romperá rustc. Simplemente conéctese al sistema LLVM estáticamente (como ya lo hace --llvm-root ).

Creamos una caja rustc_llvm_apple y solo vinculamos dos LLVM completos en rustc en todo momento. Esto probablemente no volaría

Simplemente vincule el sistema LLVM (estáticamente) para las distribuciones de Apple. En mi experiencia, ya funciona un poco bien.

Podríamos investigar un desinfectante de código de bits para traducir nuestro código de bits al de ellos. Creo que la probabilidad de éxito aquí es baja debido al mantenimiento. Creo que RenderScript hace esto.

De acuerdo... entonces, la cuestión es que el formato de código de bits LLVM es un poco estable entre las versiones de LLVM. ¿Apple hace algo inusual para que eso no sea cierto, o el formato de código de bits utilizado no es LLVM por completo (es decir, tiene cosas específicas de Apple)?


Siento que escuché en 2013 que usar el código de bits LLVM como formato de distribución es estúpido. Ciertamente estoy de acuerdo; ¿La distribución de bibliotecas binarias nativas ya no funciona para iOS?

También estoy muy interesado en lo que sucedería cuando Apple actualice a la versión LLVM con un formato de código de bits incompatible internamente y la gente siga compilando cosas con compiladores antiguos.

Experimenté brevemente con esto, es decir, emití el código de bits durante las compilaciones de carga, luego traté de crear una biblioteca estática con el código de bits incluido. Cuando traté de vincular llvm con la biblioteca de código de bits, obtuve una versión LLVM incompatible del código de bits.

No tengo una prueba fácil para reproducir esto, pero supongo que solo hay una verificación de versión tonta que niega la vinculación entre diferentes versiones de LLVM. O simplemente hice algo completamente incorrecto. Intentaré presentar un caso de prueba cuando tenga algo de tiempo para ver esto nuevamente.

Sería útil tener el mensaje de error exacto de llvm-link.

@bluejekyll LLVM tiene varios archivos de código de bits en su directorio de prueba. Las pruebas contra estos archivos de código de bits se ejecutan continuamente (llvm-dis-3.8/opt-3.8 entiende bien un archivo de código de bits de 3 años de 3.2, por ejemplo), por lo que debe ser algo de Apple.

Simplemente vincule el sistema LLVM (estáticamente) para las distribuciones de Apple. En mi experiencia, ya funciona un poco bien.

Es algo más fácil decirlo que hacerlo: hasta donde yo sé, la única versión bendecida de apple-llvm para cargas de App Store es la que se envía con el Xcode actual. Esto también significa potencialmente mantener los enlaces de LLVM para dos versiones de LLVM (no necesariamente dos versiones secundarias vecinas tampoco). No creo que sea válido usar una versión anterior de apple-llvm.

También estoy muy interesado en lo que sucedería cuando Apple actualice a la versión LLVM con un formato de código de bits incompatible internamente y la gente siga compilando cosas con compiladores antiguos.

Creo que evitan esto al permitir que el último Xcode envíe aplicaciones (y estoy bastante seguro de que está grabado en la imagen de salida con la versión de LLVM que usó).

IIRC, el código de bits está empaquetado para cada arquitectura, ya que el código de bits de arquitectura cruzada no es generado por clang (creo que es un objetivo contrario al clang y al código de bits en general). Se almacena en una sección para cada archivo de objeto, por lo que al menos se duplica. Eso podría ser parte de por qué alguien mencionó que el código de bits podría no ser la mejor manera de hacer esto.

Siento un poco que todas las soluciones recomendadas son algo asquerosas. La forma menos complicada que se me ocurre es permitir que diferentes objetivos sobrecarguen el comportamiento de generación de código y que la ruta de generación de código de Apple esté en una caja dinámica. (Que sería solo la ruta de generación de códigos normal compilada contra apple-llvm).

Dado que este error menciona la App Store, ¿vale la pena hablar sobre la historia del manejo de excepciones aquí? (es decir, panic=abort es estrictamente necesario en este momento).

LLVM tiene varios archivos de código de bits en su directorio de prueba. Las pruebas contra estos archivos de código de bits se ejecutan continuamente (llvm-dis-3.8/opt-3.8 entiende bien un archivo de código de bits de 3 años de 3.2, por ejemplo), por lo que debe ser algo de Apple.

@nagisa gracias por hacerme saber esto. Me da la esperanza de que todavía podría haber una solución aquí, y que probablemente estaba haciendo algo mal.

@ricky26 buenos puntos.

que yo sepa, la única versión bendecida de apple-llvm para cargas de App Store es la que se envía con el Xcode actual.

¿No es Xcode LLVM en Apple lo mismo que el sistema LLVM? Me refería a Xcode LLVM entonces. Tendríamos que asegurarnos de que xcode sea siempre la versión más reciente al enviar trenes rustc.

Por supuesto, la forma en que Apple hace las cosas nos impide producir un bitcode de Apple válido con una versión anterior de rustc y esencialmente nos obliga a tirar todos los beneficios que nuestra historia de estabilidad proporciona por la ventana, y no veo ninguna forma de que esto pueda solucionarse.

Esto también significa potencialmente mantener los enlaces de LLVM para dos versiones de LLVM

Ya mantenemos¹ la compatibilidad con las versiones 3.7 a 3.9 de LLVM (y potencialmente troncal). Siempre que el LLVM de Xcode no sea una versión antigua, creo que estamos bien en ese sentido. Si Xcode LLVM es realmente una versión antigua/personalizada/etc., entonces no veo que podamos admitir esta función en absoluto. Especialmente porque no tenemos la opción de enviar parches a _ese_ LLVM para agregar las características que necesitamos. Tampoco me gustaría bloquear rustc para que sea compatible con 3.7 para siempre en caso de que Apple decida no actualizar Xcode LLVM hasta 2038.

¹: sin embargo, si rustc se creó contra LLVM xy, debe vincularse exactamente a LLVM xy.

La carga dinámica de LLVM ciertamente no es una opción. La API de LLVM es menos estable que su código de bits y, si construimos contra LLVM xy, entonces tener LLVM xz en lugar de xy casi seguramente romperá rustc. Simplemente conéctese al sistema LLVM estáticamente (como ya lo hace --llvm-root).

@nagisa La API de C++ es inestable, pero usamos la API de C y hemos tenido mucho éxito al admitir varias versiones de LLVM a la vez. No veo la diferencia en términos de soporte de API.

Simplemente vincule el sistema LLVM (estáticamente) para las distribuciones de Apple. En mi experiencia, ya funciona un poco bien.

Podríamos simplemente enviar el LLVM de Apple para todas las plataformas de Apple, pero esto significa acoplar nuestro LLVM a Apple para generar incluso código de máquina de escritorio, y excluye la opción de admitir el código de bits de iOS en hosts que no son de Apple.

De acuerdo... entonces, la cuestión es que el formato de código de bits LLVM es un poco estable entre las versiones de LLVM. ¿Apple hace algo inusual para que eso no sea cierto, o el formato de código de bits utilizado no es LLVM por completo (es decir, tiene cosas específicas de Apple)?

El formato de código de bits no es estable entre versiones.

¿La distribución de bibliotecas binarias nativas ya no funciona para iOS?

Funciona hoy. No es el método preferido y no es obvio que seguirá siendo compatible.

Esto también significa potencialmente mantener los enlaces de LLVM para dos versiones de LLVM (no necesariamente dos versiones secundarias vecinas tampoco). No creo que sea válido usar una versión anterior de apple-llvm.

@ricky26 Mantenemos con éxito la compatibilidad entre varias versiones de LLVM. Siempre que Apple y el nuestro no se separen demasiado, debería ser factible, pero siempre existe el riesgo de una ruptura tan grande que la división no se puede cruzar, y sé que se avecinan cambios importantes en la API.

Siempre que el LLVM de Xcode no sea una versión antigua, creo que estamos bien en ese sentido.

Desde esta página https://gist.github.com/yamaya/2924292 :

clang-700.0.72 => LLVM 3.7.0
clang-700.1.76 => LLVM 3.7.0
clang-700.1.81 => LLVM 3.7.0
clang-703.0.29 => LLVM 3.8.0
clang-703.0.31 => LLVM 3.8.0

La API de C++ es inestable, pero usamos la API de C y hemos tenido mucho éxito al admitir varias versiones de LLVM a la vez. No veo la diferencia en términos de soporte de API.

Eso no es verdad. Tenemos (¡bastante grande!) una serie de enlaces a las API de C++ en forma de rustllvm. Hay una serie de casos en los que compilamos ese contenedor según la versión de LLVM contra la que se compiló. En caso de que la versión de LLVM utilizada y compilada no coincida, obtendrá errores de vinculación dinámica o, lo que es peor, tendrá problemas en tiempo de ejecución.

excluye la opción de admitir el código de bits de iOS en hosts que no son de Apple.

Si Apple no quiere tomar el código de bits generado por otra cosa que no sea su bifurcación de LLVM, entonces no veo cómo podríamos hacer algo aquí que no sea mantener una bifurcación similar y aplicar ingeniería inversa a sus parches internos.

El formato de código de bits no es estable entre versiones.

Claro, pero es bastante justo suponer¹ que el código de bits entre varias revisiones de LLVM conocidas como 3.7.0, por ejemplo, es lo suficientemente compatible para generar códigos de bits para el consumo de otra compilación de LLVM de la serie 3.7.0. Ciertamente es mejor que enlazar a libLLVM dinámicamente.

¹: especialmente dado que el código de bits de la serie 3.2 sigue siendo compatible con LLVM 3.8, incluso si es una muestra muy pequeña.

Algunas notas:

  • Xcode ni siquiera incluye una libLLVM vinculable (estática o dinámica), solo una libclang.dylib que vincula estáticamente a LLVM.
  • Apple envía la fuente a su 'clang' (incluido LLVM) en 'Herramientas de desarrollador' en https://opensource.apple.com , pero ese sitio tiende a tardar una eternidad en actualizarse.
  • La historia puede ser mejor con Swift, que tiene su propia bifurcación de LLVM con etiquetas de lanzamiento , pero es posible que no se correspondan perfectamente con lo que se envía con Xcode. (Es posible usar instantáneas de cadena de herramientas de código abierto con Xcode, pero los proyectos creados con tales cadenas de herramientas no se pueden enviar a la App Store).

cc @rust-lang/compilador

Sería curioso saber cómo otros lenguajes de programación planean lidiar con esto. En particular mono y listo.

La respuesta de Unity a este problema es il2cpp: construir todos sus ensamblajes IL en código C++.

Error de golang relevante: https://github.com/golang/go/issues/12682; la sugerencia parece ser que podrían usar la cadena de herramientas LLVM go (que no es tan destacada como la cadena de herramientas go estándar).

En general, la historia del soporte de código de bits fuera de Apple es pobre.

Mono propiamente dicho va a través de Apple LLVM parecería: http://tirania.org/blog/archive/2015/Sep-02.html

Un obstáculo será que no puede llevar el ensamblaje en línea en código de bits :(

Para la historia del mono tuve un rápido intercambio con Miguel de Icaza sobre lo que Mono hace por los curiosos: https://twitter.com/mitsuhiko/status/769458873237434368

@mitsuhiko Usted _puede_ tener ensamblado en línea en código de bits en iOS y tvOS, pero no en watchOS, por alguna razón.

¿Algún movimiento al respecto? No me siento nada bien usando Rust en iOS sin un plan para admitir código de bits. Apple tiene un historial de hacer que cosas opcionales como esta no sean opcionales de manera bastante repentina y, de hecho, el código de bits ya se requiere en watchOS y tvOS.

Siento un poco que todas las soluciones recomendadas son algo asquerosas. La forma menos complicada que se me ocurre es permitir que diferentes objetivos sobrecarguen el comportamiento de generación de código y que la ruta de generación de código de Apple esté en una caja dinámica. (Que sería solo la ruta de generación de códigos normal compilada contra apple-llvm).

Este enfoque (de @ricky26) parece ser el más natural para mí como usuario de rustc.

No creo que nada haya cambiado en esto recientemente, al menos que yo sepa. Con el reciente anuncio de LLVM sobre el control de versiones, indicaron que el bitcode (creo) siempre debería poder cargarse en futuras versiones de LLVM. Eso puede significar que este problema está "resuelto" en un nivel fundamental, pero aún requeriría una interfaz más ergonómica para extraer todo el código de bits.

¿Hay alguna actualización sobre esto?

Este comentarista en HackerNews logró usar Bitcode generado desde Rust en macOS e iOS. El hilo tiene información detallada sobre cómo habilitar el código de bits para los binarios de óxido, ¡lo que suena como una gran noticia!

https://noticias.ycombinator.com/item?id=14305084

Como el comentarista en cuestión, notas rápidas:

  • Usé -C lto --emit llvm-bc para que rustc emitiera un archivo .bc que contenía la caja actual y todas las dependencias. Esto funciona, pero es esencialmente un truco; en particular, no funciona para las dependencias de C, incluido jemalloc (aunque de todos modos eso no se usa en iOS). Sería mejor si rustc admitiera correctamente la emisión de Mach-O con "código de bits incrustado"; puedes mirar la fuente de clang para ver cómo se hace.

  • Si quieres probarlo y no te importa el truco, parece que 'simplemente funciona', excepto por el problema de la versión:

  • El principal obstáculo práctico es que Rust se sincroniza con el troncal LLVM con más frecuencia que Xcode, que parece hacerlo solo una vez al año. Las versiones más nuevas de LLVM pueden cargar código de bits antiguo, pero no al revés, por lo que debe usar una versión anterior de rustc o compilar la última con un LLVM antiguo. (En realidad, rustc 1.17 parece seguir funcionando con Xcode 8.x, pero no todas las noches desde la actualización de LLVM 4.0; sin embargo, eso es solo una coincidencia).

  • Idealmente, Rust enviaría archivos binarios oficiales creados con una versión adecuada de LLVM. En la práctica, parece estar bien usar la versión correcta de LLVM estándar, pero si desea usar la bifurcación de Apple:

    • Como dije en un comentario anterior, Xcode no envía binarios LLVM en ninguna forma enlazable, ni siquiera dinámicamente; solo clang y libclang.dylib (que exporta la API de Clang pero no la de LLVM).
    • Pero, como también dije, el código fuente generalmente aparece en opensource.apple.com (en Developer Tools -> clang; el archivo incluye todo LLVM), de manera un tanto inconsistente/después de un retraso. Sin embargo, especialmente dadas las garantías de compatibilidad con versiones anteriores ampliadas señaladas por @alexcrichton , puede que no sea el fin del mundo no estar siempre actualizado. Actualmente, la versión fuente más reciente es para Xcode 8.2.1, mientras que la última es 8.3.2.

(Como prueba, intenté compilar Rust contra Xcode 8.2.1 Clang. rustllvm no se puede compilar, porque su nido de #if LLVM_VERSION_GE(..) condicionales, que están destinados a permitir que se compile contra ambos LLVM más antiguo y más nuevo, se confunde con esta rama, que dice ser LLVM 3.9svn, pero en términos de API está en algún lugar entre 3.8 y 3.9. Probablemente no valga la pena arreglarlo, ya que Xcode está casi listo para su próxima actualización anual de todos modos).

¿Se ha hecho algún progreso en este frente? Alternativamente, ¿usted (equipo central) consideraría esta terrible experiencia como un problema con una solución permanente sólida a la vista o espera que esta cosa de salto de versión permanezca en el futuro previsible?

Estoy considerando implementar partes de una aplicación de iOS en Rust por su sistema de tipo superior y su semántica de bajo nivel, y preferiría no quedarme atrapado con hacks/retrasos que no sean bitcode o regulares cuando haya una actualización para Xcode o rustc.

@regexident

Creo que vamos a implementar versiones intercambiables de LLVM por otras razones. Si eso se implementa, no deberíamos tener problemas para enviar trans por separado para Apple, wasm y todo lo demás.

CC #45684

No es código binario de Apple sigue siendo muy peligroso ala https://medium.com/@FredericJacobs/why -im-no-permitir-código binario-f35cd8fbfcc5 Imposible verificar construcciones. Problemas de criptografía. etc

@burdges Para ciertas aplicaciones, esto es absolutamente un problema.

Pero para watchOS y tvOS Apple, de hecho, requiere Bitcode para los envíos a la App Store. No tienes elección. Aparte de "no hagas cosas criptográficas o críticas en esas plataformas". También hay que temer que Apple aplique Bitcode para iOS en algún momento en el futuro. Preferiría no tener un producto bloqueado en ese momento.

Intenté construir con Rust 1.24.0 para iOS usando el truco -C lto --emit=llvm-bc , pero el enlazador dio los siguientes errores:

Undefined symbols for architecture x86_64:
  "_backtrace_create_state", referenced from:
      std::sys_common::gnu::libbacktrace::init_state::h686c3e443c712b0f in Logger(x86_64.o)
  "_backtrace_syminfo", referenced from:
      std::panicking::default_hook::_$u7b$$u7b$closure$u7d$$u7d$::h598a932d5bb0d80b in Logger(x86_64.o)
      core::iter::iterator::Iterator::position::_$u7b$$u7b$closure$u7d$$u7d$::hbf03153d55553502 in Logger(x86_64.o)
  "_backtrace_pcinfo", referenced from:
      std::panicking::default_hook::_$u7b$$u7b$closure$u7d$$u7d$::h598a932d5bb0d80b in Logger(x86_64.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

¿Alguna idea de cuál podría ser el problema?

Editar: parece que al menos puedo suprimir ese problema envolviendo todo el código en cada fn externo público con AssertUnwindSafe

libbacktrace es una biblioteca C que se incluye en el árbol de fuentes de Rust:

https://github.com/rust-lang/rust/tree/master/src/libbacktrace

Tendrás que compilarlo como bitcode de alguna manera.

Estoy confundido, porque solo puedo encontrar un libbacktrace creado para mi computadora portátil, pero no para el sistema operativo del teléfono. ¿Cómo inserta rust esos símbolos en el stdlib? ¿Hay una manera más fácil de hacer esto, deshabilitando de alguna manera la funcionalidad de rastreo? Eliminé la variable de entorno RUST_BACKTRACE pero eso no ayudó. He leído que puedes compilar rustc sin backtraces, pero esperaba algo más fácil, por ejemplo, en el archivo cargo.toml de mi proyecto

Básicamente, desea construir el árbol de fuentes de rustc mientras le indica que pase -fembed-bitcode al compilador de C. Idealmente, solo podría agregarlo a CFLAGS ; desafortunadamente, acabo de intentarlo y no funcionó correctamente debido a dos problemas con gcc-rs (utilizado por el sistema de compilación de rustc para compilar dependencias de C). Sin embargo, conseguí que funcionara con un procedimiento un poco complicado:

cd /tmp/build
cat >ccwrap.py <<END

#!/usr/bin/env python
import os, sys
os.execv('/usr/bin/xcrun', ['clang', '-fembed-bitcode'] + [arg for arg in sys.argv[1:] if arg not in {'-ffunction-sections', '-fdata-sections'}])

END

chmod 755 ccwrap.py
ln -s /usr/bin/ar ar
export CC_aarch64_apple_ios=`pwd`/ccwrap.py
/usr/src/rust/configure --target=aarch64-apple-ios
make

Esto debería darte un libbacktrace.a (en ./build/aarch64-apple-ios/native/libbacktrace/.libs/ ) con código de bits incrustado. __LLVM,__bitcode de lo que de otro modo serían bibliotecas nativas, de la misma manera que clang: entonces no habría necesidad de compilar y vincular manualmente los archivos .bc.

(En realidad, dado que el error que citó parece un error normal del enlazador, creo que podría superarlo simplemente vinculando un libbacktrace.a regular, sin código de bits incrustado. Pero en el mejor de los casos, eso daría como resultado un archivo de salida con código de bits incrustado roto).

Los problemas antes mencionados:

  • gcc-rs pasa -ffunction-sections y -fdata-sections sin forma de apagarlos; clang se queja de esto cuando se combina con -fembed-bitcode (incluso si -fno-function-sections se pasa más tarde).

Presenté un informe de problemas y, como solución alternativa, el procedimiento anterior utiliza una secuencia de comandos contenedora que elimina esos argumentos. Pero eso causó un segundo problema:

  • gcc-rs intenta encontrar ar en el mismo directorio que CC_aarch64_apple_ios (!?); configurar manualmente AR_aarch64_apple_ios no tuvo ningún efecto

No pude reproducir esto con el último cc-rs (renombrado de gcc-rs ), así que no presenté un problema. Como solución alternativa, el procedimiento anterior vincula ar en el mismo directorio.

¡Gracias por las sugerencias! De hecho, solo necesitaba el código de bits para mi propio código, no las cosas de backtrace, así que solo usé el libbacktrace compilado sin ninguna incrustación de código de bits

Con el truco que probé, ahora me encuentro con otro problema: dsymutil segfaults cuando intento crear un dSYM para él. La ejecución normal sin dSYM funciona bien, pero la creación de dSYM se interrumpe por alguna razón. Eliminé mi libbacktrace.a, lo reemplacé con funciones de marcador de posición vacías y todo funcionó bien, por lo que parece que hay un problema con mi rust lib.

Eso suena como un error en dsymutil, que debe informarse aguas arriba a LLVM. ¿Puede intentar ejecutar dsymutil en LLDB y publicar un seguimiento del bloqueo? O para obtener mejor información de depuración, puede intentar compilar LLVM en modo de depuración y reproducirlo con eso.

(Tenga en cuenta que el binario en una instalación de LLVM estándar se llama llvm-dsymutil , pero en estos días el dsymutil Xcode es solo un enlace simbólico a llvm-dsymutil . dsymutil solía ser una utilidad de código cerrado separada, pero durante algunos años esa versión se envió como dsymutil-classic y no se usó de manera predeterminada).

@comex por curiosidad, ¿debería la caja cc compilar todo con -fembed-bitcode ? O si estamos usando el sonido "oficial", ¿está bien evitar incrustar código de bits?

(¡Lo siento, no estoy muy familiarizado con las mejores prácticas de ios!)

Para el código Rust en sí, ¿sería mejor si simplemente emitiéramos un código de bytes en lugar de archivos de objetos? ¿Es eso algo que Clang/el enlazador puede entender?

@alexcrichton

¿debería la caja cc compilar todo con -fembed-bitcode ? O si estamos usando el sonido "oficial", ¿está bien evitar incrustar código de bits?

El uso del sonido metálico oficial no elimina la necesidad de un código de bits incrustado. Más bien, el código de bits se incluye, además del código nativo, en el archivo de la aplicación cargado en Apple, y luego Apple puede volver a compilarlo en el lado del servidor, por ejemplo, para optimizarlo para diferentes microarquitecturas.

Probablemente tendría sentido pasar -fembed-bitcode de forma predeterminada en iOS/watchOS/tvOS. Si es así, al compilar en modo de depuración, se debe pasar -fembed-bitcode-marker (en lugar o además, no importa); esto le dice a clang que solo incluya una sección de código de bits ficticio en lugar de cualquier código de bits real, ya que el código de bits incrustado solo se necesita para los archivos finales de la aplicación y acelera ligeramente la compilación para omitirlo. En realidad, Xcode pasa -fembed-bitcode-marker para todo lo que no sea la creación del archivo final de la aplicación, incluso las compilaciones de desarrollo que tienen optimizaciones, pero dado que cc no tiene un concepto separado de "versión realmente final modo", probablemente debería simplemente pasarlo en modo de depuración. Tenga en cuenta que es seguro incrustar código de bits incluso si la compilación final no lo requiere.

Para el código Rust en sí, ¿sería mejor si simplemente emitiéramos un código de bytes en lugar de archivos de objetos? ¿Es eso algo que Clang/el enlazador puede entender?

Tanto clang como ld admiten archivos de código de bits sin procesar que se pasan como entradas; esto normalmente se usa cuando LTO está habilitado ( -flto ), en cuyo caso los archivos .o que genera clang son en realidad código de bits sin formato, no Mach-O. (Éstos aún se pueden formar en bibliotecas estáticas usando el comando lipo normal). Sin embargo, esto es independiente del formato de "código de bits incrustado", que consiste en un Mach-O con código de bits metido en la sección __LLVM,__bitcode , en además de código nativo en las secciones habituales. Este formato se utiliza en archivos de objetos cuando LTO está desactivado, así como en ejecutables vinculados finales o bibliotecas dinámicas, independientemente de la configuración de LTO. (Si LTO está activado, el enlazador es responsable de crear esta sección; si LTO está desactivado, el enlazador simplemente concatena las secciones __LLVM,__bitcode de cada archivo de objeto como lo haría con cualquier otra sección, en lugar de generar un solo módulo de código de bits. ) EDITAR: en realidad, hace algo un poco más complicado , genera un archivo xar de las secciones de código de bits y las coloca en una sección llamada __LLVM,__bundle ; de todos modos, no es algo que tenga que preocuparnos.

Creo que idealmente rustc debería producir un "código de bits incrustado" de forma predeterminada en iOS, no un código de bits sin formato. No es demasiado difícil de hacer y evita romper la compilación incremental, especialmente en el modo de depuración, donde puede producir una sección de código de bits ficticia, como -fembed-bitcode-marker , pero potencialmente también en el modo de lanzamiento, ya que el enlazador simplemente rellena los objetos. ' Secciones de código de bits juntas en lugar de hacer algo costoso en el momento del enlace.

Así es como clang genera un código de bits incrustado:

https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/BackendUtil.cpp#L1242

Relativamente simple: antes de invocar el backend, descarga el módulo LLVM actual como código de bits, luego
mete eso como datos binarios en una nueva variable global (¡en ese mismo módulo!), Colocada en la sección __LLVM,__bitcode . Parece una especie de diseño hacky (¿por qué la interfaz tiene que hacer esto manualmente?), Pero no debería ser demasiado difícil de reproducir en rustc.

@comex ese enfoque tiene sentido, aunque creo que hay razones (ver #48833 que acabo de hacer) para usar el sonido metálico de Apple como backend, mientras estamos pensando en cambios como este. Además, ¿qué tan fácil es compilarnos a nosotros mismos a partir del código de bits incrustado?

@michaeleiselsc Lo siento, no entiendo lo que quiere decir con "compilarnos a partir del código de bits incrustado".

Como en, en lugar de simplemente dar un binario a la tienda de aplicaciones con un código de bits incrustado, también hay beneficios al tomar el código de bits y construirlo nosotros mismos usando Apple Clang. Dos beneficios que me interesan son las correcciones posteriores que tiene Apple Clang y la capacidad de usar desinfectantes de sonido, por ejemplo, el desinfectante de cobertura.

@comex ok, así que bastante fácil (relativamente), pero tengo algunas preguntas:

  • ¿Por qué -fembed-bitcode-marker una cosa? Usando clang localmente, solo emite una estática vacía en una sección. ¿Significa eso que la mera presencia de la sección significa algo? ¿Se rompe alguna herramienta en el camino en iOS si la sección no está allí? (¿pero en realidad no se ve dentro de la sección porque está vacía?
  • ¿Sabes si la sección __cmdline es necesaria? Parece que -fembed-bitcode también incorpora algún tipo de línea de comandos en el binario. No estoy muy seguro de lo que pondríamos aquí, ya que probablemente no sea la línea de comando de rustc, pero ¿alguna herramienta analiza esto? ¿Se interrumpe la compilación si se usa -fembed-bitcode=bitcode con iOS?
  • Y finalmente, ¿hay alguna razón para querer deshabilitar esto? ¿O deberíamos simplemente habilitar esto incondicionalmente para los objetivos de iOS y seguir adelante?

¿Por qué es -fembed-bitcode-marker una cosa?

Creo que xcode lo usa para indicar que se supone que algo debe usar bitcode, pero en realidad no se compiló bitcode. Si intenta archivar un proyecto de este tipo más tarde, ld fallará con un error.

A la pregunta de si queremos habilitar esto siempre, definitivamente hay algunos casos en los que nos gustaría tener cuidado. Por ejemplo, si alguien lo envía a una plataforma de distribución de aplicaciones beta como HockeyApp, ¿HockeyApp eliminará esa sección de código de bits o los probadores beta tendrán que descargar un binario mucho más grande de lo que necesitan?

@mitsuhiko Sí, la idea es que el enlazador pueda verificar que la compilación esté configurada correctamente para el código de bits, incluso si actualmente está probando compilaciones que en realidad no necesitan el código de bits.

Por ejemplo, si compila un archivo C sin mencionar el código de bits, luego intenta vincularlo con -fembed-bitcode-marker , obtiene:

$ clang -c -o test.o test.c
$ clang -dynamiclib -o test.dylib test.o -fembed-bitcode-marker
ld: warning: all bitcode will be dropped because 'test.o' was built
without bitcode. You must rebuild it with bitcode enabled (Xcode
setting ENABLE_BITCODE), obtain an updated library from the vendor,
or disable bitcode for this target.

La advertencia desaparece si también pasa -fembed-bitcode-marker en la primera línea.

@alexcrichton En cuanto a __cmdline ... hmm... parece que el enlazador requiere que esté presente (busque "Crear código de bit"):

https://opensource.apple.com/source/ld64/ld64-274.2/src/ld/parsers/macho_relocatable_file.cpp.auto.html

Pero no veo nada que se preocupe por el valor real. Probablemente sea mejor poner un valor ficticio allí.

¿Se resolvió este problema fusionando #48896?

He estado jugando con esto en las compilaciones nocturnas y funciona muy bien hasta que intentas archivar con Xcode. Parece que está agregando fembed-bitcode-marker pero no fembed-bitcode a la salida de la biblioteca estática de Rust. Está compilado con cargo lipo --release con:

$ cargo --version
cargo 1.27.0-nightly (af3f1cd29 2018-05-03)
$ cargo lipo --version
cargo-lipo 2.0.0-beta-2
$ rustc --version
rustc 1.27.0-nightly (565235ee7 2018-05-07)
ld: '/Users/chrisbal/Documents/Beach/rust-universal-template/target/universal/release/libexample.a(example_generic-be72fb1769c1779b.example_generic6-152d14edfb6970f54250733c74e59b7.rs.rcgu.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Cuando ejecuto otool -arch arm64 -l /Users/chrisbal/Documents/Beach/rust-universal-template/target/universal/release/libexample.a | grep bitcode obtengo muchos sectname __bitcode , pero no sé cómo verificar si se trata de un código de bits real y no solo de marcadores.

Estoy usando cajas anidadas, así que tal vez la caja "genérica" ​​interna no está recibiendo las banderas de código de bits.

editar: aquí está nuestro repositorio que demuestra el problema https://github.com/Raizlabs/rust-universal-template/tree/879e7412d729e8963586c5b083d51b09733aec32

@chrisballinger , funciona con bandera adicional, ver
RUSTFLAGS="-Z embed-bitcode" cargo lipo --release

$ cargo --version
cargo 1.28.0-nightly (f352115d5 2018-05-15)
$ cargo lipo --version
cargo-lipo 2.0.0-beta-2
$ rustc --version
rustc 1.28.0-nightly (952f344cd 2018-05-18)

Pero tengo otro error de compilación solo para arm7 arch:

.rs.rcgu.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture armv7

¿Alguien sabe cómo arreglar arm7 arch ?

Lamentablemente, no puedo hacerlo funcionar tan bien, obteniendo el mismo error que @chrisballinger :

ld: '/sandbox/target/universal/release/librgame.a(std-da6dba40351cda22.std3-d36cd881bae00a8b5fc36289b5737f78.rs.rcgu.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Intenté compilarlo con RUSTFLAGS="-Z embed-bitcode" cargo lipo --release y configurarlo en .cargo/config . Sin embargo, agrega la bandera:

` Executing: "cargo" "build" "--target" "x86_64-apple-ios" "--lib" "--features" "" "--color" "auto" "--release" "--verbose" Compiling libc v0.2.42 Compiling rand_core v0.2.1 Running `rustc --crate-name libc /Users/aleksandrivanov/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.42/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 --cfg 'feature="default"' --cfg 'feature="use_std"' -C metadata=dce309634355ac97 -C extra-filename=-dce309634355ac97 --out-dir /Users/aleksandrivanov/Sandbox/Projects/tetris/rgame/target/x86_64-apple-ios/release/deps --target x86_64-apple-ios -L dependency=/Users/aleksandrivanov/Sandbox/Projects/tetris/rgame/target/x86_64-apple-ios/release/deps -L dependency=/Users/aleksandrivanov/Sandbox/Projects/tetris/rgame/target/release/deps --cap-lints allow -Zembed-bitcode` ...

¿Alguna actualización aquí? Considerar seriamente una biblioteca central compartida para nuestra aplicación y sin esta solución c ++ es la opción probable.

@chrisballinger , ¿puede estar relacionado con https://github.com/rust-lang/rust/issues/52686?

@volodg No, este problema es de hace un tiempo.

Con la fusión de #48896, ¿se supone que funciona de inmediato?

Estoy en 1.29.1 y los objetos aún no tienen un código de bits incrustado de forma predeterminada. Como mencionó @volodg anteriormente, puede oxidarse para incrustarlos usando RUSTFLAGS="-Z embed-bitcode" . Pero, por lo que experimenté, entonces te encuentras con un problema en el que las bibliotecas propias de Rust (compiler_builtins, std) no se compilan con el código de bits incrustado. Tal vez la reconstrucción de objetivos de iOS usando xargo con código de bits incrustado funcionaría, pero no lo intenté.

Intenté usar xargo como me propusiste, pero el problema parece seguir ahí :(

Usando este Xargo.toml

[dependencies]
std = {}
[target]
features = ["jemalloc"]

También agregando esto a Cargo.toml :

[profile.release]
panic = "abort"

Compilé usando xargo build --release --target $TARGET para todos esos objetivos:

  • aarch64-apple-darwin
  • armv7-apple-darwin
  • armv7s-apple-darwin
  • i386-apple-darwin
  • x86_84-manzana-darwin

Luego usé lipo para crear una biblioteca estática.

Todavía tengo un error del enlazador:

ld: '../../cargo/target/universal/libgreetings.a(greetings-ceeec73d35f7dbe0.greetings.9kcaav8v-cgu.2.rcgu.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Llegamos un poco más lejos con el camino del xargo.

Mi Xargo.toml

[dependencies]
std = {}

Mi Cargo.toml

[profile.release]
panic = "abort"

No sé si es necesario, pero desde xargo doc, debe usar explícitamente extern crate compiler_builtins , que agregué a mi lib.rs.

Luego compilé con: RUSTFLAGS="-Z embed-bitcode" xargo build --target $TARGET --release para compilar. Asegúrese de compilar core/std/compiler_bultins. xargo clean no limpia las compilaciones anteriores correctamente de lo que experimenté, por lo que fue necesario un rm -rf ~/.xargo para volver a compilar std cuando probé diferentes ajustes de Xargo.toml .

Pero luego, al archivar en Xcode 10, obtengo (a armv7 vinculación):

Intrinsic has incorrect argument type!
void (i8*, i8, i32, i1)* @llvm.memset.p0i8.i32
Intrinsic has incorrect argument type!
void (i8*, i8*, i32, i1)* @llvm.memcpy.p0i8.p0i8.i32
Intrinsic has incorrect argument type!
...
(lots of it)
...
LLVM ERROR: Broken module found, compilation aborted!
clang: error: linker command failed with exit code 1 (use -v to see invocation)

¿Significa que el error depende del lado de LLVM?

EDITAR : ¿Cómo podemos ayudar a avanzar en este tema?

¿Alguien ha probado esto recientemente? ¿Parece que armv7 es el mayor problema?

Hola a todos. He estado siguiendo este hilo durante un tiempo y estoy muy emocionado de ver que el código de bits de Apple es compatible con Rust. ¿Alguien ha podido hasta ahora hacer que esto funcione? ¿Qué falta actualmente y cómo podemos ayudar?
¡Gracias!

Después de algunas horas de buscar este problema, encontré la razón por la cual la incrustación de código de bits de Rust no funciona en Xcode. La respuesta corta es que la versión LLVM de Xcode espera el código de bits LLVM 6.0 , mientras que Rust julio de 2018 .

Ahora, la respuesta larga...

Como podemos ver en el registro de @llvm.memcpy , @llvm.memmove y @llvm.memset , y el error de compilación de Xcode fue claro sobre el tipo de argumento incorrecto como se ve en mi comentario anterior .

Por cierto, Kotlin Native agregó soporte para código de bits incrustado en octubre de 2018 y aparentemente funciona bien en Xcode . La razón es que Kotlin todavía usa LLVM 6.0 .

Al ver eso, traté de compilar usando una versión anterior de Rust antes de pasar a 7.0. Probé con nightly-2018-06-01-x86_64-apple-darwin , y éxito, ¡compila!

También traté de compilar sin usar Xargo sin éxito. Todas las dependencias deben compilarse con incrustación de código de bits.

En resumidas cuentas, a menos que Apple mejore su versión LLVM, no creo que veamos soporte para el código de bits incrustado en el corto plazo... A menos que alguien encuentre una forma inteligente de convertir el código de bits incrustado en el código de bits de 6.0...

@appaquet ¡ Gracias por llegar al fondo! Fue todo un misterio para mí y no creo que alguna vez me sumergiera tan profundo como lo hiciste tú. Es bueno saber que probablemente debería comenzar a funcionar una vez que Apple actualice la versión LLVM.

Gracias @appaquet por tu clara respuesta. Ahora supongo que solo tenemos que confiar en Apple para hacer lo correcto.

Vista lateral de alguien que tiene interés en multiplataforma para dispositivos móviles y comparó la mayoría de las soluciones prometedoras (React Native, Flutter, Kotlin/Native, Rust)

Reacciona Nativo. Admite código de bits desde el inicio, porque esencialmente el puente está escrito en C++ y solo interpreta el código JS en tiempo de ejecución.

Aleteo. Todavía no es compatible con el código de bits: https://github.com/flutter/flutter/issues/15288

Kotlin/Nativo. JetBrains está considerando las plataformas móviles como una prioridad y, aunque les tomó un tiempo y son solo marcadores de código de bits (todavía no es un código de bits completo), es lo suficientemente bueno para comenzar a trabajar; consulte https://github.com/JetBrains/kotlin-native/ pull/1564 y https://github.com/JetBrains/kotlin-native/issues/1202#issuecomment -444022513

Óxido. Admite código de bits para LLVM 7, mientras que Apple usa la versión 6.

Si quiero tener tanto la lógica empresarial como la interfaz de usuario multiplataforma, elegiría React Native o Flutter. Pero para muchas, muchas aplicaciones serias, este camino es demasiado arriesgado. React Native no tiene el rendimiento suficiente y la API y la estabilidad de la dependencia son un problema (¿llegará alguna vez la versión 1.0?). Flutter es un poco inmaduro pero parece ganar más y más tracción.

Ahora, si quiero compartir solo la lógica empresarial en algún tipo de módulos (como lo hicieron las grandes aplicaciones anteriores con C ++ y JNI/Obj-C ++) y luego construir una interfaz de usuario verdaderamente nativa en la parte superior, al principio tengo una opción entre los cuatro. Luego tacho React Native, porque tomar JavaScriptCore completo y puente para ejecutar la lógica de negocios entre JS<->Native parece un poco exagerado (iniciar este puente también es bastante costoso). Flutter potencialmente se puede usar, pero no está diseñado de esa manera , por lo que nuevamente terminaría usando el marco de la interfaz de usuario para ejecutar la lógica comercial. Además, no es compatible con código de bits.
Rust y Kotlin/Native apuntan a este nicho, tienen herramientas decentes, producen binarios nativos (¡rendimiento y huella!). Bitcode es un gran problema para aquellos que quieren adoptar Rust como lenguaje para construir módulos multiplataforma en plataformas móviles. Y ahora Kotlin/Native tiene una ventaja.

Para resumir por qué el código de bits es muy importante para los desarrolladores de iOS. No puedo escribir nada en tvOS o watchOS. Muchos marcos de terceros que se distribuyen como archivos binarios tienen bitcode habilitado (docenas de ejemplos, desde la parte superior de mi cabeza Google IMA: el anuncio de video más popular). Algunas auditorías de seguridad lo requieren. Y finalmente, cada vez que Apple dice "a partir del próximo año ya no aceptaremos aplicaciones sin un código de bits completamente integrado", todo el mundo recibe un cronómetro.

Ahora supongo que solo tenemos que confiar en Apple para hacer lo correcto.

Sí, claro, esto es por lo que Apple es conocido;)
No sé cuál sería la mejor solución (bajar temporalmente a LLVM 6 no es una opción, ¿verdad?), Pero Rust está perdiendo por completo a los desarrolladores multiplataforma de iOS y móviles.

Muchas gracias por esta explicación detallada @oleksandr-yefremov. He estado leyendo un poco sobre el tema y encontré este interesante comentario: https://gist.github.com/yamaya/2924292#gistcomment -2738480

La versión de LLVM está vinculada a la versión de Swift utilizada en XCode. Hasta el momento se aplicó el siguiente apoyo:

Xcode 8.3  --> swift 3.1 --> llvm 4.0.0
Xcode 9.0  --> swift 4.0 --> llvm 4.0.0
Xcode 9.3  --> swift 4.1 --> llvm 5.0.2
Xcode 10.0 --> swift 4.2 --> llvm 6.0.1

Mientras miraba el swift-5.0-branch , noté que la versión declarada de LLVM es 7.0.0 : https://github.com/apple/swift-llvm/blob/swift-5.0-branch/ CMakeLists.txt#L25 -L33

No sé si hay más bloqueadores aquí, pero me parece que podríamos usar Rust para generar binarios de Bitcode 🎉

Parece que Xcode 10.2 incluirá Swift 5.0 y, de hecho, debería lanzarse muy pronto. Pero, por otro lado, LLVM 8.0 está programado para ser lanzado la próxima semana. Es muy probable que Rust se actualice antes de que Apple comience a usarlo.

Para que Rust admita correctamente el código de bits, necesitaríamos las compilaciones de arquitecturas Apple ARM de Rust para usar una versión anclada de LLVM (tal vez del repositorio https://github.com/apple/swift-llvm: Apple no parece usar el lanzó el paquete LLVM pero sus propias sucursales). Esa versión de LLVM solo se actualizaría cuando Apple lance una nueva versión final de Xcode con una versión diferente de LLVM.

Por cierto, parece que el último Rust se puede construir con LLVM 6, por lo que definitivamente parece factible: https://github.com/rust-lang/rust/blob/master/src/bootstrap/native.rs#L282
Definitivamente necesitaría que la gente interviniera cuando se crea un problema para actualizar la versión requerida de LLVM (la de LLVM 6: https://github.com/rust-lang/rust/issues/55842).

@vincentisambart Rust ya ha estado usando LLVM 8 para compilaciones nocturnas durante 5 meses IIRC.
LLVM 6 es una versión mínima compatible si desea compilarlo usted mismo y se prueba en CI: https://github.com/rust-lang/rust/blob/706e67b0a0143d651eb03f2fa2c30645899e81ff/src/ci/docker/x86_64-gnu-llvm-6.0 /Dockerfile

Ahora supongo que solo tenemos que confiar en Apple para hacer lo correcto.

He estado persiguiendo algo en este sentido durante un tiempo (y ahora he salido) y supongo que, en cuanto a la plataforma, no tiene sentido que Apple haga esto, porque:

  • Swift quiere ser Rust de varias maneras (ver el manifiesto de propiedad para uno) pero se está quedando atrás mucho
  • Apple necesita que Swift sea y siga siendo el idioma principal de su plataforma, por lo que no tiene sentido que faciliten otro idioma importante en su plataforma ni que impulsen a Swift a otros entornos.

Rust ya ha estado usando LLVM 8 para compilaciones nocturnas durante 5 meses IIRC.

Entonces, incluso si Apple comienza a admitir el código de bits LLVM 7, es posible que el código de bits generado por las compilaciones oficiales recientes de Rust no funcione. Incluso si lo hace, podría fallar la próxima vez que Rust cambie a una versión de LLVM con un cambio incompatible en el código de bits generado.

LLVM 6 es una versión mínima compatible si desea construirlo usted mismo y se prueba en CI

Luego, hacer que las compilaciones oficiales de *-apple-ios de Rust se construyan con LLVM 6 (o mejor algo como https://github.com/apple/swift-llvm/releases/tag/swift-4.2.2-RELEASE, si que funciona) podría solucionar los problemas de código de bits.

Creo que Rust actualmente se envía con dos backends LLVM (Emscripten y estándar) después de la fusión de https://github.com/rust-lang/rust/issues/46819.
Aunque #46819 menciona el backend LLVM de ios para el código de bits, no se implementó.

No para descarrilar esto por completo, pero ¿no tendría más sentido en general intentar habilitar la transpilación a C para tales casos? Es poco probable que Rust pueda mantenerse al día con los requisitos de código de bits por parte de Apple.

Incluso si existen fuentes potenciales de incompatibilidades, abre la puerta a pruebas en las que podríamos intentar compilar con una versión anterior compatible de Rust, una que incorpore la versión LLVM correcta para Apple.

En un enfoque multiplataforma completo, esto sigue siendo un gran bloqueo, obviamente, ya que necesitaríamos poder compilar el mismo código fuente de la última versión de Rust para beneficiarnos de las últimas mejoras y también para poder compilar desde una versión más antigua. versión de Rust, específicamente para generar binarios compatibles con códigos de bits para el ecosistema de Apple. Eso es factible, pero no adecuado.

Todavía estoy muy emocionado de ver que esto suceda, ya que al menos abrirá las puertas para que más personas prueben esto y nos empuje a todos hacia adelante en la dirección correcta.

Hablando como alguien que en este momento está tratando de decidir un enfoque para escribir código móvil multiplataforma para un equipo bastante grande, literalmente no podemos usar Rust si no podemos generar código de bits. Una de nuestras aplicaciones se basa en código de bits para poder generar un binario lo suficientemente pequeño para descargarlo a través de redes celulares, y tenemos algunos clientes importantes que insisten en eso.

Basado en todo lo que veo sobre Rust, creo que tiene la mayor ventaja a largo plazo de cualquiera de las posibilidades que veo (Kotlin Multiplatform, compilación cruzada de Swift, Mono, Dart, C ++, React Native), pero definitivamente necesitaría bitcode para ser totalmente compatible, incluso si eso significaba no poder mantenerse al día con las últimas versiones de Rust.

Incluso si el código de bits funcionó, Rust aún no puede apuntar a watchOS o tvOS de todos modos, ¿o sí?

Es poco probable que Rust pueda mantenerse al día con los requisitos de código de bits por parte de Apple.

El problema aquí es que el LLVM de Rust es demasiado nuevo , no que sea demasiado antiguo . Estoy de acuerdo en que deberíamos tener una mejor historia de compatibilidad aquí.

¿Qué tan factible es que rustc admita múltiples LLVM?

Relacionado: Compatibilidad con objetivos de tvOS y watchOS (y simulador)

Ya utiliza múltiples LLVM. Para los objetivos de emscripten, utiliza la bifurcación LLVM de emscripten que está en LLVM 6 atm.

El problema aquí es que el LLVM de Rust es _demasiado nuevo_, no que sea _demasiado viejo_. Estoy de acuerdo en que deberíamos tener una mejor historia de compatibilidad aquí.

El problema no es que sea demasiado antiguo o demasiado nuevo, sino que incluso si el óxido coincide con la versión de LLVM, en cualquier versión de iOS, esto puede fallar nuevamente. Apple (hasta donde yo sé) no garantiza de ninguna manera la estabilidad con respecto al código de bits.

El problema no es que sea demasiado antiguo o demasiado nuevo, sino que incluso si el óxido coincide con la versión de LLVM, en cualquier versión de iOS, esto puede fallar nuevamente. Apple (hasta donde yo sé) no garantiza de ninguna manera la estabilidad con respecto al código de bits.

En la práctica, vemos actualizaciones importantes de Xcode una vez al año cuando salen nuevas versiones de iOS. Cuando esto sucede, los desarrolladores reciben un aviso bastante claro de que deben comenzar a enviar aplicaciones con una versión más nueva de Xcode, por lo que rara vez sorprende. No diría que esto es particularmente difícil de planificar.

No diría que esto es particularmente difícil de planificar.

Dado que no hay absolutamente ninguna garantía en torno al código de bits, eso podría convertirse en algo muy difícil de planificar. Imagínese que de una versión a otra decidieran usar su propio formato de código de bits que no termina en una versión de código abierto de LLVM.

Dado que no hay absolutamente ninguna garantía en torno al código de bits, eso podría convertirse en algo muy difícil de planificar. Imagínese que de una versión a otra decidieran usar su propio formato de código de bits que no termina en una versión de código abierto de LLVM.

Si vamos a suponer que Apple va a hacer cambios importantes sin tener en cuenta a nadie más, seguro. Tener una documentación más clara sobre sus planes para Bitcode no mejora mucho si asumimos que son maliciosos o simplemente no les importa.

Pero claramente han hecho de Swift una parte importante de su plataforma y muchos miles de desarrolladores dependen de ella, incluidos sus propios equipos y algunos de sus socios más importantes. Swift se basa en el LLVM de código abierto y se está desarrollando completamente al aire libre, incluida la cadena de herramientas que usa Xcode para generar el código de bits que Apple acepta.

Entonces, para que cambien repentinamente ese formato sin que nadie se dé cuenta o se preocupe, requeriría que tomaran en privado sus repositorios Swift y LLVM, ¿verdad? Ciertamente es posible, pero no me parece muy probable.

Si el equipo de Rust decide que el riesgo de eso es una buena razón para no admitir bitcode, esa es sin duda su prerrogativa. Me entristecería un poco eso, pero no me corresponde decirles a los demás dónde pasar el tiempo.

Dado que no hay absolutamente ninguna garantía en torno al código de bits, eso podría convertirse en algo muy difícil de planificar. Imagínese que de una versión a otra decidieran usar su propio formato de código de bits que no termina en una versión de código abierto de LLVM.

Apple lanza Xcode Beta a principios de junio y la versión final en septiembre. Después de 6 a 9 meses, deja de aceptar aplicaciones compiladas con versiones anteriores de Xcode en Appstore.

Creo que hay suficiente tiempo para preparar los cambios de código de bits durante esa línea de tiempo.

Acabo de probar con Xcode 10.2 beta 3 (que incluye Swift 5 con LLVM 7) y pude vincularme con un Rust reciente por la noche con código de bits incrustado. Obviamente, esto solo funciona con objetivos de iOS, ya que Rust no tiene objetivos de watchOS/tvOS .

También acepto que Rust debe poder usar la bifurcación LLVM de Apple para todos los objetivos relacionados con Apple para mantener la compatibilidad con los códigos de bits.

Sí, la ventana de lanzamiento beta suena razonable. Creo que la idea de que Apple vaya a cerrar la fuente LLVM o su formato de código de bits es muy poco probable, pero Apple requiere código de bits en futuras versiones de iOS definitivamente parece que sucederá. Y quién sabe, tal vez incluso comiencen a requerir código de bits para las presentaciones de Mac App Store con el proyecto Mazapán.

El tipo de forma no garantizada de lidiar con la compatibilidad que se propone es verdaderamente repulsiva, pero creo que las plataformas móviles eventualmente deberían convertirse en plataformas de nivel 1 , especialmente en los casos en los que de otro modo habrías usado C++, como para el desarrollo de videojuegos. Además, también podría desarrollar juegos con Rust para Apple TV.

Espero que un enfoque sancionado oficialmente por el equipo Compiler anime a alguien a trabajar en esto, pero creo que un comentario anterior de @brson resume la vacilación:

Mantenemos con éxito la compatibilidad entre varias versiones de LLVM. Siempre que Apple y el nuestro no se separen demasiado, debería ser factible, pero siempre existe el riesgo de una ruptura tan grande que la división no se puede cruzar.

O tal vez el código de bits se estabilice en el futuro y todos olvidemos que este debate sucedió alguna vez 🙏

Me comeré mi sombrero ahora 😞

en el que dije:

la idea de que Apple va a cerrar la fuente LLVM o su formato de código de bits es muy poco probable

Lo cual fue principalmente en respuesta a la desconfianza expresada por @mitsuhiko :

Imagínese que de una versión a otra decidieran usar su propio formato de código de bits que no termina en una versión de código abierto de LLVM.

Pero si observa el problema #48833 , definitivamente hay un precedente. Como @comex escribió anteriormente:

ha habido casos en los que las características aparecen en el LLVM de Xcode antes que el troncal LLVM, como todo el puerto arm64, cuando se desarrolló originalmente, porque Apple quería mantener en secreto que planeaban enviar dispositivos arm64

Y la historia de @michaeleiselsc del mismo problema:

una aplicación en la que estaba trabajando se vio muy afectada por reinicios aleatorios en diciembre de 2016, y se debe a un problema específico que el LLVM de código abierto solo solucionó en diciembre de 2017. Cuando pasamos del LLVM de código abierto al LLVM de Apple en diciembre de 2016, el problema fue arreglado

Dado que la idea es usar LLVM de Apple con Rust, no suena tan mal, pero definitivamente existe el riesgo de tener algún error desagradable ocasional debido a implementaciones divergentes 😢. No es un riesgo que todos los proyectos puedan asumir. La transpilación suena como una mejor opción en este momento, pero hasta ahora, no parece tan posible .

Sigo pensando que debería admitirse el uso de LLVM de Apple, pero debería haber advertencias claras en la documentación que explique que no hay garantías de que las cosas sigan funcionando (un nivel 1.5 o algo así).

Kotlin/Nativo. JetBrains está considerando las plataformas móviles como una prioridad y, aunque les tomó un tiempo y solo son marcadores de código de bits (todavía no es un código de bits completo), es lo suficientemente bueno para comenzar a trabajar con ellos; consulte JetBrains/kotlin-native#1564 y JetBrains/kotlin-native# 1202 (comentario)

¡Gracias por señalar esto @oleksandr-yefremov! Profundicé un poco más y pude replicar el enfoque nativo/ kotlin en golang . Creo que ustedes deberían poder hacer lo mismo, lo que permitiría usar rust en aplicaciones iOS/tvOS/watchOS habilitadas con bitcode sin necesariamente emitir bitcode.

¿Bitcode funciona ahora? ¿Alguien intentó?

@volodg Soy un novato en óxido. Sin embargo, realicé este tutorial con el último rust todas las noches (al momento de escribir rustc 1.37.0-nightly (088b98730 2019-07-03) ) y NO funcionó.

Parece que los marcadores están ahí..

$ otool -arch arm64 -l librust.a  | grep bitcode
  sectname __bitcode
...

Pero recibo el siguiente error al construir para un dispositivo iOS (el simulador funciona):

ld: '/Users/amrox/Documents/Projects/rust-ios-example/hello-rust/libs/librust.a(rust-e6011ffb55678675.rust.8yq9vjk7-cgu.3.rcgu.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Eso es todo lo que tengo.

Logré vincular rustc nightly-2019-09-05 aarch64-apple-ios and rustflags = "-C lto -Z embed-bitcode" staticlib con la aplicación clang-1100.0.33.5 (Xcode 11 beta 7) and -fembed-bitcode . El código fuente es https://github.com/saturday06/rust-ios-bitcode-test .

  • ¿Sabes si la sección __cmdline es necesaria?

Dos años después, puedo responder esto: para implementar en dispositivos físicos o crear archivos Xcode, una línea de cmd vacía está bien, sin embargo, para los envíos de App Store, Apple realiza la validación de la línea de comando clang. He puesto una descripción más larga en este PR, que incluye un parche hacky para que funcione: https://github.com/getditto/rust-bitcode/pull/7

Me gustaría upstream esto de alguna manera, pero las opciones no son atractivas. ¿Inventamos algunas opciones de sonido cuando apuntamos a iOS? ¿Proporcionamos un envvar para elegir exactamente cómo mentir en caso de que Apple cambie sus reglas de validación? Estaría feliz de hacer el cambio si hay una opción razonable aquí.

-Cembed-bitcode=no no funciona para el objetivo ios. todavía hay una sección de código de bits en un archivo .a
¿Cómo construir sin código de bits?

¿Fue útil esta página
0 / 5 - 0 calificaciones