Incruste el código fuente directamente en su aplicación Qt con qmake y qrc, para el cumplimiento de GPL

 C Programming >> Programación C >  >> Tags >> Qt
Incruste el código fuente directamente en su aplicación Qt con qmake y qrc, para el cumplimiento de GPL

En mi publicación anterior sobre la venta de software GPL, describí algunos puntos que dificultan la venta de software GPL. Uno de ellos es la disponibilidad del código fuente. Podrías ponerlo en línea pero luego todos tienen acceso sin pagar. Otras opciones, como colocarlo detrás de un inicio de sesión o enviar un enlace después de la compra, requieren sistemas adicionales y guardar más información del usuario, lo que genera muchas molestias adicionales para mí y para los usuarios. Una de mis ideas para 'resolver' este problema es enviar el código fuente real. directamente dentro de la aplicación. Este artículo le muestra cómo hacerlo, creando un archivo del código fuente actual en cada compilación con qmake e incrustándolo dentro de la aplicación usando qrc , incluido un botón para guardar el archivo localmente en el disco. Funciona tanto en el escritorio como en Android, incluidos los permisos necesarios.

El programa de ejemplo tiene 2 botones, uno para guardar el archivo zip que creamos dinámicamente en cada compilación y otro para guardar la imagen de ejemplo. La imagen de ejemplo es una captura de pantalla aleatoria que encontré en una carpeta antigua de uno de mis trabajos anteriores, ese sistema ya no está en uso.

Esto resuelve otro obstáculo, el aspecto de la fuente de la aplicación móvil. En una computadora de escritorio, puedo proporcionar un archivo zip con el instalador y el código fuente, pero en las tiendas de aplicaciones no puedo hacer eso, solo un .apk archivo o .aab paquete.

Al incrustar el código dentro de la aplicación, en Android los usuarios pueden guardar el código desde la aplicación en su sistema, sin necesidad de descargar un archivo fuente.

Esta guía funciona para Qt5 y asume que está familiarizado con el marco Qt y Qml. El programa de demostración se puede encontrar en github. La primera parte de la guía cubre la creación dinámica del archivo fuente en cada compilación y la segunda parte cubre la integración en una aplicación Qt.

Esta es la parte 2 de mi serie sobre la venta de software GPL. Puedes encontrar las otras partes aquí:

  • Parte 1:Vender mi propio software GPL, parte 1:muchos obstáculos
  • Parte 2:incruste el código fuente directamente en su aplicación Qt con qmake y qrc, para el cumplimiento de GPL
  • Parte 3:Software GPL existente a la venta

Disponibilidad del código fuente

Si no ha leído el artículo anterior, le recomiendo que lo haga, ya que esto explica por qué tengo problemas con esta parte, la disponibilidad del código fuente. Deseo que la fuente esté disponible, pero solo para clientes reales. Cualquier cosa que hagan con el código fuente está en su derecho, siempre y cuando cumpla con la GPL. Así que no estoy en contra de publicar el código, pero tampoco quiero terminar con el software disponible en todas partes. Al final, si un cliente compra el programa y publica la fuente, tiene derecho a hacerlo y estoy de acuerdo con eso.

Las preguntas frecuentes de GPL tienen tres elementos de preguntas y respuestas sobre la carga y la distribución de fuentes que responden a todas las preguntas que pueda tener:

¿La GPL me permite vender copias del programa a cambio de dinero?

¿La GPL me permite cobrar una tarifa por descargar el programa desde mi sitio de distribución?

Si distribuyo software con licencia GPL por una tarifa, ¿debo ponerlo a disposición del público sin cargo?

La última línea del segundo elemento, you must offer equivalent access to the source code in the same way through the same place at no further charge , parece estar cubierto por lo que sé cuando proporciono la fuente junto con la descarga y dentro de la aplicación (siempre que la descarga no sea posible, como en las tiendas de aplicaciones).

Uno de los efectos de esta forma de publicar el código fuente es que no debe poder ejecutar la aplicación antes de poder extraer el código fuente. Las versiones más nuevas también requieren una nueva compra, ya que la aplicación solo se envía con el código fuente de esa versión. En las plataformas de escritorio planeo enviar un archivo de la fuente en la descarga después de la compra, por lo que no es necesario que ejecute la aplicación para obtener la fuente, pero en Android en la tienda de aplicaciones eso no es posible. Así que, en ese caso, este es el mejor esfuerzo, incluso si pasa por la revisión de la tienda de aplicaciones.

qhacer un archivo de código fuente

Puede encontrar el proyecto de ejemplo aquí en github. Esta sección del artículo cubre cómo se hace el archivo del código fuente, más adelante cubriremos el qrc sección para extraer el archivo en el disco.

Estoy enviando un .zip simple archive con el código fuente y los archivos relevantes del proyecto. El archivo se crea con el siguiente comando:

zip -r source.zip ./ -i '*.cpp' '*.h' '*.qml' '*.qrc' '*.pro' '*.png' 'README.md' 'LICENSE'

Este comando produce un archivo zip relativo al directorio de trabajo actual en el que se conserva la estructura de carpetas. Incluye todos los archivos en la lista de extensiones comodín y el README.md expediente.

Este archivo, source.zip , se hace referencia en el DISTFILES sección del .pro archivo así como en el qrc archivo (que se incrustará en la aplicación), por lo que debe estar disponible antes de compilar el programa.

Al principio traté de agregar un compilador extra al qmake archivo de proyecto, como se documenta aquí, pero eso fue un poco complicado. O tenía que agregar todos los archivos de entrada, de lo contrario no se detectarían los cambios, o habría muchos trucos variables. Además, cuando el comando se ejecuta no era del todo predecible y necesito ejecutar el comando antes la construcción real. Esto se debe a que hacemos referencia al source.zip archivo en nuestro qrc archivo, debe estar allí antes de que construyamos.

Al final usé un simple system() comando, que se garantiza que se ejecutará antes de la compilación real:

system(cd $$PWD; rm source.zip; zip -r source.zip ./ -i \'*.cpp\' \'*.h\' \'*.qml\' \'*.qrc\' \'*.pro\' \'*.png\' \'android/*\' 'README.md' 'LICENSE')

Esto no es multiplataforma y solo funciona con los indicadores de línea de comandos de esta versión zip específica, pero por ahora está bien. Siempre puedo encapsular un comando diferente más adelante en un bloque como el siguiente:

win32 {
    system(windows command)
} else {
    system(linux command)
}

El resultado cuando se construye a través de Qt Creator o se ejecuta qmake se parece a esto:

19:48:23: Running steps for project qrcToDisk...
19:48:23: Starting: "/bin/qmake" /src/QtExamples/qrcToDisk/qrcToDisk.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
  adding: src/QtExamples/qrcToDisk/files/example.png (deflated 14%)
  adding: src/QtExamples/qrcToDisk/SaveToDisk.cpp (deflated 56%)
  adding: src/QtExamples/qrcToDisk/qml.qrc (deflated 36%)
  adding: src/QtExamples/qrcToDisk/main.qml (deflated 64%)
  adding: src/QtExamples/qrcToDisk/main.cpp (deflated 50%)
  adding: src/QtExamples/qrcToDisk/qrcToDisk.pro (deflated 41%)
  adding: src/QtExamples/qrcToDisk/SaveToDisk.h (deflated 33%)
19:48:23: The process "/bin/qmake" exited normally.

Si omite el rm comando, cualquier archivo ya existente se sobrescribirá y se agregarán nuevos archivos. Los archivos antiguos no se eliminan.

El archivo zip se abre bien y el contenido es el esperado:

Guardar un archivo incrustado Qt qrc en el disco

Un qrc El archivo es parte del sistema de recursos Qt. El sistema de recursos Qt es un mecanismo independiente de la plataforma para almacenar archivos binarios en el ejecutable de la aplicación. Más a menudo qmake genera make reglas para generar el archivo qrc_application.cpp que está vinculado a su aplicación. Este archivo contiene todos los datos de las imágenes y otros recursos como matrices estáticas de C++ de datos binarios comprimidos.

También puede configurar qrc para crear un archivo de recursos binarios externo que luego se registra con el sistema de recursos. Esto es útil si tiene, por ejemplo, dos conjuntos de imágenes para el mismo código base.

A continuación encontrará el contenido de ejemplo de mi qml.qrc archivo:

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>files/example.png</file>
        <file>source.zip</file>
    </qresource>
</RCC>

Copiar un archivo de qrc al sistema de archivos es tan simple como llamar a QFile::copy . QFile es compatible con el sistema de recursos Qt y si la ruta de su archivo comienza con dos puntos (: ), sabe buscar en el sistema de recursos el nombre del archivo. Un ejemplo:

QFile::copy(":/files/example.png", "/tmp/example.png");

Con el anterior qrc archivo, el archivo example.png que está incrustado en la aplicación se copiará en el /tmp carpeta.

El programa de demostración que escribí para probar esto hace un poco más, como desinfectar el nombre del archivo, buscar carpetas que no existen y sobrescribir, pero el QFile::copy como es la esencia de esto.

Un problema que tuve fue que al principio usé un QML FileDialog para permitir que el usuario seleccionara la carpeta para guardar los archivos. Sin embargo, la ruta devuelta, onlinux, comenzó con file:// , en lugar de solo la ruta (/home/user/... ). En Android, la ruta devuelta, independientemente de la que elija el usuario, fue /data/user/0/org.qtproject.example.qrcToDisk , que no es una carpeta a la que el usuario pueda navegar. Al principio, traté de solucionar esos problemas, pero resultó que no funcionaba de manera confiable, así que opté por usar QStandardPaths::DocumentsLocation , que siempre debe devolver algo, cree la carpeta si es necesario.

Otra cosa a tener en cuenta es que, de forma predeterminada, los permisos de los archivos en el qrc son de solo lectura (ya que no puede volver a escribir en él) y QFile copia esos permisos. En el proyecto de ejemplo, configuré el permiso de archivo del nuevo archivo para que se pueda escribir.

Lo mismo ocurre en el caso de que el archivo de destino ya exista, QFile::copy fallará a menos que elimine manualmente ese archivo.

En este ejemplo, sobrescribo cualquier archivo existente, depende de los usuarios de este ejemplo implementar una pregunta de usuario para sobrescribir.

Hay un poco de código repetitivo para solicitar permisos dinámicamente en Android, esos permisos ya están en el AndroidManifest.xml archivo, pero las versiones más nuevas de Android también requieren que las solicite antes de usarlas, así que lo hacemos. Si todo funciona, se ve a continuación:

Una vez guardados, los archivos están en el Documents carpeta: