Build Qt 5 MySQL Plugin for Android: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
Line 87: Line 87:
# pkg (optional in case you want to build for higher OpenSSL/libiconv/mariadbclient/Qt version)
# pkg (optional in case you want to build for higher OpenSSL/libiconv/mariadbclient/Qt version)


<code>#!/bin/bash
<code>
 
#!/bin/bash
# Based on https://gist.github.com/RazZziel/fd607459c1f07a43cdf9
# Based on https://gist.github.com/RazZziel/fd607459c1f07a43cdf9
 
export ANDROID_NDK_ROOT="$HOME/.Qt/android-ndk-r10e/"
export ANDROID_NDK_ROOT="$HOME/.android/android-ndk-r10e/"
export QT_ROOT="$HOME/.Qt/5.5/"
export QT_ROOT="$HOME/.Qt/5.7/"
 
SR="$ANDROID_NDK_ROOT/platforms/android-17/arch-arm/"
SR="$ANDROID_NDK_ROOT/platforms/android-17/arch-arm/"
BR="$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-"
BR="$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-"
 
here="$(dirname "$0")"
here="$(dirname "$0")"
find "$SR" > "$here/rootfs_files_before.txt" || exit 1
find "$SR" > "$here/rootfs_files_before.txt" || exit 1
Line 105: Line 106:
}
}
trap checkChanges EXIT
trap checkChanges EXIT
 
# OpenSSL
# OpenSSL
#pkg=openssl-1.0.1f.tar.gz
#pkg=openssl-1.0.1f.tar.gz
#pkg=openssl-1.0.1e.tar.gz
#pkg=openssl-1.0.1e.tar.gz
pkg=openssl-1.0.2d.tar.gz
pkg=openssl-1.0.2h.tar.gz
dir=$(basename $pkg .tar.gz)
dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
if [ ! -d $dir ]; then
         wget -c http://www.openssl.org/source/$pkg
         wget -c http://www.openssl.org/source/$pkg
         tar -xf $pkg || exit 1
         tar -xf $pkg || exit 1
fi
fi
 
pushd $dir
pushd $dir
         RANLIB="$BR"ranlib CC="$BR"gcc ./Configure android-armv7 --prefix=$SR/usr
         RANLIB="$BR"ranlib CC="$BR"gcc ./Configure android-armv7 --prefix=$SR/usr
Line 123: Line 124:
         make install_sw || exit 1
         make install_sw || exit 1
popd
popd
 
 
# libiconv
# libiconv
pkg=libiconv-1.14.tar.gz
pkg=libiconv-1.14.tar.gz
dir=$(basename $pkg .tar.gz)
dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
if [ ! -d $dir ]; then
         wget -c http://ftp.gnu.org/pub/gnu/libiconv/$pkg
         wget -c http://ftp.gnu.org/pub/gnu/libiconv/$pkg
         tar -xf $pkg || exit 1
         tar -xf $pkg || exit 1
fi
fi
 
pushd $dir
pushd $dir
         STRIP="$BR"strip RANLIB="$BR"ranlib OBJDUMP="$BR"objdump AR="$BR"ar CC="$BR"gcc CFLAGS=--sysroot=$SR CPP="$BR"cpp CPPFLAGS=$CFLAGS ./configure --host=arm --prefix=$SR/usr --with-sysroot=$SR
         STRIP="$BR"strip RANLIB="$BR"ranlib OBJDUMP="$BR"objdump AR="$BR"ar CC="$BR"gcc CFLAGS=--sysroot=$SR CPP="$BR"cpp CPPFLAGS=$CFLAGS ./configure --host=arm --prefix=$SR/usr --with-sysroot=$SR
Line 139: Line 140:
         make install || exit 1
         make install || exit 1
popd
popd
 
 
# mariadbclient
# mariadbclient
 
version=2.0.0
version=2.0.0
pkg=mariadb_client-$version-src.tar.gz
pkg=mariadb_client-$version-src.tar.gz
url=https://downloads.mariadb.org/f/client-native-$version/src/$pkg
url=http://archive.mariadb.org/client-native-$version/src/$pkg
 
# FIXME: This one fails to build, linker errors
# FIXME: This one fails to build, linker errors
#version=2.1.0
#version=2.1.0
#pkg=mariadb-connector-c-$version-src.tar.gz
#pkg=mariadb-connector-c-$version-src.tar.gz
#url=https://downloads.mariadb.org/f/connector-c-$version/source-tgz/$pkg
#url=https://downloads.mariadb.org/f/connector-c-$version/source-tgz/$pkg
 
dir=$(basename $pkg .tar.gz)
dir=$(basename $pkg .tar.gz)
if [ ! -d $dir ]; then
if [ ! -d $dir ]; then
Line 157: Line 158:
         tar -xf $pkg || exit 1
         tar -xf $pkg || exit 1
fi
fi
 
pushd $dir
pushd $dir
         sed -i -e "s|ADD_SUBDIRECTORY(unittest/libmariadb)|#ADD_SUBDIRECTORY(unittest/libmariadb)|" CMakeLists.txt
         sed -i -e "s|ADD_SUBDIRECTORY(unittest/libmariadb)|#ADD_SUBDIRECTORY(unittest/libmariadb)|" CMakeLists.txt
Line 185: Line 186:
         make install || exit 1
         make install || exit 1
         popd
         popd
 
         # ???
         # ???
         pwd
         pwd
         cp build/libmariadb/*.{a,so} "$SR/usr/lib/mariadb/" || exit 1
         cp build/libmariadb/*.{a,so} "$SR/usr/lib/mariadb/" || exit 1
popd
popd
 
 
# qt
# qt
qmake="$QT_ROOT/android_armv7/bin/qmake"
qmake="$QT_ROOT/android_armv7/bin/qmake"
Line 197: Line 198:
[ ! -x "$qmake" ] && { echo "Qmake is not executable in '$qmake'"; exit 1; }
[ ! -x "$qmake" ] && { echo "Qmake is not executable in '$qmake'"; exit 1; }
qtVersion=$(qmake -query QT_VERSION)
qtVersion=$(qmake -query QT_VERSION)
qtVersion=5.7.0
#pkg=qt-everywhere-opensource-src-$qtVersion.tar.gz
pkg=qtbase-opensource-src-$qtVersion.tar.gz


#pkg=qt-everywhere-opensource-src-$qtVersion.tar.gz
#pkg=qtbase-opensource-src-$qtVersion.tar.gz
pkg=qtbase-opensource-src-5.5.1.tar.gz
dir=$(basename $pkg .tar.gz)
dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
if [ ! -d $dir ]; then
#        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/submodules/$pkg
        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/submodules/$pkg
#        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/$pkg
#        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/$pkg
        wget -c http://download.qt.io/official_releases/qt/5.5/5.5.1/submodules/qtbase-opensource-src-5.5.1.tar.gz
         tar -xf $pkg || exit 1
         tar -xf $pkg || exit 1
fi
fi
 
pushd $dir/src/plugins/sqldrivers/mysql/
pushd $dir/src/plugins/sqldrivers/mysql/
         $qmake "INCLUDEPATH+=$SR/usr/include/mariadb" "LIBS+=$SR/usr/lib/mariadb/libmariadbclient.a $SR/usr/lib/libssl.a $SR/usr/lib/libcrypto.a $SR/usr/lib/libiconv.a" "LIBPATH+=$SR/usr/lib/mariadb" -o Makefile mysql.pro
         $qmake "INCLUDEPATH+=$SR/usr/include/mariadb" "LIBS+=$SR/usr/lib/mariadb/libmariadbclient.a $SR/usr/lib/libssl.a $SR/usr/lib/libcrypto.a $SR/usr/lib/libiconv.a" "LIBPATH+=$SR/usr/lib/mariadb" -o Makefile mysql.pro
Line 215: Line 215:
         make install || exit 1
         make install || exit 1
popd
popd
 
 
echo
echo
echo "BOOYAH!!!"
echo "BOOYAH!!!"

Revision as of 19:48, 4 July 2016

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

Building the Qt5 mysql plugin for Android turned out to not be as straightforward as you may hope. I'll cover the necessary steps to accomplish this below.

Using mariadbclient (Option 1)

Setting up the general environment

Set the following environment variables:

  1. SR=/path/to/android/ndk/platforms/android-9/arch-arm
  2. BR=/path/to/android/ndk/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-

NOTE: I have been unable to get openssl to compile on the x86 version of android, hence the ARMv7 variables above. If you are successful at getting openssl to compile with the x86 android, by all means update this wiki :).

Prerequisites

The mysql module requires the following to compile:

  1. The mysql client library. For mariadb (recommended mysql implementation), you also require:
    1. openssl
    2. libiconv

Compiling OpenSSL

I've tested this with openssl version 1.0.1e. This should work with future versions as well, but I can't guarantee that.

First, grab the sources and unpack them. Then, enter the source directory and do the following:

RANLIB="$BR"ranlib CC="$BR"gcc ./Configure android-armv7 --prefix=$SR/usr
ANDROID_DEV=$SR/usr make
make install

Note: There should be a way to get openssl to compile and install only the library, but I haven't found the right make targets for that yet. The above will make and install everything for openssl rather than just the library.

To install only the binary files use

make install_sw

Compiling libiconv

I've tested this with libiconv version 1.14. Again, this should work with future versions, but I can't guarantee as much.

First, grab the sources and unpack them. Then, enter the source directory and do the following:

STRIP="$BR"strip RANLIB="$BR"ranlib OBJDUMP="$BR"objdump AR="$BR"ar CC="$BR"gcc CFLAGS=--sysroot=$SR CPP="$BR"cpp CPPFLAGS=$CFLAGS ./configure --build=x86_64 --host=arm --prefix=$SR/usr --with-sysroot=$SR && make install

Compiling mariadbclient

After testing, I've found that the released sources are not compatible with mysql (as of version 1.0.0). They are missing the mysql_library_init function, which the Qt mysql plugin uses. However, the bazaar sources are compatible with mysql and include this function. Grab the mariadb sources from bazaar, configure, compile, and install the mariadb connector client library as described below:

bzr branch lp:mariadb-native-client
cd maria-native-client

The mariadb unit tests will fail and halt the compilation of maria db due to some missing pthread routines. I recommend commenting out the unit tests so they don't block the install. Modify CMakeLists.txt in the base source directory and comment out the following line:

ADD_SUBDIRECTORY(unittest/libmariadb)

UPDATE: As of connector version 2.0.0, mariadb is fully compatible with the released version. If you download the 2.0.0 (or later) connector, you can start from this point. You will not need the bazaar sources, nor will you need to disable the unit tests above.

Now you can configure via cmake:

mkdir build && cd build
PKG_CONFIG_PATH=$SR/usr/lib/pkgconfig cmake -DCMAKE_AR="$BR"ar -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="$BR"gcc -DCMAKE_C_FLAGS=--sysroot=$SR -DCMAKE_INSTALL_PREFIX=$SR/usr -DCMAKE_LINKER="$BR"ld -DCMAKE_NM="$BR"nm -DCMAKE_OBJCOPY="$BR"objcopy -DCMAKE_OBJDUMP="$BR"objdump -DCMAKE_RANLIB="$BR"ranlib -DCMAKE_STRIP="$BR"strip -DWITH_EXTERNAL_ZLIB=ON -DICONV_INCLUDE_DIR=$SR/usr/include -DICONV_LIBRARIES=$SR/usr/lib/libiconv.a -DZLIB_INCLUDE_DIR=$SR/usr/include -DZLIB_LIBRARY=$SR/usr/lib/libz.so ../

At this point, you'll want to make some minor changes to the sources to make them compile on android. For one, the android compiler does not know what a 'ushort' is. So, define it in include/my_global.h inside the #define _global_h block:

#ifndef ushort
#define ushort uint16
#endif

Now you're ready to compile and install:

make install

Deployment Notes

You will need to add the mariadb shared object library file the list of additional libraries to add to the APK image. To get the exact name of the file needed after compiling the QT mysql plugin use the following command:

"$BR"objdump -p libqsqlmysql.so | grep NEEDED

To correctly create a mariadb.so file instead of mariadb.so.1 edit libmariadb/CMakeLists.txt and comment out the block:

 SET_TARGET_PROPERTIES(libmariadb PROPERTIES VERSION ${CPACK_PACKAGE_VERSION_MAJOR} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})

Using mariadbclient (Option 2)

Using this shell script you can build the plugin easily after modifying the following variables:

  1. ANDROID_NDK_ROOT
  2. QT_ROOT
  3. SR (optional in case you want to build for higher Android version)
  4. pkg (optional in case you want to build for higher OpenSSL/libiconv/mariadbclient/Qt version)
#!/bin/bash
 
# Based on https://gist.github.com/RazZziel/fd607459c1f07a43cdf9
 
export ANDROID_NDK_ROOT="$HOME/.android/android-ndk-r10e/"
export QT_ROOT="$HOME/.Qt/5.7/"
 
SR="$ANDROID_NDK_ROOT/platforms/android-17/arch-arm/"
BR="$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-"
 
here="$(dirname "$0")"
find "$SR" > "$here/rootfs_files_before.txt" || exit 1
checkChanges() {
        find "$SR" > "$here/rootfs_files_after.txt" || exit 1
        echo "Changes:"
        diff -u "$here/rootfs_files_before.txt" "$here/rootfs_files_after.txt"
}
trap checkChanges EXIT
 
# OpenSSL
#pkg=openssl-1.0.1f.tar.gz
#pkg=openssl-1.0.1e.tar.gz
pkg=openssl-1.0.2h.tar.gz
dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
        wget -c http://www.openssl.org/source/$pkg
        tar -xf $pkg || exit 1
fi
 
pushd $dir
        RANLIB="$BR"ranlib CC="$BR"gcc ./Configure android-armv7 --prefix=$SR/usr
        ANDROID_DEV=$SR/usr make #|| exit 1
        ANDROID_DEV=$SR/usr make || exit 1
        make install_sw || exit 1
popd
 
 
# libiconv
pkg=libiconv-1.14.tar.gz
dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
        wget -c http://ftp.gnu.org/pub/gnu/libiconv/$pkg
        tar -xf $pkg || exit 1
fi
 
pushd $dir
        STRIP="$BR"strip RANLIB="$BR"ranlib OBJDUMP="$BR"objdump AR="$BR"ar CC="$BR"gcc CFLAGS=--sysroot=$SR CPP="$BR"cpp CPPFLAGS=$CFLAGS ./configure --host=arm --prefix=$SR/usr --with-sysroot=$SR
        make || exit 1
        make install || exit 1
popd
 
 
# mariadbclient
 
version=2.0.0
pkg=mariadb_client-$version-src.tar.gz
url=http://archive.mariadb.org/client-native-$version/src/$pkg
 
# FIXME: This one fails to build, linker errors
#version=2.1.0
#pkg=mariadb-connector-c-$version-src.tar.gz
#url=https://downloads.mariadb.org/f/connector-c-$version/source-tgz/$pkg
 
dir=$(basename $pkg .tar.gz)
if [ ! -d $dir ]; then
        wget -c $url
        tar -xf $pkg || exit 1
fi
 
pushd $dir
        sed -i -e "s|ADD_SUBDIRECTORY(unittest/libmariadb)|#ADD_SUBDIRECTORY(unittest/libmariadb)|" CMakeLists.txt
        sed -i -e "N; s|typedef unsigned short ushort;\n#endif|#endif\ntypedef unsigned short ushort;|" include/my_global.h
        sed -i -e "N; s|SET_TARGET_PROPERTIES(libmariadb PROPERTIES VERSION.*||" libmariadb/CMakeLists.txt
        sed -i -e "N; s|SOVERSION \${CPACK_PACKAGE_VERSION_MAJOR})||" libmariadb/CMakeLists.txt # Pig disgusting: the previous multiline thingie should've done it
        sed -i -e "N; s|\${CPACK_PACKAGE_VERSION_MAJOR}||" libmariadb/CMakeLists.txt # Pig disgusting: what the fuck
        mkdir build
        pushd build
        PKG_CONFIG_PATH=$SR/usr/lib/pkgconfig cmake \
		-DCMAKE_BUILD_TYPE=Release \
		-DCMAKE_C_FLAGS=--sysroot="$SR" \
		-DCMAKE_INSTALL_PREFIX="$SR/usr" \
		-DCMAKE_C_COMPILER="$BR"gcc \
		-DCMAKE_LINKER="$BR"ld \
		-DCMAKE_AR="$BR"ar \
		-DCMAKE_NM="$BR"nm \
		-DCMAKE_OBJCOPY="$BR"objcopy \
		-DCMAKE_OBJDUMP="$BR"objdump \
		-DCMAKE_RANLIB="$BR"ranlib \
		-DCMAKE_STRIP="$BR"strip \
		-DICONV_INCLUDE_DIR="$SR/usr/include" \
		-DICONV_LIBRARIES="$SR/usr/lib/libiconv.a" \
		-DWITH_EXTERNAL_ZLIB=ON \
		-DZLIB_INCLUDE_DIR="$SR/usr/include" \
		-DZLIB_LIBRARY="$SR/usr/lib/libz.so" ../ || exit 1
        make install || exit 1
        popd
 
        # ???
        pwd
        cp build/libmariadb/*.{a,so} "$SR/usr/lib/mariadb/" || exit 1
popd
 
 
# qt
qmake="$QT_ROOT/android_armv7/bin/qmake"
[ ! -f "$qmake" ] && { echo "Could not find qmake in '$qmake'"; exit 1; }
[ ! -x "$qmake" ] && { echo "Qmake is not executable in '$qmake'"; exit 1; }
qtVersion=$(qmake -query QT_VERSION)
qtVersion=5.7.0 
#pkg=qt-everywhere-opensource-src-$qtVersion.tar.gz
pkg=qtbase-opensource-src-$qtVersion.tar.gz

dir=$(basename $pkg .tar.gz)
 
if [ ! -d $dir ]; then
        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/submodules/$pkg
#        wget -c http://download.qt.io/official_releases/qt/${qtVersion%.*}/$qtVersion/$pkg
        tar -xf $pkg || exit 1
fi
 
pushd $dir/src/plugins/sqldrivers/mysql/
        $qmake "INCLUDEPATH+=$SR/usr/include/mariadb" "LIBS+=$SR/usr/lib/mariadb/libmariadbclient.a $SR/usr/lib/libssl.a $SR/usr/lib/libcrypto.a $SR/usr/lib/libiconv.a" "LIBPATH+=$SR/usr/lib/mariadb" -o Makefile mysql.pro
        make || exit 1
        make install || exit 1
popd
 
 
echo
echo "BOOYAH!!!"
echo

Deployment Note

You've to add an external library to your .pro file because the generated plugin depends on libmariadb.so

contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
    ANDROID_EXTRA_LIBS = \
        # modify the path
        $$PWD/../../../mysqllibandroid/mariadb_client-2.0.0-src/build/libmariadb/libmariadb.so
}

Using mysqlclient (Option 3)

Stub for someone to experiment with and update this page

Compiling the Qt mysql plugin

You cannot compile the mysql plugin from the configure script for android- that appears to be broken as of this writing. You can, however, compile it manually from the sources. Grab the Qt5 sources from git, configure them for android as normal (without the qt-sql-mysql or plugin-sql-mysql flags), make, and install as normal. Then enter the qtbase/src/plugins/sqldrivers/mysql directory and execute the following: