GPGme with Qt5

GPGを任意のプログラムから呼び出すことができるGPGmeのconfigureにQt5のオプションがあることに気が付きました。

何ができるのかよく分かりませんが、とりあえず有効にしてみようとして四苦八苦したので備忘録。

## 環境

* Ubuntu 16.04 LTS
* Qt 5.8
* GPGme 1.8 (f06220b  (61538))

```
        GPGME v1.8.0 has been configured as follows:

        Revision:          f06220b  (61538)
        Platform:          x86_64-pc-linux-gnu

        UI Server:         yes
        FD Passing:        yes

        Language bindings: cl cpp  qt
```

## Qt5

Qt5をUbuntuにインストールすると、デフォルトでは/opt/Qtにインストールされます。

諸々は`/opt/Qt/5.8/gcc_64`などにありますが、普段はqmakeが何でもやってくれるので、configureに渡すにはどうしたらいいのか途方に暮れます。

まずpkgconfigでQt5Core.pcが無いよ！って怒られますので、`ln -s /opt/Qt/5.8/gcc_64/lib/pkgconfig/*.pc /usr/local/lib/pkgconfig/`します。

以下のパラメータでconfigureは通ります。

```
MOC=/opt/Qt/5.8/gcc_64/bin/moc \
    GPGME_QT_CFLAGS="-I/opt/Qt/5.8/gcc_64/include -I/opt/Qt/5.8/gcc_64/include/QtCore" \
    GPGME_QT_LIBS="-lQt5Core -L/opt/Qt/5.8/gcc_64/lib -Wl,-rpath /opt/Qt/5.8/gcc_64/lib" \
    ./configure
```

## make

makeを実行すると、次のようなエラーが出ます。

```
...
libtool: link: g++  -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o  .libs/dataprovider.o .libs/job.o .libs/multideletejob.o .libs/qgpgmeadduseridjob.o .libs/qgpgmebackend.o .libs/qgpgmechangeexpiryjob.o .libs/qgpgmechangeownertrustjob.o .libs/qgpgmechangepasswdjob.o .libs/qgpgmedecryptjob.o .libs/qgpgmedecryptverifyjob.o .libs/qgpgmedeletejob.o .libs/qgpgmedownloadjob.o .libs/qgpgmeencryptjob.o .libs/qgpgmeexportjob.o .libs/qgpgmeimportfromkeyserverjob.o .libs/qgpgmeimportjob.o .libs/qgpgmekeygenerationjob.o .libs/qgpgmekeylistjob.o .libs/qgpgmelistallkeysjob.o .libs/qgpgmenewcryptoconfig.o .libs/qgpgmerefreshkeysjob.o .libs/qgpgmesecretkeyexportjob.o .libs/qgpgmesignencryptjob.o .libs/qgpgmesignjob.o .libs/qgpgmesignkeyjob.o .libs/qgpgmeverifydetachedjob.o .libs/qgpgmeverifyopaquejob.o .libs/threadedjobmixin.o .libs/qgpgmekeyformailboxjob.o .libs/gpgme_backend_debug.o .libs/qgpgmetofupolicyjob.o .libs/defaultkeygenerationjob.o .libs/qgpgmewkspublishjob.o .libs/dn.o   -Wl,-rpath -Wl,/home/mugwort_rc/Downloads/gpgme-1.8.0-3/gpgme-1.8.0/lang/cpp/src/.libs -Wl,-rpath -Wl,/home/mugwort_rc/Downloads/gpgme-1.8.0-3/gpgme-1.8.0/src/.libs -Wl,-rpath -Wl,/opt/Qt/5.8/gcc_64/lib -Wl,-rpath -Wl,/opt/Qt/5.8/gcc_64/lib ../../cpp/src/.libs/libgpgmepp.so ../../../src/.libs/libgpgme.so -lassuan -L/usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/libgpg-error.so /opt/Qt/5.8/gcc_64/lib/libQt5Core.so -L/opt/Qt/5.8/gcc_64/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/5/../../.. -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o  -O2 -Wl,-rpath   -Wl,-soname -Wl,libqgpgme.so.7 -o .libs/libqgpgme.so.7.1.0
/usr/bin/ld: cannot find libqgpgme.so.7: No such file or directory
collect2: error: ld returned 1 exit status
...
```

libqgpgme.soを作るコマンドでlibqgpgme.so.7を必要としているみたいです？

よく見るとlibtoolが怪しいです。（`-Wl,-soname -Wl,libqgpgme.so.7`）

ルートディレクトリ（configureと同じディレクトリ）にあるlibtoolの`\${wl}-soname \$wl\$soname -o \$lib`となっているところを、`\${wl}-soname=\$soname -o \$lib`とします。

```diff
--- a/libtool	2017-02-17 23:31:33.476642000 +0900
+++ b/libtool	2017-02-17 23:32:51.476700473 +0900
@@ -10157,7 +10157,7 @@
 old_archive_from_expsyms_cmds=""
 
 # Commands used to build a shared archive.
-archive_cmds="\$CC \$pic_flag -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib"
+archive_cmds="\$CC \$pic_flag -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname=\$soname -o \$lib"
 archive_expsym_cmds="\$CC \$pic_flag -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-retain-symbols-file \$wl\$export_symbols -o \$lib"
 
 # Commands used to build a loadable module if different from building
```

おそらくこれで問題なくビルドが通るはずです。（少なくともgpgme1.8では…。）

## Python

ついでにPython wrapper（PyME）もインストールします。

* Python 3.5
* virtualenv
* SWIG 3.0.12

lang/pythonに移動します。

setup.py buildを行うと、まずconfig.hが無いと怒られるのでln -s ../../config.hを行います。

次にdata.hが無いと怒られるので、setup.pyを開き、include_dirsに`../../src/`を追加します。

```diff
--- a/setup.py	2017-02-18 00:01:47.810115922 +0900
+++ b/setup.py	2017-02-18 00:01:44.225997126 +0900
@@ -28,7 +28,7 @@
 gpgme_config_flags = ["--thread=pthread"]
 gpgme_config = ["gpgme-config"] + gpgme_config_flags
 gpgme_h = ""
-include_dirs = [os.getcwd()]
+include_dirs = [os.getcwd(), "../../src/"]
 library_dirs = []
 in_tree = False
 extra_swig_opts = []
```

後は`setup.py build`、`setup.py install`でvirtualenv上にgpgライブラリが追加されます。

参照: [pyme備忘録](http://qiita.com/mugwort_rc/items/3401e49af0de5df4058d)

## QGpgME

### QIODeviceDataProvider

GPGmeにデータを渡す際、毎回`QIODevice::readAll()`して`QByteArray::constData()`を取得するのは面倒ですし、スマートではありません。

GPGmeにはDataProviderというのが用意されており、任意のデータソースを読み書きする手段となります。

```cpp
std::shared_ptr<QIODevice> file(new QFile(filepath));
if ( ! file->open(QIODevice::ReadOnly) ) {
    return;
}

QGpgME::QIODeviceDataProvider provider(file);
GpgME::Data data(&provider);
```