GPL 準拠のために、qmake と qrc を使用してソース コードを Qt アプリに直接埋め込む

GPL ソフトウェアの販売に関する以前の投稿で、GPL ソフトウェアの販売を難しくしているいくつかの点について概説しました。それらの 1 つは、ソース コードの入手可能性です。オンラインに置くこともできますが、誰もがお金を払わずにアクセスできます.ログインの背後に置いたり、購入後にリンクを送信したりするなどの他のオプションには、追加のシステムが必要であり、より多くのユーザー情報を保存する必要があり、私とユーザーにとって多くの余分な手間がかかります.この問題を「解決」するための私のアイデアの1つは、実際のソースコードを出荷することです.アプリケーション内で直接。この記事では、qmake を使用してすべてのビルドで現在のソース コードのアーカイブを作成する方法を示します。 qrc を使用してアプリケーション内にそれを埋め込みます 、アーカイブをディスクにローカルに保存するためのボタンを含みます。必要な権限を含め、デスクトップだけでなく Android でも動作します。

サンプル プログラムには 2 つのボタンがあり、1 つはビルドごとに動的に作成する zip アーカイブを保存するためのもので、もう 1 つはサンプル イメージを保存するためのものです。サンプル画像は、以前の仕事の古いフォルダーで見つけたランダムなスクリーンショットです。そのシステムはもう使用されていません。

これにより、別のハードルであるモバイル アプリ ソースの側面が解決されます。デスクトップでは、インストーラーとソース コードを含む zip ファイルを提供できますが、アプリ ストアでは提供できません。.apk だけです。 ファイルまたは .aab バンドル。

アプリケーション内にコードを埋め込むことにより、Android では、ユーザーはソース アーカイブをダウンロードする必要なく、アプリ内のコードをシステムに保存できます。

このガイドは Qt5 で機能し、Qt フレームワークと Qml に精通していることを前提としています。デモ プログラムは github にあります。ガイドの最初の部分では、ビルドごとにソース アーカイブを動的に作成する方法について説明し、2 番目の部分ではそれを Qt アプリケーションに埋め込む方法について説明します。

これは、GPL ソフトウェアの販売に関するシリーズのパート 2 です。他の部分はここにあります:

  • パート 1:自分の GPL ソフトウェアを販売する、パート 1:多くのハードル
  • パート 2:GPL 準拠のために、qmake と qrc を使用してソース コードを Qt アプリに直接埋め込む
  • パート 3:既存の GPL ソフトウェアの販売

ソース コードの入手可能性

以前の記事をまだ読んでいない場合は、読むことをお勧めします。なぜなら、この部分であるソース コードの入手に苦労している理由が説明されているからです。ソースが利用可能であることを望んでいませんが、実際の顧客のみが利用できます。ソースコードが GPL に準拠している限り、そのソース コードに対して行うことはすべて彼らの権利です。したがって、私はコードの公開に反対しているわけではありませんが、ソフトウェアがどこでも利用できるようになってしまうことも望んでいません。最終的に、顧客がプログラムを購入してソースを公開する場合、それは顧客の権利であり、私はそれで問題ありません。

GPL FAQ には、課金とソース配布に関する 3 つの Q&A 項目があり、すべての質問に答えています。

GPL は、プログラムのコピーを金銭で販売することを許可していますか?

GPL では、配布サイトからプログラムをダウンロードするために料金を請求することはできますか?

GPL で保護されたソフトウェアを有料で配布する場合、無料で一般に公開する必要がありますか?

2 番目の項目の最後の行 you must offer equivalent access to the source code in the same way through the same place at no further charge 、ダウンロードと一緒にソースを提供するとき、およびアプリケーション内でソースを提供するとき(アプリストアなどでダウンロードできない場合はいつでも)、私が知る限り、カバーされているようです.

ソース コードを公開するこの方法の影響の 1 つは、ソース コードを抽出する前にアプリケーションを実行できるようにすることです。アプリにはそのバージョンのソース コードのみが付属しているため、新しいバージョンも新たに購入する必要があります。デスクトップ プラットフォームでは、購入後にダウンロードでソースのアーカイブを出荷する予定です。したがって、ソースを取得するためにアプリケーションを実行する必要はありませんが、Android ではアプリ ストアでそれを行うことはできません。したがって、その場合、アプリ ストアのレビューさえ通過できれば、これはベスト エフォートです。

qmake ソース コード アーカイブ

サンプル プロジェクトは、こちらの github にあります。記事のこのセクションでは、ソース コード アーカイブの作成方法について説明します。後で qrc について説明します。

シンプルな .zip を出荷しています ソース コードと関連するプロジェクト ファイルをアーカイブします。ファイルは次のコマンドで作成されます:

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

このコマンドは、フォルダー構造が保持されている現在の作業ディレクトリに関連する zip ファイルを生成します。ワイルドカード拡張子リストのすべてのファイルと README.md が含まれます ファイル。

このファイル、source.zipDISTFILES で参照されます .pro のセクション ファイルと同様に qrc ファイル (アプリケーションに埋め込むため) であるため、プログラムをビルドする前に利用できる必要があります。

最初は qmake に追加のコンパイラを追加しようとしました ここに文書化されているように、プロジェクトファイルですが、それは少し面倒でした。すべての入力ファイルを追加する必要がありました。そうしないと、変更が検出されないか、さまざまなトリックが行われる可能性があります。また、コマンドの実行が完全に予測できず、にコマンドを実行する必要がある場合 実際のビルド。これは、source.zip を参照しているためです。 qrc のファイル

最後に、単純な system() を使用しました このコマンドは、実際のビルドの前に実行されることが保証されています:

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

これはクロスプラットフォームではなく、この特定の zip バージョンのコマンドライン フラグでのみ機能しますが、今のところはそれで十分です。以下のように、後でいつでも別のコマンドをブロックにカプセル化できます:

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

Qt Creator を使用してビルドするか、qmake を実行したときの出力 次のようになります:

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.

rm を省略した場合 コマンドを実行すると、既存のファイルは上書きされ、新しいファイルが追加されます。古いファイルは削除されません。

zip アーカイブは正常に開き、内容は期待どおりです:

Qt qrc 埋め込みファイルをディスクに保存

qrc ファイルは Qt リソース システムの一部です。 Qt リソース システムは、バイナリ ファイルをアプリケーションの実行可能ファイルに格納するための、プラットフォームに依存しないメカニズムです。ほとんどの場合 qmake make を生成します ファイル qrc_application.cpp を生成するルール あなたのアプリケーションにリンクされています。このファイルには、画像およびその他のリソースのすべてのデータが、圧縮されたバイナリ データの静的 C++ 配列として含まれています。

qrc を設定することもできます 後でリソース システムに登録される外部バイナリ リソース ファイルを作成します。これは、たとえば、同じコードベースに 2 セットの画像がある場合に便利です。

以下に、私の qml.qrc の内容の例を示します。 ファイル:

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

qrc からファイルをコピーする ファイルシステムへのアクセスは QFile::copy を呼び出すだけです . QFile Qt リソース システムをサポートし、ファイルのパスがコロン (:) で始まる場合 )、リソース システムでファイル名を検索することがわかっています。例:

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

上記の qrc で ファイル、ファイル example.png アプリケーションに埋め込まれている /tmp にコピーされます

これをテストするために私が書いたデモ プログラムは、ファイル名のサニタイズ、存在しないフォルダーのチェック、上書きなど、もう少し多くのことを行いますが、QFile::copy のようなものです。

私が抱えていた問題の 1 つは、最初に QML FileDialog を使用して、ユーザーがファイルを保存するフォルダーを選択できるようにしたことです。ただし、返されたパスは、Linux では file:// で始まります 、単なるパスの代わりに (/home/user/... )。 Android では、ユーザーが何を選択しても返されるパスは /data/user/0/org.qtproject.example.qrcToDisk でした 、これはユーザーが参照できるフォルダーではありません。最初はこれらの問題を回避しようとしましたが、確実に動作しないことが判明したため、QStandardPaths::DocumentsLocation を使用することにしました。 、常に何かを返す必要があります。必要に応じてフォルダーを作成してください。

心に留めておくべきもう 1 つのことは、デフォルトで qrc 内のファイルのアクセス許可が ファイルは読み取り専用 (書き戻すことができないため) であり、QFile これらの権限をコピーします。サンプル プロジェクトでは、新しいファイルのファイル許可を書き込み可能に設定しました。

宛先ファイルが既に存在する場合も同様です QFile::copy そのファイルを手動で削除しない限り失敗します。

この例では、既存のファイルを上書きします。上書きするユーザーの質問を実装するのは、この例のユーザー次第です。

Android でパーミッションを動的にリクエストするボイラープレート コードが少しあります。これらのパーミッションは既に AndroidManifest.xml にあります。 ファイルですが、Android の新しいバージョンでも、使用する前にそれらを要求する必要があるため、そうしています。すべてうまくいくと、以下のようになります:

保存すると、ファイルは Documents にあります フォルダ: