Runtime: Aplicación de consola autónoma de un solo exe

Creado en 3 nov. 2016  ·  98Comentarios  ·  Fuente: dotnet/runtime

La publicación de una aplicación de consola autónoma en .net core, como se describe aquí, da

¿Es posible agrupar todas las dependencias para que obtengamos un solo ejecutable? Un myapp.exe gran tamaño cuando se orienta a Windows, por ejemplo.

Supongo que estoy buscando algo similar a ILMerge, pero para .net core. ¿Es posible mediante algún indicador de opción en dotnet publish o algún otro comando? Si no es así, considérelo como una solicitud de función. Gracias.

area-Meta question

Comentario más útil

Esto es simplemente horrible, me pregunto por qué se aprobó durante el proceso de diseño, quiero distribuir su aplicación a uno de sus clientes, luego le deseo buena suerte para encontrar qué abrir:
image

Esto es feo y un completo desastre

tiempo de ejecución /
MyProgram.exe
MyLib.dll

Esta hubiera sido una idea mucho mejor

Incluso Java lo maneja mejor:
explorer_2018-04-21_16-42-33

Todos 98 comentarios

Este escenario no es compatible en este momento. Esté atento al repositorio https://github.com/dotnet/corert para el trabajo que lo llevará por este camino.

CoreRT es el lugar adecuado para buscar esta solución.

Gracias. Parece que CoreRT es exactamente lo que estaba buscando.

Para otros que puedan tropezar con esto, lea aquí

Específicamente quiero esta función sin una compilación previa. No quiero corert, quiero la misma experiencia de jit, depuración y tiempo de ejecución que una aplicación autónoma normal, pero tampoco quiero distribuir cuatro archivos por utilidad. Eso es un inconveniente para quien quiera usar la utilidad. Solo lo quiero empaquetado y ejecutado desde un solo archivo ejecutable. Esto me está haciendo elegir .NET Framework sobre .NET Core para muchas utilidades.

.NET Framework es "trampa", ya que tiene muchos archivos presentes en el sistema operativo.
Puede lograr lo mismo con .NET Core, instalando .NET Core compartido en toda la máquina si eso es lo que desea.

Refactorizar CoreCLR para fusionar todos sus archivos en uno (incluido nativo + administrado) no es un trabajo trivial y no creo que el escenario sea tan interesante para muchos clientes.

La diferencia es que se garantiza que todas las máquinas con Windows tienen .NET Framework pero no .NET Core, por lo que, a menos que haya una razón especial por la que valga la pena hacer la implementación más compleja, supongo que terminaré quedándome allí.
Supongo que los clientes no suelen escribir utilidades ejecutables individuales. Tal vez algun dia. :-)

a menos que haya una razón especial por la que valga la pena hacer que la implementación sea más compleja

Hay MUCHAS razones para preferir .NET Core sobre .NET Framework. Rendimiento, modularidad, facilidad de servicio, aislamiento, etc. Y eso es ignorar la multiplataforma.

Tener una sola utilidad exe es principalmente una preocupación estética. No hay una diferencia funcional real (para todos los involucrados) si el ejecutable es un solo archivo o una sola carpeta con un puñado de archivos en él.

@mellinoe Oh, estoy de acuerdo con los proyectos en general, eso es cierto. En las pequeñas utilidades donde este cosmético es deseable, .NET Framework hasta ahora ha hecho un buen trabajo. Estoy de acuerdo en que es cosmético en el mismo sentido en que puede especificar una empresa de montaje y un mensaje de copyright. Pero ser algo cosmético no hace que me guste menos. Obviamente, no es una prioridad aquí, eso es bastante comprensible.

Posiblemente relacionado: https://github.com/dotnet/core/issues/600

No es principalmente cosmético. Imagina que quiero distribuir una aplicación que tiene varios componentes incrustados en su interior, como por ejemplo Idsrv4 o RavenDb + mis propias cosas. Toman una dependencia de los bits del núcleo de aspnet. Todo esto funciona bien siempre que dependan de la misma versión de aspnet core. Tan pronto como uno de ellos avance a la siguiente versión, probablemente ya no funcionará. Si OTOH pudiera fusionar cada componente en un solo .dll, el problema desaparece.

Una cosa a tener en cuenta es que hay más problemas técnicos además de que ILMerge no funciona. El tiempo de ejecución en sí mismo se divide fundamentalmente en muchos archivos, y también hay archivos auxiliares como el host CLR, el archivo de texto de dependencias del tiempo de ejecución y más. La única razón por la que un ejecutable de un solo archivo ha funcionado en el pasado es porque se confiaba en .NET Framework, una instalación global de todo el sistema. Comparar los dos escenarios es un poco injusto, porque .NET Framework realmente no tiene una opción "autónoma".

Todo esto funciona bien siempre que dependan de la misma versión de aspnet core. Tan pronto como uno de ellos avance a la siguiente versión, probablemente ya no funcionará.

Esto no es realmente cierto. Puede publicar varias aplicaciones diferentes en diferentes versiones de tiempo de ejecución y luego agruparlas en la misma "uber-app". Simplemente no puede mezclar sus dependencias en una sola carpeta. Incluso si usa la opción de publicación dependiente del marco, aún puede mezclar y combinar versiones. Entiendo que esto es menos conveniente que tener literalmente un solo archivo, y podría evitar cosas como incrustar un archivo ejecutable como recurso en el PE. Sin embargo, no estoy seguro de si eso es a lo que te refieres, ya que probablemente aún necesites extraer el archivo para ejecutarlo, lo que aún podrías hacer con un directorio.

No quise decir la versión en tiempo de ejecución, sé que no va a funcionar. Lo que quiero decir es lo que sucede en mi escenario cuando cada componente depende de [email protected]. El componente a luego se actualiza a [email protected]. Normalmente eso está bien, pero en esta hipótesis, los autores de LibXYZ no saben / no se preocupan por el control de versiones semántico. Ilmerge hizo que este problema desapareciera.

Además del punto pertinente de @thefringeninja , sugeriría que una sola unidad binaria desplegable reduce la sobrecarga de operaciones. Reduce la probabilidad de que algo salga mal con una implementación, reduce la carga de apreciar cognitivamente lo que ha enviado y reduce la configuración de las herramientas de operaciones, ya sea en scripts o en el estado deseado.

Aprecio que la herramienta dotnet es incipiente y acaba de llegar a 2.0, pero en comparación con alternativas como golang, esta función falta. Considere agregarlo a la hoja de ruta.

Como desarrollador de lib, agradecería tener ILMerge nuevamente en Core. 👍

Dotnet.exe es un solo archivo. NuGet.exe es un solo archivo. Creo que los cosméticos son importantes, y un archivo ejecutable de un solo archivo grita simplicidad de una manera que una carpeta con 100 archivos no lo hace. Sería genial encontrar una manera de lograr esto con dotnetcore

Supuse que esto era posible, y después de varias semanas de trabajo, vine a publicar la herramienta de consola CLI en un solo .exe ... ummm parece que en este momento no puedo obtener un solo * .exe
Pensé que ese era el objetivo de las aplicaciones centrales autónomas.

@PRIMETSS

Pensé que ese era el objetivo de las aplicaciones centrales autónomas.

El punto de las aplicaciones autónomas es que son autónomas, es decir, no requieren que .Net Core esté instalado en la máquina de destino, porque la aplicación en sí contiene todo lo que necesita para ejecutarse.

Para implementar una aplicación de este tipo, debe copiar un directorio completo de archivos. Tener un solo archivo facilitaría la implementación, pero eso es todo, sigue siendo una aplicación autónoma incluso sin eso.

Para aplicaciones grandes y similares a servicios, esto puede no ser tan importante, pero es esencial que las herramientas de línea de comandos y las aplicaciones pequeñas sean lo más simples posible y fáciles de implementar con COPIA.

Regularmente escribo herramientas de línea de comandos en .NET y tenerlas como 1 EXE hace que las actualizaciones / implementaciones / empaquetado sean MUCHO más simples. Siempre empaqueto todos los archivos .config y otros archivos requeridos dentro de EXE.

Piense en ese único EXE como un mini contenedor. Casi todos los beneficios de las implementaciones basadas en contenedores se aplican aquí.

Esto es simplemente horrible, me pregunto por qué se aprobó durante el proceso de diseño, quiero distribuir su aplicación a uno de sus clientes, luego le deseo buena suerte para encontrar qué abrir:
image

Esto es feo y un completo desastre

tiempo de ejecución /
MyProgram.exe
MyLib.dll

Esta hubiera sido una idea mucho mejor

Incluso Java lo maneja mejor:
explorer_2018-04-21_16-42-33

Sí, estaba pensando en la misma línea, ya que las aplicaciones autónomas deben tener los archivos de tiempo de ejecución incluidos (¡obviamente!) (Y no tenemos una forma de fusionarlos), entonces también pensé que solo una separación de carpetas sería ser más ordenado, y sí, también creo que los archivos de tiempo de ejecución deben almacenarse en una carpeta de tiempo de ejecución, por lo que cualquiera que intente usar una herramienta de línea de comandos escrita en el núcleo, al menos lo encontrará un poco más intuitivo en cuanto a qué ejecutar.

@Scellow @PRIMETSS Tengo que estar de acuerdo

¿Cómo es esto aún un problema? La demanda está por las nubes para esto.

sí, a esta carpeta separada con la adición de comprimirla en un contenedor y tener dos archivos, el exe y el contenedor. Fácil distribución.

Otro +1 para reabrir y tener como característica.

Esperaba que la implementación autónoma fuera autónoma y encontré mi camino aquí. También me gustaría que esto sucediera.

¿Cómo puede alguien decir que esto es solo una cuestión estética? (Solo desarrolladores de Framework ...)
¿Nadie pensó en herramientas que no están instaladas? (.NET resolvió dll-hell y .net core lo devuelve)

Solo quiero que mi herramienta de línea de comandos sea autónoma.

¡Esto es malo, realmente malo!

+1

+1 Acabo de intentar ejecutar una actividad personalizada en Azure Batch en un clúster sin .net core runtime y no puede manejar la gran cantidad de archivos que crea la versión "autónoma".

Total size of resourceFiles cannot be more than 32768 characters

Esta no es una solución oficial, pero podría ser útil. Soy el autor de warp, una herramienta que le permite crear aplicaciones binarias individuales autónomas: https://github.com/dgiagio/warp

¡Creo que warp es básicamente lo que todo el mundo está buscando aquí! Se trata solo de la capacidad de tener un solo archivo exe, lo que sea que esté en segundo plano, nada más. Piense en los paquetes NuGet: es un solo archivo .nuget y eso es todo; no es algo más complejo que un archivo que empaqueta otros archivos.

warp es una solución hacky, esto no es lo que queremos

Lo que queremos es:

dotnet publish --self-contained -c Release -r win10-x64

Y produce:

App.exe
runtime/

O mejor como GO / Rust, etc.

App.exe

Todo lo demás no es querido

Warp produce un App.exe ... ¿Cómo es hacky? Obviamente, no es parte del marco, pero logra el objetivo de "un archivo exe".

Esto es lo que quiero decir, debería ser un comportamiento predeterminado, no usar una solución de terceros (creo)

Warp funciona de maravilla. ¡Gracias por tu trabajo @dgiagio!

+1

Me gustaría mucho ver algún tipo de archivo de archivo único que agrupe el ejecutable y todas las dependencias. No tiene que incluir los nativos; creo que está perfectamente bien requerir que dotnet core esté instalado en el sistema. Algo muy similar a los archivos jar de Java. ¿Un archivo dar?

Algo como:
dotnet publish: autónomo
dotnet ejecutar - MyApp.dar autónomo

Parece que hay una propuesta para esto ahora: https://github.com/dotnet/designs/pull/52/files?short_path=28dba55

Aquí está el problema de seguimiento: https://github.com/dotnet/coreclr/issues/20287

Además, @shanselman tiene una publicación de blog sobre la solución Warp:

https://www.hanselman.com/blog/BrainstormingCreatingASmallSingleSelfcontainedExecutableOutOfANETCoreApplication.aspx

Leí la propuesta y vi esto:

image

Eso no es lo que tenía en mente, esto suena como un proceso lento, básicamente simplemente comprimir todo ...
¿Pensé que todo el código se fusionaría en un solo ejecutable / dll? ¿O tal vez me perdí algo en la propuesta?

@RUSshy ¿Está preguntando acerca de la compilación nativa de todo el código administrado y la vinculación de todo para obtener un ejecutable (como en CoreRT)? Este no es un objetivo para el trabajo actual de un solo archivo en .Net Core.

Sin embargo, existen soluciones propuestas para reducir la extracción de disco y el tiempo de inicio (por ejemplo: cargar ciertos tipos de archivos directamente desde el paquete , reutilizar archivos extraídos ). Las etapas de desarrollo de la solución de archivo único se describen aquí .

CC: @jeffschwMSFT

¿Por qué es necesario extraer los archivos? Solíamos salirse con la nuestra en .NET con ILMerge.

@ phillip-haydon, como se describe aquí , ILMerge y las soluciones de un solo archivo logran diferentes objetivos.

ILMerge combina el IL de muchos ensamblados en uno, pero en el proceso, pierde la identidad original de los ensamblados combinados. Por lo tanto, fallarán cosas como el uso de la reflexión basada en nombres de ensamblados originales. Las aplicaciones aún pueden usar ILMerge si pueden tolerar este cambio.

CoreRT es otra cosa, compilación AOT de su código .NET, parece interesante, pero aún no está listo (desearía que MS se concentrara en ello y asignara más recursos ... esto es exactamente lo que la gente quiere y por qué se mudaron a GO )

De todos modos, no tengo conocimientos técnicos para hablar sobre los detalles, pero el caso de uso es:

Publique un solo ejecutable autónomo, y solo eso, nada comprimido, nada extraído, sin gastos generales, solo el ejecutable

@ swaroop-sridhar, ¿tiene un ejemplo de esto que funcione para dotnet core en linux? de acuerdo con https://github.com/dotnet/ILMerge/blob/master/ILMerge/ILMerge.csproj#L13 este es un proyecto solo para windows / mono.

@thefringeninja ILMerge es una herramienta de Windows, no conozco ningún plan para portar ILMerge a otras plataformas.
La solución de archivo único se implementará en varias plataformas. Esto está en proceso de desarrollo.

@karelz @mellinoe
Implementar Implementar Implementar!si es único o menos como 1-3 archivos, eso será mejor para Implementar (Incluir Publicar, Actualizar).

CoreRT es AOT
pero la gente quiere AOT?
el proyecto (CoreRT) siempre no es fácil de usar (es de 2014). ¡Ahora es 2019! ( Aproximadamente 5 años )
¡Qué preciosos 5 años para un lenguaje de pragram!el CoreRT ni siquiera plan para el próximo lanzamiento !!!dejar que las personas esperen más otros 5 años?

@ swaroop-sridhar Eso es lamentable. ILMerge / ILRepack es ideal para que los desarrolladores de bibliotecas eviten el problema de la dependencia del diamante.

Hay planes para admitirlo en .NET Core 3.0:
Se ha mencionado en las publicaciones del blog .NET Core 3.0, por ejemplo, aquí: https://devblogs.microsoft.com/dotnet/net-core-3-and-support-for-windows-desktop-applications/ en "Side-by- lateral y de implementación local de aplicaciones ".
Lea también: https://www.hanselman.com/blog/BrainstormingCreatingASmallSingleSelfcontainedExecutableOutOfANETCoreApplication.aspx

.net no debería necesitar todos estos trucos para producir un pequeño ejecutable autónomo ... debería ser el comportamiento predeterminado, GO te devora vivo, Rust también viene, céntrate en CoreRT o ILMerge, las aplicaciones principales de .net ya también lo son largo para comenzar debido a todos los archivos para cargar, no agregue más escuchado a esto con zip / unzip como se menciona en la propuesta, este no es el camino a seguir

.net no debería necesitar todos estos trucos para producir un pequeño ejecutable autónomo ... debería ser el comportamiento predeterminado, GO te devora vivo, Rust también viene, céntrate en CoreRT o ILMerge, las aplicaciones principales de .net ya también lo son largo para comenzar debido a todos los archivos para cargar, no agregue más escuchado a esto con zip / unzip como se menciona en la propuesta, este no es el camino a seguir

Como quieras .net no debería necesitar estar vivo, porque ppl tiene java.
go o rust o dlang no deberían admitir el destino de compilación para un programa ejecutable único, porque tienen el Fuck Zip / Unzip!

@RUSshy

.net no debería necesitar todos estos trucos para producir un pequeño ejecutable autónomo

Convenido. Al mismo tiempo, .NET proporciona ciertas características sobre otros lenguajes que son difíciles de reconciliar con los requisitos de un enlazador estático (por ejemplo, generación de código sobre la marcha, reflexión, enlace de datos, etc.). Hemos experimentado con la exclusión de estas características en escenarios donde el enlace estático / de archivo único es importante. Hemos aprendido de los comentarios de los clientes que el resultado de esto ya no se siente como .NET, en parte porque la cantidad de bibliotecas que puede consumir del ecosistema cae drásticamente.

Entonces, hacer un enlazador correctamente que no comprometa la fidelidad de las características de las que todos hemos tomado una dependencia y amamos en .NET, es un problema difícil. Como parte de la solución de esto, estamos experimentando con varios enfoques. A esto lo llamas trucos, yo lo llamo de mente abierta y dispuesto a pensar fuera de la caja. Pero convertir ciegamente .NET en Go / Rust / C ++ no es la respuesta correcta.

Hemos experimentado con la exclusión de estas características en escenarios donde el enlace estático / de archivo único es importante. Hemos aprendido de los comentarios de los clientes que el resultado de esto ya no se siente como .NET, en parte porque la cantidad de bibliotecas que puede consumir del ecosistema cae drásticamente.

¿Ha pensado el equipo en crear una versión separada de .net centrada en el desarrollo nativo y entornos restringidos, como hicieron los jetbrains con kotlin JVM / kotlin NATIVE?

Como dijiste, tratar de que .net se adapte a todos los casos de uso no es la opción más inteligente, por lo que un sabor específico podría ser la respuesta correcta a este problema.

Y tbh, afaik, este problema realmente no existía antes de .net core ya que cada instalación de Windows ya tenía .net framework, por lo que solo tuvo que distribuir sus pocos KBs exe, y lo que me molesta es que nadie parece haber pensado en este tipo de problema al diseñar .net core, que fue básicamente una reescritura de .net framework ... es por eso que digo que estas opciones mencionadas son simples trucos, están aquí para corregir errores de diseño

Después de leer https://github.com/dotnet/designs/blob/master/accepted/single-file/staging.md , parece que hay más pasos para la propuesta, y no termina en zip / unzip, por lo que no una pelea perdida, ojalá el equipo pueda venir con algo más ligero, que se menciona en ese documento, ¡bien!

Cosas como esta son la razón por la que Windows sigue siendo un sistema operativo de juguete.

@kjkrum ¿ Cosas como qué?

@cryru es lo que dice la gente cuando no sabe lo que hace.

@Cryru Cosas como no poder construir un ejecutable independiente y el olvido inconsciente de la necesidad real de hacerlo. Casi todos los demás sistemas de compilación existentes no solo compilarán un ejecutable vinculado estáticamente, sino que eliminarán las partes no utilizadas de las dependencias. La eliminación de dependencias ha sido una característica estándar durante al menos una década; enlace estático desde la invención de los cumplidores.

@Cryru Cosas como no poder construir un ejecutable independiente y el olvido inconsciente de la necesidad real de hacerlo. Casi todos los demás sistemas de compilación existentes no solo compilarán un ejecutable vinculado estáticamente, sino que eliminarán las partes no utilizadas de las dependencias. La eliminación de dependencias ha sido una característica estándar durante al menos una década; enlace estático desde la invención de los cumplidores.

De acuerdo, esto en realidad está relacionado con la posición de los programas C # en el sistema operativo.
Los programas de C # siempre no pueden convertirse en ciudadanos de primera clase.Solo para ser de segunda clase.

Esto está resuelto.
TLDR: dotnet publish -r win10-x64 /p:PublishSingleFile=true

Detalles:
https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#single -file-ejecutables
https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md

Esto está resuelto.
TLDR: dotnet publish -r win10-x64 /p:PublishSingleFile=true

Detalles:
https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#single -file-ejecutables
https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md

¿En qué versión de dotnet-core se agregó esta función? Estoy usando 3.0.100-preview5-011568 y recibí este error:
error MSB4030: "/p:PublishSingleFile=true" is an invalid value for the "SelfContained" parameter of the "ResolveFrameworkReferences" task. The "SelfContained" parameter is of type "System.Boolean".

LE: En realidad está funcionando, parece que solo hay un error de sintaxis en https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md que dice publicar con dotnet publish -r win10-x64 --self-contained /p:PublishSingleFile=true y en realidad es sin agregar --self-contained .

Gracias @mihaimyh . Corregiré el error tipográfico en el documento de diseño.

Siempre estoy en contra del uso de la solución zip / unzip para la función autónoma de un solo exe .
porque esto provocará el siguiente problema.
¡Cómo reducir el tamaño del archivo exe único!

De hecho, desde el principio conviene utilizar IL-Merge de formas similares.

No debería haber un debate, esto es una pérdida de tiempo, nadie pidió comprimir / descomprimir todo, y sin embargo, vinieron con este diseño y perdieron su tiempo y el nuestro.

La gente pide un ejecutable único y AOT, deje de perder nuestro tiempo Microsoft

Quiero explícitamente un solo archivo sin AOT. Prefiero la capacidad de JIT para poder usar código de reflexión, genéricos y generado en tiempo de ejecución.

Supongo que MS no quiere escuchar, ok

Siempre estoy en contra del uso de la solución zip / unzip para la función autónoma de un solo exe .
porque esto provocará el siguiente problema.
¡Cómo reducir el tamaño del archivo exe único!

No estoy seguro de entender, como si estuviera comprimido, ya estuviera comprimido. ¿O se refiere a la reducción de dependencias redundantes y, por lo tanto, a un tamaño reducido antes de la compresión?

No entender la negatividad. Todavía no lo he usado más que una prueba rápida. Pero parece que el ejecutable único funciona bien para la situación de implementación de una aplicación en un cliente o como herramienta CLI. Que es donde creo que esta característica es útil. Fuera de eso, en Dev u otro entorno no veo un caso de uso para ello, por lo que lo que han hecho funciona bien como solución por ahora.

@RUSshy

Supongo que MS no quiere escuchar, ok

Por el contrario, están solicitando y recopilando una amplia gama de casos de uso que puede ver en los hilos relacionados. Tu opinión es importante, pero las opiniones de otros miembros de la comunidad son igualmente importantes y no debes burlarte de Microsoft por escucharlas.

Basado en su declaración, creo que podría haberme confundido con Microsoft. Solo soy un miembro de la comunidad como usted que no habla en nombre de Microsoft de ninguna manera.

Siempre estoy en contra del uso de la solución zip / unzip para la función autónoma de un solo exe .
porque esto provocará el siguiente problema.
¡Cómo reducir el tamaño del archivo exe único!

No estoy seguro de entender, como si estuviera comprimido, ya estuviera comprimido. ¿O se refiere a la reducción de dependencias redundantes y, por lo tanto, a un tamaño reducido antes de la compresión?

si usa WebApi o MVC o ConsoleApp, escriba un HelloWorld! Tu bien sabes lo que quiero decir.
el archivo empaquetado es demasiado grande, trae demasiado código pero nunca se ejecutará.
si las formas IL-Merge reducirán la rama de código no utilizada.

Sí, claro, hice una consola HelloWorld y sí, seguro que es 68K
Capture
El ninguno autónomo fue 67K
Pero es C # no ensamblaje. Si quisiera un HelloWorld <1K, ¿por qué usar c #?
Las aplicaciones más grandes usan más del marco, por lo que en un momento su código más personalizado que el marco.
¿Estamos realmente preocupados por unos 100K? Si es así, no use un framework y pase el tiempo escribiendo todo desde cero.
¿Que me estoy perdiendo aqui?

Siempre estoy en contra del uso de la solución zip / unzip para la función autónoma de un solo exe .
porque esto provocará el siguiente problema.
¡Cómo reducir el tamaño del archivo exe único!
si usa WebApi o MVC o ConsoleApp, escriba un HelloWorld! Tu bien sabes lo que quiero decir.
el archivo empaquetado es demasiado grande, trae demasiado código pero nunca se ejecutará.
si las formas IL-Merge reducirán la rama de código no utilizada.

@sgf, hay dos problemas algo separados aquí:

  • ¿Cómo reducir el código de una aplicación?
  • ¿Cómo empaquetar la aplicación en un solo archivo?

Para la reducción de código, existen varias técnicas adicionales

  • Fusionar IL: esto no es para todas las aplicaciones, porque pierde la identidad del ensamblado en el proceso. Este no es un objetivo para el trabajo actual de un solo ejecutivo.
  • Recorte de IL no utilizado: ILLinker tiene PublishTrimmed ) y se están desarrollando más optimizaciones en ILLinker.
  • Comprimir / Descomprimir: dotnet publish no comprime actualmente el archivo único publicado, pero se puede hacer.

¿Cómo empaquetar la aplicación en un solo archivo?
dotnet publish admite la publicación en un solo archivo: el archivo publicado será tan grande como lo sería la aplicación.

Respecto a la generación de código nativo:

  • Actualmente, el soporte para generar código nativo es a través del compilador listo para ejecutar (propiedad PublishReadyToRun ).
  • La publicación a través de la compilación AOT es excelente ( CoreRT ), pero aún no está disponible. Con la compilación AOT también, el tamaño del ejecutable depende de las opciones de compilación: ej .: ¿incluimos el jit para ejecutar el código generado, etc.?

Sí, claro, hice una consola HelloWorld y sí, seguro que es 68K
Capture
El ninguno autónomo fue 67K
Pero es C # no ensamblaje. Si quisiera un HelloWorld <1K, ¿por qué usar c #?
Las aplicaciones más grandes usan más del marco, por lo que en un momento su código más personalizado que el marco.
¿Estamos realmente preocupados por unos 100K? Si es así, no use un framework y pase el tiempo escribiendo todo desde cero.
¿Que me estoy perdiendo aqui?

lo siento como se muestra su img, con autocontenido. Eso es 68626KB, son aproximadamente 68mb = 68KK, no solo 68K !!!
no necesitaremos <1kb (con autocontrol, eso es imposible), <3000KB está bien, acepta.
Pero 68mb es más 30X +
¡¡¡No siempre escribirás un programa HelloWorld !!!

Disculpas, error a altas horas de la noche con los K
Gracias por la explicación / información agregada swaroop-sridhar, no tenía conocimiento de algunos cambios nuevos allí.
Probé con 3.preview 6 con los siguientes interruptores

dotnet publish -r RID / p: PublishTrimmed = true / p: PublishSingleFile = true
y ahora hasta 29,000K

Seguro que no todas las aplicaciones serán Hello World, pero para una aplicación C # Core SelfContained, que también contiene el tiempo de ejecución ... Personalmente, no estoy preocupado. Seguro que entiendo que si estás escribiendo una pequeña herramienta de consola, sería bueno tenerla en 3K. Pero, ¿por qué usar C # para eso en primer lugar?
¡Interesante discusión, chicos!

image
Capture

30mb LOL, llámame cuando sea algo así como 1-3mb, el tiempo de ejecución está lleno de hinchazón, marca GO, la gente migra en oleada

https://www.jetbrains.com/lp/devecosystem-2019/

Incluso kotlin comienza a ganar acciones, y con kotlin native puso c # en vergüenza

Y Swift llegará a Windows https://forums.swift.org/t/swift-win32-programming/20686

Así que aquí algunas sugerencias:

  • Agregar opción para eliminar Reflection
  • Agregar opción para eliminar cosas JIT
  • Optimice mejor el código C # para que no confíe en JIT

30mb LOL, llámame cuando sea algo así como 1-3mb, el tiempo de ejecución está lleno de hinchazón, marca GO, la gente migra en oleada

https://www.jetbrains.com/lp/devecosystem-2019/

Incluso kotlin comienza a ganar acciones, y con kotlin native puso c # en vergüenza

Y Swift llegará a Windows https://forums.swift.org/t/swift-win32-programming/20686

Así que aquí algunas sugerencias:

  • Agregar opción para eliminar Reflection
  • Agregar opción para eliminar cosas JIT
  • Optimice mejor el código C # para que no confíe en JIT

Creo que esto no es justo. .NET no se diseñó para crear las aplicaciones de consola de un solo archivo más pequeñas. Lo usamos para sitios web y apis Asp.Net. Por lo tanto, el marco en sí trae una tonelada de características además de toneladas de paquetes nuget que puede incluir. No puedo imaginar que exista una preocupación si una aplicación web tiene 50 o varios cientos de megabytes de tamaño. La principal preocupación es la velocidad, el uso de la memoria y la capacidad de mantenimiento a largo plazo. A quién le importa el tamaño del servidor.

Si su única intención es crear una aplicación de consola de tamaño pequeño de un solo mb, ¿por qué no utilizar la herramienta adecuada para el trabajo? En lugar de quejarse de que una aplicación con un marco de funciones completo empaquetado en un solo archivo tiene un tamaño de varias decenas de megabytes, incluso para un "mundo hola", ¿por qué no optar por Rust, por ejemplo?

Microsoft está haciendo un gran trabajo con .NET desde sus inicios e incluso más en los últimos años, así que gracias por eso.

¿Qué responder a tales tonterías, mentiras y falta de sentido de la eficiencia?

No se da cuenta de lo incorrecta que era la dirección central de .net, y solo recientemente comenzaron a darse cuenta trabajando en Distribución / Combinación de IL / AOT

Y ahora, para avanzar en el vagón de ensamblaje web, no pueden porque .net runtime es una hinchazón tan ENORME que no pueden implementar archivos de tamaño decente

Y todavía te quedas con "¿A quién le importa el tamaño del servidor?", Esta forma de pensar es lo que convirtió el núcleo .net "supuestamente moderno" en una pila tecnológica ya obsoleta e irrelevante.

Microsoft no está haciendo un gran trabajo con .net, fallaron porque querían complacer a las personas mayores por la compatibilidad con .net framework, fue uno de sus errores

Lo siento si sueno grosero, pero a veces tienes que serlo para hacer cambios

Lo siento si sueno grosero pero

Suenas grosero, punto. Eso, y sus despidos y conclusiones precipitadas, no tienen el efecto de ser persuasivo.

Disculpas, error a altas horas de la noche con los K
Gracias por la explicación / información agregada swaroop-sridhar, no tenía conocimiento de algunos cambios nuevos allí.
Probé con 3.preview 6 con los siguientes interruptores

dotnet publish -r RID / p: PublishTrimmed = true / p: PublishSingleFile = true
y ahora hasta 29,000K

Seguro que no todas las aplicaciones serán Hello World, pero para una aplicación C # Core SelfContained, que también contiene el tiempo de ejecución ... Personalmente, no estoy preocupado. Seguro que entiendo que si estás escribiendo una pequeña herramienta de consola, sería bueno tenerla en 3K. Pero, ¿por qué usar C # para eso en primer lugar?
¡Interesante discusión, chicos!

image
Capture

¿No debería, como un lenguaje moderno, tener un poco de ambición por unificar el mundo?
¿Quiere que todos los desarrolladores escriban c # en casa para C ++? o empujarlos a ir, Kotlin, Swift?
Cuota de mercado y erosionar aún más c #?

.Net porque no implementa multiplataforma perdió los primeros 15+ años de la gran oportunidad de desarrollo.
Pero ahora .net ha vuelto al camino correcto.

Sí, como comenté antes, no estoy seguro de por qué la negatividad.
.Net Core no ha sido más que fantástico si viene de Full Framework. Y la visión de fusión de .Net Standard + Core creo que es sensata y progresiva.

Comparar .NET con GO o cualquier otro lenguaje / marco no tiene sentido.
De todos modos, estoy FUERA de este tema, ya que creo que la solución en la que están trabajando y mejorando para Single .exe ha resuelto bastante bien mi 'pregunta' de hace varios años ... Lo suficientemente bueno para mí y se adapta a mis necesidades inmediatas.

¡Así que gracias Guys & Gals!

AFUERA

Me gustaría recordarles a todos en este hilo sobre el Código de Conducta .

Está bien no estar de acuerdo o tener una opinión diferente, pero por favor, seamos civilizados y expresemos eso como una discusión técnica. No es necesario usar palabras fuertes.
Además, enfocar ideas, implementaciones con sus opiniones es un juego justo. SIN EMBARGO, NO ES ACEPTABLE atacar a PERSONAS detrás de ellos. Por favor, seamos respetuosos entre nosotros, escuchemos opiniones diferentes y evitemos declaraciones contundentes y comentarios ofensivos.

Además, me gustaría pedirles a todos que estén abiertos a otros puntos de vista y opiniones. Antes de emitir juicios, generalmente es bueno escuchar a la otra parte; a menudo hay una historia detrás de por qué las cosas son como son. Buscar ideas y soluciones cuando uno sabe por qué son como son suele ser más productivo.

¡Gracias!

Siempre estoy en contra del uso de la solución zip / unzip para la función autónoma de un solo exe .
porque esto provocará el siguiente problema.
¡Cómo reducir el tamaño del archivo exe único!
si usa WebApi o MVC o ConsoleApp, escriba un HelloWorld! Tu bien sabes lo que quiero decir.
el archivo empaquetado es demasiado grande, trae demasiado código pero nunca se ejecutará.
si las formas IL-Merge reducirán la rama de código no utilizada.

@sgf, hay dos problemas algo separados aquí:

  • ¿Cómo reducir el código de una aplicación?
  • ¿Cómo empaquetar la aplicación en un solo archivo?

Para la reducción de código, existen varias técnicas adicionales

  • Fusionar IL: esto no es para todas las aplicaciones, porque pierde la identidad del ensamblado en el proceso. Este no es un objetivo para el trabajo actual de un solo ejecutivo.
  • Recorte de IL no utilizado: ILLinker tiene PublishTrimmed ) y se están desarrollando más optimizaciones en ILLinker.
  • Comprimir / Descomprimir: dotnet publish no comprime actualmente el archivo único publicado, pero se puede hacer.

¿Cómo empaquetar la aplicación en un solo archivo?
dotnet publish admite la publicación en un solo archivo: el archivo publicado será tan grande como lo sería la aplicación.

Respecto a la generación de código nativo:

  • Actualmente, el soporte para generar código nativo es a través del compilador listo para ejecutar (propiedad PublishReadyToRun ).
  • La publicación a través de la compilación AOT es excelente ( CoreRT ), pero aún no está disponible. Con la compilación AOT también, el tamaño del ejecutable depende de las opciones de compilación: ej .: ¿incluimos el jit para ejecutar el código generado, etc.?

Según sea necesario, combine dinámicamente las DLL nativas con un nombre como: XXX.exe (UnManaged).
Uso de análisis estático para el análisis al compilar el enlace de nivel de función de NativeDLL (no administrado).

api-ms-win-core-console-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll
api-ms-win-core-file-l1-1-0.dll
api-ms-win-core-file-l1-2-0.dll
api-ms-win-core-file-l2-1-0.dll
api-ms-win-core-handle-l1-1-0.dll
api-ms-win-core-heap-l1-1-0.dll
api-ms-win-core-interlocked-l1-1-0.dll
api-ms-win-core-libraryloader-l1-1-0.dll
api-ms-win-core-localization-l1-2-0.dll
api-ms-win-core-memory-l1-1-0.dll
api-ms-win-core-namedpipe-l1-1-0.dll
api-ms-win-core-processenvironment-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-1.dll
api-ms-win-core-profile-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-1-0.dll
api-ms-win-core-synch-l1-2-0.dll
api-ms-win-core-sysinfo-l1-1-0.dll
api-ms-win-core-timezone-l1-1-0.dll
api-ms-win-core-util-l1-1-0.dll
api-ms-win-crt-conio-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-multibyte-l1-1-0.dll
api-ms-win-crt-private-l1-1-0.dll
api-ms-win-crt-process-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
aspnetcorev2_inprocess.dll
clrcompression.dll
clretwrc.dll
clrjit.dll
coreclr.dll
dbgshim.dll
dotnet-aspnet-codegenerator-design.dll
hostfxr.dll
hostpolicy.dll
mscordaccore_amd64_amd64_4.6.27317.07.dll
mscordbi.dll
mscorrc.dll
mscorrc.debug.dll
sni.dll
sos.dll
sos_amd64_amd64_4.6.27317.07.dll
ucrtbase.dll
...etc...

si hace un buen trabajo, el resultado puede ser entre 2 y 3 mb. cuando estoy directamente empacado todos ellos con 7zip, toma alrededor de 4.85mb. Ahora obtenemos XXX.exe

Desarrolle el enlace de nivel de función similar con IL-merge.
Para una DLL administrada, el mismo truco de siempre.
Por último, incruste la DLL administrada como secciones PE.exe (marque como sección .net).

Para reflexionar, DLL de análisis del tipo reflexión. Conserve los metadatos y el tipo de reflexión (incluida la función) y todo su árbol - dependiente.

Pido disculpas, ya no quiero tomarme más tiempo para participar en la discusión sobre esto. Las opiniones no se pueden unificar.
Al principio esperaba el resultado. Pero ahora, probablemente debería considerar otros lenguajes de programación para satisfacer mis necesidades (tal vez Dlang tal vez Go tal vez Kotlin tal vez Nim o tal vez Rust sea ​​el mejor).

gracias por todos, habla de esto conmigo. perdón por mi regaño. afuera

@sgf Creo que hiciste algunos buenos puntos y sé que has firmado el tema. Solo quería decir que creo que las características que está solicitando llegarán en los próximos años a .NET Core. De hecho, si desea obtener un tamaño de archivo pequeño hoy, puede ser posible si apunta a mono.

  1. Mono ya es compatible con la compilación AOT con Linking para reducir el tamaño del archivo. Esta es una de las razones por las que se eligió mono para la implementación del tiempo de ejecución .net del navegador. https://www.mono-project.com/docs/advanced/aot/ y supongo que es por eso que los proyectos Blazor pueden tener un vinculador.

  2. Microsoft ha declarado que quiere unir sus tiempos de ejecución .NET en uno "todopoderoso". En lugar de tener mono para algunas cosas y .NET Core para otras, quieren un tiempo de ejecución único que pueda funcionar en todos los escenarios. Esto defacto significa que deberá admitir AOT y Linking / Code stripping, etc. Por lo tanto, espero que en los próximos años, el tiempo de ejecución de .NET Core obtenga estas características, o que las características de Mono y .NET Core se consoliden en una nueva Tiempo de ejecución.

Si alguien lo sabe mejor, por favor infórmeme.

+ 2 ¢

Creo que el problema es que parece que las decisiones se toman sin mucha información. En estos días, dondequiera que mire, la gente está hablando de esto; la gran mayoría de las personas que implementan programas tienen esto en la parte superior de su lista de deseos, y muchos se están moviendo de C # a otros lenguajes con mejor AOT / implementabilidad. Creo que es un hecho bastante establecido que se vuelve muy evidente si eres activo en la comunidad. Sin embargo, no parece afectar las decisiones en lo más mínimo.

La cuestión es que parece que nadie sabe exactamente hasta qué punto esto es importante. Para mí, personalmente, es extremadamente importante, así que, por supuesto, soy muy parcial, pero la impresión que tengo es que, en general, esto es de suma importancia y parece que la EM simplemente no le está prestando la atención que merece, lo que nos deja a muchos de nosotros con la impresión están tomando decisiones uniformadas, lo que a su vez no nos hace confiar en el futuro de la tecnología en su conjunto.

Estoy de acuerdo con @RUSshy. CoreRT es un proyecto increíble y definitivamente va en la dirección correcta, pero en general parece que todos los esfuerzos se centran en tecnologías de servidor / web. Cosas como tiempos de ejecución, jits y binarios grandes hablan por sí mismos en ese sentido. Nadie que implementa software quiere esas cosas.

Habiendo dicho eso, personalmente sigo usando la tecnología, aunque realmente no estoy conteniendo la respiración sobre su futuro en algunas áreas.

Me gustaría ver una mayor participación de la comunidad en la dirección que se está tomando, incluso si resulta que es lo contrario de lo que personalmente espero. Pero hasta ahora parece que se están tomando decisiones sin tener eso en cuenta. Parece que el servidor / web es lo que genera dinero y las personas que implementan programas son una minoría insignificante (al menos en términos de ganancias), pero si ese es el caso, al menos querría saber en eso se basan sus decisiones (que es muy probable), porque desde fuera parece que están lanzando una moneda al aire.

@ Alan-FGR

Pero hasta ahora parece que se están tomando decisiones sin tener eso en cuenta.

¿Tiene ejemplos específicos de tales decisiones para compartir, ya que me gustaría saber más?

Creo que MS es muy consciente de las deficiencias del tiempo de ejecución del núcleo de dotnet actual y es por eso que buscarán la paridad de características con el tiempo de ejecución mono en el futuro.

Solo mire las notas de la versión de .net core 3.0.0 preview 6:

Hoy, anunciamos .NET Core 3.0 Preview 6. Incluye actualizaciones para compilar ensamblados para un inicio mejorado, optimizando el tamaño de las aplicaciones con el vinculador y mejoras de EventPipe. También hemos lanzado nuevas imágenes de Docker para Alpine en ARM64.

Me parece que son muy conscientes de que el tamaño de la aplicación es importante para ciertos escenarios, especialmente ahora con Blazor en la mezcla.

@ Alan-FGR De acuerdo, el enfoque web es bastante extraño considerando que IIS tiene alrededor del 8% de participación de mercado y está cayendo. ASP.NET es irrelevante y ninguna mejora en C # o sus bibliotecas estándar va a cambiar eso. C # se sustenta en aplicaciones de consola, servicios de Windows, aplicaciones móviles y juegos de PC. Debe su existencia continua a Unity y Xamarin. Lo cual es una lástima, porque C # es un lenguaje realmente agradable para desarrollar. Es un gran elogio proveniente de un desarrollador de Java desde hace mucho tiempo que todavía piensa que Microsoft dejó su marca de agua con Windows XP.

Según sea necesario, combine dinámicamente las DLL nativas con un nombre como: XXX.exe (UnManaged).
Uso de análisis estático para el análisis al compilar el enlace de nivel de función de NativeDLL (no administrado).

No estoy seguro de lo que quiere decir con fusión dinámica, pero existe un plan para vincular estáticamente los componentes nativos junto con el host. Consulte esta sección .

Desarrolle el enlace de nivel de función similar con IL-merge.
Para reflexionar, DLL de análisis del tipo reflexión. Conserve los metadatos y el tipo de reflexión (incluida la función) y todo su árbol - dependiente.

Hemos discutido la opción de fusionar ensamblados en uno y tener tablas de metadatos laterales para admitir características dinámicas. Proporciona ahorros de tamaño considerables. Pero el costo de implementarlo es bastante alto, debido al nuevo soporte de metadatos y los cambios necesarios en los depuradores / perfiladores, etc. para manejarlo.

Hay algunas otras opciones para reducir el tamaño binario; por ejemplo, cuando podemos ejecutar un solo archivo directamente (sin tener que extraer a archivos), podemos colocar la firma / certificados en cada DLL a favor de firmando la aplicación en su totalidad. Esto puede ahorrar algunos MB a veces.

Pero hasta ahora parece que se están tomando decisiones sin tener eso en cuenta.

¿Tiene ejemplos específicos de tales decisiones para compartir, ya que me gustaría saber más?

Creo que MS es muy consciente de las deficiencias del tiempo de ejecución del núcleo de dotnet actual y es por eso que buscarán la paridad de características con el tiempo de ejecución mono en el futuro.

@dazinator Creo que el

De acuerdo, el enfoque web es bastante extraño considerando que IIS tiene alrededor del 8% de participación de mercado y está cayendo. ASP.NET es irrelevante y ninguna mejora en C # o sus bibliotecas estándar va a cambiar eso. C # se sustenta en aplicaciones de consola, servicios de Windows, aplicaciones móviles y juegos de PC.

@kjkrum ese es el punto. Sin embargo, tal vez para ellos el 8% de la cuota de mercado en la web sigue siendo mucho más importante que las aplicaciones de Windows y móviles. Los buenos técnicos web al menos ayudan a las ventas de servidores de Windows, por lo que su interés en eso es bastante obvio, pero centrarse tanto en eso también es una estrategia muy superficial y me niego a creer que eso es lo que impulsa sus decisiones. MS parecía ir en la dirección correcta con la base dotnet y tantos proyectos prometedores en marcha, pero parece que están dejando pasar la oportunidad de tener una tecnología dominante.

Sé que esto es anecdótico, por lo que probablemente carezca de sentido, pero todas las personas que conozco que estaban usando C # para sus proyectos (principalmente desarrolladores de juegos) pasaron a otra cosa debido a limitaciones que eran totalmente solucionables. Se mudaron a Rust, D, Go y C ++. Yo mismo uso C ++ de forma regular y estoy aprendiendo Rust, pero sigo usando C # para algunos proyectos personales porque es mucho mejor, aunque implementar un producto de calidad es un fastidio.

Debe su existencia continua a Unity y Xamarin.

Sí, qué es una bendición y una maldición debido a los muchos problemas técnicos. Unity, por ejemplo, tiene muy mala reputación, pero afortunadamente eso no pareció afectar a .NET / C #.
Sin embargo, XNA, aunque lejos de ser perfecto, tiene una reputación increíblemente buena entre usuarios y desarrolladores.

Feliz de ver esta tierra con .NET Core 3.0 hoy. ¡Gracias amigos! 👍

No estoy seguro de que eso sea lo que la gente quiere, si terminamos con una calculadora simple que es de 141 MB exe, entonces la función es una falla (y creo que el costo real es de 141 MB * 2, ya que extraerá cosas en algún lugar correcto)

image

Sí, definitivamente es lo que quiero. Sigue siendo más pequeño que una implementación autónoma normal.

Se agradecería una poda de montaje más agresiva y una sacudida de árboles, pero este es un comienzo muy útil. La mejora incremental es la forma más inteligente de generar valor.

Oh, esto es lo que quieres? mi mal, no sabía que la aplicación hinchada era popular

Una calculadora no necesita JIT, ni siquiera Reflexión, pero como eso es lo que quieres, supongo que me equivoqué desde el principio, debería dejar de programar

@RUSshy No está más hinchado que cualquier otra implementación autónoma, ¿verdad?

La eliminación de JIT y la reflexión es independiente de si todo está empaquetado en un solo archivo ejecutable. Es decir, puede eliminar JIT y la reflexión sin un solo exe, y puede tener un solo exe sin eliminar JIT y la reflexión. Son trabajos separados.

No estoy seguro de que eso sea lo que la gente quiere, si terminamos con una calculadora simple que es de 141 MB exe, entonces la función es una falla (y creo que el costo real es de 141 MB * 2, ya que extraerá cosas en algún lugar correcto)

es extraer los archivos en C: Users [YourUserName] AppDataLocalTemp.net

¿Hay alguna forma de anular dónde se desempacará el archivo exe único?
Me encontré con un problema cuando intenté extraer en / var / .... donde el usuario no tiene permisos para escribir.

@eiva ¿ qué sistema operativo era este? ¿Fue AWS lambda?
https://github.com/dotnet/core-setup/issues/7940 pistas que solucionan este problema.

Mientras tanto, puede configurar la variable de entorno DOTNET_BUNDLE_EXTRACT_BASE_DIR para controlar dónde se extraen los archivos empaquetados.

@ swaroop-sridhar ¡Gracias por la respuesta!
Es centos.7 lanzando la aplicación desde la cuenta de servicio "restringida".

@ jnm2 Aprecio que ames C #, yo también. Pero seamos honestos, es una locura que una calculadora tenga 128 megabytes.

@TechnikEmpire Siento que es necesario señalar que "Me encanta C #" es una reducción bastante intensiva de lo que dije anteriormente: D

Personalmente, no me sentiré completamente satisfecho hasta que tenga la capacidad de hacer temblar los árboles de mi propio código y bibliotecas, bibliotecas de terceros referenciadas y .NET en sí. Pero eso no hace que la función single-exe sea menos valiosa para mí hoy. Es un paso en una dimensión. Sacudir árboles es una dimensión independiente y espero que reciba mucha atención.

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

Temas relacionados

GitAntoinee picture GitAntoinee  ·  3Comentarios

nalywa picture nalywa  ·  3Comentarios

jzabroski picture jzabroski  ·  3Comentarios

omariom picture omariom  ·  3Comentarios

v0l picture v0l  ·  3Comentarios