
– SERIE PARA DESARROLLADORES DE WINE 01 –
Cuando se trata de Wine, la mayoría de los usuarios experimentados de Linux han oído hablar de él, pero cuando se les pide que expliquen exactamente qué es Wine, muchos pueden no ser capaces de articularlo con claridad. Este artículo proporcionará una introducción sencilla a cómo funciona Wine y cómo empezar a desarrollar con Wine. Por lo tanto, si usted pertenece a una de las siguientes tres categorías de lectores:
Esperemos que, tras leer este artículo, obtenga algunas ideas.
PARTE 1: ¿QUÉ ES WINE?
Wine es un acrónimo recursivo de «Wine Is Not an Emulator» (Wine no es un emulador), similar a «GNU» (GNU no es Unix). Esto significa que Wine no es un emulador en el sentido tradicional. En concreto, no es una máquina virtual, sino una capa de compatibilidad que implementa la API de Windows. Para ponerlo en perspectiva, se puede pensar que las aplicaciones de Windows son similares a las de Android, y Wine desempeña un papel parecido al de Android. Encapsula las diversas funcionalidades proporcionadas por el sistema operativo en API y permite que las aplicaciones se ejecuten en un entorno aislado. El aspecto específico de la API y el grado de aislamiento son detalles de implementación y no entran en conflicto con el concepto fundamental. En otro nivel, Wine también puede considerarse un simulador, pero en lugar de simular hardware como una CPU, simula el comportamiento de Windows.
PARTE 2: INTRODUCCIÓN A LOS PRINCIPIOS DE WINE
Esta sección es relativamente básica y singular, y es mejor tener una cierta comprensión de los sistemas operativos cuando se lee. Si sólo te interesa compilar y ejecutar Wine y no te interesan los principios, puedes saltarte esta parte sin que afecte a tu comprensión del contenido posterior.
El propósito de Wine es ejecutar programas ejecutables en Windows (PE, portable executable). Sabemos que la esencia de un programa ejecutable es el código máquina dispuesto según ciertas reglas, y el código máquina está relacionado con el conjunto de instrucciones. Gracias a que la mayoría de los PC son x86/x64, en teoría las aplicaciones Windows pueden ejecutarse directamente en máquinas Linux x86/x64 desde la perspectiva del conjunto de instrucciones, sin necesidad de simulación a nivel de hardware.
Sin embargo, para cargar y ejecutar directamente archivos PE, se requiere cierta compatibilidad ABI. Por ejemplo, los programas PE de Windows asumen que se cargan en la dirección 0x400000, por lo que cuando Wine implementa su propio cargador, necesita asegurarse de que la imagen PE se carga en la misma ubicación. Para programas enlazados estáticamente, puede que no haya mucho que hacer, pero para programas enlazados dinámicamente, Wine necesita imitar el comportamiento del cargador de Windows, cargando las librerías dependientes y realizando el trabajo de relocalización necesario.
Para minimizar la dependencia a nivel binario, Wine decidió implementar al menos las bibliotecas dinámicas GDI32, KERNEL32 y USER32, ya que otras bibliotecas se construyen sobre la base de estas tres. En teoría, otras bibliotecas dinámicas podrían utilizar directamente bibliotecas existentes de Windows, pero por diversas razones, Wine tiende a implementar tantas API como sea posible. Nos referimos a las bibliotecas API implementadas por el propio Wine como «builtin» y a las de Windows como «nativas». Cuando Wine carga bibliotecas dinámicas incorporadas, también establece una cabecera PE en la memoria para imitar la disposición de la memoria en Windows. Una implementación más detallada podría ser el tema de un futuro artículo sobre el cargador de Wine, explicando cómo se cargan el propio Wine, los programas PE y las bibliotecas dinámicas.
Además de la funcionalidad del cargador, Wine también necesita resolver problemas de comunicación entre procesos (IPC). El enfoque de Wine consiste en implementar todos los objetos y mecanismos entre procesos, como objetos GDI y semáforos, dentro del servidor Wine. Wine también permite al sistema ejecutar múltiples instancias del servidor Wine. Los objetos dentro del mismo servidor Wine pueden comunicarse entre sí de forma natural como si estuvieran en el mismo espacio, mientras que los objetos bajo diferentes servidores Wine están aislados unos de otros. Esta arquitectura garantiza que los programas de distintos contenedores no se afecten mutuamente. La implementación específica del servidor Wine es a través de sockets Unix, que proporcionan un mecanismo IPC para la interacción con la capa API.
Con estas bases, Wine puede implementar sistemáticamente diversas funciones. Se trata simplemente de comprender el comportamiento y el significado de las API en Windows y, a continuación, reimplementarlas. Aunque parezca sencillo, la dificultad real no es pequeña, especialmente en el caso de algunos comportamientos no documentados, que requieren una comprensión considerable del sistema global antes de poder abordarlos. Incluso algunas diferencias, como el contenido relacionado con la interfaz de usuario, requieren una implementación selectiva debido a las diferentes filosofías de diseño entre el sistema de ventanas de Windows y X. Actualmente, Wine es compatible no solo con Linux, sino también con BSD, Mac OS X y Android.
PARTE 3: ENTORNO
El siguiente entorno de desarrollo se describe utilizando deepin como ejemplo.
En primer lugar, obtenga el código. La dirección oficial del repositorio de código de Wine es:
> git://source.winehq.org/git/wine.git
Si quiere empaquetarlo convenientemente para que otros lo usen y no quiere ocuparse de los detalles del empaquetado, puede usar el Wine mantenido por cada distribución. Por ejemplo, la dirección del repositorio de Wine mantenido por Debian es:
> https://salsa.debian.org/wine-team/wine.git
Aquí utilizaremos el Wine oficial como ejemplo:
git clone git://source.winehq.org/git/wine.git
A continuación, instale las dependencias necesarias para el desarrollo. Por simplicidad, sólo compilaremos Wine de 32 bits, ya que Wine de 64 bits sólo soporta programas PE de 64 bits, y todavía hay muchos programas en Windows que sólo están disponibles en versiones de 32 bits.
sudo apt install\
gcc-multilib\
flex\
bison\
libx11-dev:i386\
libfreetype6-dev:i386\
libxcursor-dev:i386\
libxi-dev:i386\
libxshmfence-dev:i386\
libxxf86vm-dev:i386\
libxrandr-dev:i386\
libxfixes-dev:i386\
libxinerama-dev:i386\
libxcomposite-dev:i386\
libglu1-mesa-dev:i386\
libosmesa6-dev:i386\
ocl-icd-opencl-dev:i386\
libpcap-dev:i386\
libdbus-1-dev:i386\
libgnutls28-dev:i386\
libncurses-dev:i386\
libsane-dev:i386\
libv4l-dev:i386\
libgphoto2-dev:i386\
liblcms2-dev:i386\
libpulse-dev:i386\
libgstreamer-plugins-base1.0-dev:i386\
libudev-dev:i386\
libcapi20-dev:i386\
libcups2-dev:i386\
libfontconfig1-dev:i386\
libgsm1-dev:i386\
libkrb5-dev:i386\
libtiff-dev:i386\
libmpg123-dev:i386\
libopenal-dev:i386\
libldap2-dev:i386\
libxrandr-dev:i386\
libxml2-dev:i386\
libxslt1-dev:i386\
libjpeg62-turbo-dev:i386\
libusb-1.0-0-dev:i386\
gettext\
libsdl2-dev:i386\
libvulkan-dev:i386
A continuación, ejecute el script:
./configure --with-gnutls --without-hal --without-oss
Dependiendo de la versión de Wine, puede ver diferentes mensajes de soporte de funciones en este punto. Puede ajustar las dependencias y los parámetros en función de sus necesidades, y para más detalles, puede consultar el contenido de configure.ac
.
El código fuente de Wine es bastante grande, y la compilación puede llevar mucho tiempo. Puede aumentar el parámetro de paralelismo en función de las capacidades de su CPU, por ejemplo, utilizando make -j8
para la compilación.
Después de compilar, ejecuta:
./wine --version
Para comprobar el número de versión. Si desea instalarlo en el sistema, puede ejecutar:
sudo make install
Sin embargo, tenga en cuenta que su instalación puede cambiar las asociaciones de archivos predeterminadas.
PARTE 4: USO
Ejecute el siguiente comando:
./wine winecfg
Esto le permitirá configurar el contenedor por defecto. El contenedor por defecto se encuentra en el directorio .wine
bajo su directorio HOME. La variable de entorno WINEPREFIX
se utiliza para modificar la ruta actual del contenedor. Por ejemplo, si tienes un archivo ejecutable llamado demo.exe
y quieres probar, si puede ejecutarse normalmente, puedes ejecutar:
WINEPREFIX=~/.demo_exe ./wine demo.exe
El directorio demo_exe
bajo su directorio HOME será utilizado como su directorio contenedor.
PARTE 5: DESARROLLO
Tras la compilación, la estructura de directorios del código fuente de Wine es la siguiente:
├── aclocal.m4
├── ANNOUNCE
├── AUTHORS
├── config.log
├── config.status
├── configure
├── configure.ac
├── COPYING.LIB
├── dlls
├── documentation
├── fonts
├── include
├── libs
├── LICENSE
├── LICENSE.OLD
├── loader
├── MAINTAINERS
├── Makefile
├── Makefile.in
├── po
├── programs
├── README
├── server
├── tools
├── VERSION
└── wine -> tools/winewrapper
A partir de aquí, el proceso es similar al del desarrollo normal. Por ejemplo, si encontramos un error relacionado con las fuentes en una determinada aplicación, podemos utilizar primero nuestra experiencia para determinar cómo está implementado el programa en Windows y, a continuación, comprobar la implementación correspondiente. Por ejemplo, la implementación de fuentes relacionada con GDI se encuentra en dlls/gdi32/font
.c
y dlls/gdi32/freetype.c
. Tras modificar el código, puedes verificarlo rápidamente ejecutando make
en el directorio del módulo, como dlls/gdi32
en el ejemplo anterior.
Para problemas complejos que no son fáciles de localizar, puede utilizar el registro para depuración. La variable de entorno WINEDEBUG
especifica los registros que deben imprimirse.
A veces, podemos necesitar simplificar situaciones complejas, lo que a menudo implica escribir pequeños programas de demostración para reproducir el problema. Si no quieres compilar en Windows, puedes utilizar mingw para compilar directamente archivos exe en deepin. El proceso es sencillo: primero, instala mingw:
sudo apt install mingw-w64
A continuación, implemente el programa utilizando la API de Windows como de costumbre y, por último, utilice la cadena de herramientas mingw para generar el archivo. Aquí tienes un Makefile de ejemplo:
hello.exe: hello.c
i686-w64-mingw32-g++ -o hello.exe hello.c -DUNICODE -D_UNICODE -municode -lgdi32
En el ejemplo anterior, UNICODE
está definido, por lo que el programa utiliza la versión UNICODE de la API con la función de entrada wmain
. La bandera -lgdi32
indica que es necesario enlazar la biblioteca gdi32. El archivo hello.exe
resultante puede ejecutarse tanto en Windows como en deepin.
PARTE 6: OTRAS CONSIDERACIONES
Este artículo sólo cubre los aspectos básicos del desarrollo de Wine. Hay mucho más que explorar en el propio Wine. Por ejemplo, ¿cómo utiliza Wine un mecanismo de controladores para separar las interfaces de las implementaciones? ¿O cómo implementa Wine el mecanismo COM utilizando C puro? Aunque Wine existe desde hace tiempo, su desarrollo sigue siendo muy activo. Los estudiantes interesados pueden unirse y contribuir al ecosistema Linux, permitiendo a todo el mundo acceder a más aplicaciones de alta calidad. Esto puede considerarse una forma de apoyo indirecto a la comunidad.
PARTE 7: ACTUALIZACIONES
7.1 Nueva WOW64
En el ejemplo de compilación anterior, sólo compilamos Wine de 32 bits y omitimos los detalles de la compilación de Wine de 64 bits. A partir de Wine 8, Wine comenzó un proceso de desarrollo llamado Conversión PE, que reimplementó el mecanismo WOW64. En este modo, sólo es necesario compilar una versión de Wine, que puede ejecutar programas tanto de 32 como de 64 bits. Además, ya no depende de las bibliotecas de ejecución de 32 bits. Aunque este modo aún se considera experimental, ha sido el método por defecto desde deepin-wine8.
Para compilar Wine con el nuevo mecanismo WOW64, siga estos pasos:
- La dirección oficial del código fuente de Wine ha cambiado. Descargue el código fuente de https://gitlab.winehq.org/wine/wine.git.
- Sigue siendo necesario instalar las bibliotecas de desarrollo necesarias para la compilación, pero esta vez sólo es necesario instalar las versiones amd64. Al instalar las bibliotecas de desarrollo, ya no es necesario especificar el sufijo :i386. Además, mingw-w64 es ahora un requisito en este modo.
- Cree un nuevo directorio llamado
build-wine
al mismo nivel que el directorio del código fuente de Wine, y navegue hasta este directorio. - Ejecute
../wine/configure --prefix=/opt/wine-newwow64 --enable-archs=i386,x86_64
. Si aparece alguna indicación, como que faltan dependencias de compilación, puede volver a ejecutar el comando después de instalar los paquetes necesarios. - Compilar con
make -j8
. - Instale con
sudo make install
. Wine se instalará en la ubicación especificada por el prefijo en el paso 4, es decir,/opt/wine-newwow64
. Por supuesto, también puedes optar por no instalarlo y ejecutarlo directamente desde el directorio de compilación.
7.2 Otras arquitecturas
Como se mencionó en la sección de principios, los sistemas Linux en máquinas x86/x64 pueden ejecutar programas PE x86/x64 a través de Wine. De hecho, con el avance de la tecnología DBT (traducción binaria dinámica), ahora existen soluciones para ejecutar Wine en ARM y otras arquitecturas. Los lectores interesados pueden consultar el proyecto Box64.
En noviembre, WeChat lanzó una versión nativa para Linux en la tienda deepin, con funcionalidades casi idénticas a las de Windows y macOS. La versión Wine de WeChat por fin puede «jubilarse», y esperamos que más software lance versiones nativas en el futuro, lo que permitirá a Wine completar antes su «misión histórica».
En cuanto al enlace al proyecto Box64, he encontrado algunos problemas al intentar analizarlo. Esto podría deberse al propio enlace o a problemas relacionados con la red. Te recomiendo que compruebes la validez del enlace y vuelvas a intentarlo. Si tienes alguna otra pregunta o necesitas ayuda con alguna otra cosa, ¡no dudes en preguntar!
Lecturas relacionadas:
(1)Haga clic para apoyar a la Comunidad deepin
(2)Colección de deepin Technical Sharing