Несколько дней назад встал вопрос о написании консольного приложения, которое будет работать в Linux CentOS 7 и взаимодействовать с MS SQL Server 2012. Мне очень нравится Qt и я решил, что воспользуюсь им для решения этой задачи. И если под Windows я достаточно быстро настроил необходимое окружение, то под Linux я столкнулся с проблемами, которые очень тяжело было решить с помощью гуглинга. Этому вопросу я посвятил полтора дня. Считаю полезным поделиться своим опытом, возможно кому-то это поможет сэкономить драгоценное время.
Инструменты
Я не хочу тянуть на сервер исходники Qt, для того чтобы собрать плагин и само приложение. Поэтому беру образ CentOS 7 LiveGNOME и устанавливаю его на VirtualBox машину. После делаю полный апдейт, и ставлю VirtualBox Guest Additions.
Устанавливаю g++:
sudo yum install gcc-c++
Скачиваю установщик Qt для Linux x64. Устанавливаю Qt 5.9.1, дополнительно при установке выбираю галочку Source, чтобы получить исходники.
Установка Microsoft ODBC Driver for SQL Server
Согласно инструкции устанавливаю драйвер:
sudo su
curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel
sudo ACCEPT_EULA=Y yum install msodbcsql
sudo ACCEPT_EULA=Y yum install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
sudo yum install unixODBC-devel
Драйвер нужно установить как на VirtualBox, так и на машину, где будет работать софт.
Сборка Qt плагина QODBC
Следуя инструкции, скачиваем куда-нибудь unixODBC, распаковываем. Теперь нам нужно собрать unixODBC и установить. В документации Qt, а так же в других источниках в основном я встречал примеры, которые предполагают установку unixODBC в /usr/local/unixODBC. Тут дело вкуса конечно, но я буду использовать именно такое расположение. Так же файлы конфигов драйверов я хочу поместить в /usr/local/etc Для этого нужно сконфигурировать unixODBC со следующими параметрами:
./configure --prefix=/usr/local/unixODBC --sysconfdir=/usr/local/etc
Затем собираем и устанавливаем:
make
make install
Теперь необходимо настроить конфигурацию Microsoft ODBC Driver for SQL Server. Для этого переходим в /usr/local/unixODBC/bin и выполняем:
sudo ./odbcinst -i -d -f /opt/microsoft/msodbcsql/etc/odbcinst.ini
Если вы устанавливали драйвер как было описано выше, то расположение файла odbcinst.ini будет именно таким. Иначе вам нужно определить свой путь. Все эти действия нужно выполнить и на Virtualbox машине и на рабочей.
Теперь нужно собрать Qt плагин для работы с ODBC драйвером. И с этого момента начинаются проблемы, которые частично связаны с багом, который еще не пофиксили. Для того, чтобы собрать плагин придется применить некоторые костыли. Если у кого-то возникнет более элегантный вариант костыля, пожалуйста напишите в комментариях.
Итак, для сборки в штатных условиях нам нужно выполнить простую процедуру. Переходим в QT_DIR/5.9.1/Src/qtbase/src/plugins/sqldrivers/odbc и выполняем:
qmake "INCLUDEPATH+=/usr/local/unixODBC/include" "LIBS+=-L/usr/local/unixODBC/lib -lodbc"
make
make install
Но из-за того, что имеем баг, скорее всего вы получите ошибку:
Cannot read QT_DIR/5.9.1/Src/qtbase/src/plugins/sqldrivers/qtsqldrivers-config.pri: No such file or directory
Project ERROR: Library 'odbc' is not defined.
На отсутствие файла qtsqldrivers-config.pri, можно не обращать внимание, а вот вторая ошибка не даст нам собрать плагин. Чтобы ее избежать нужно закомменитровать в файле odbc.pro строчку:
#QMAKE_USE += odbc
После этого повторим вызов qmake:
qmake "INCLUDEPATH+=/usr/local/unixODBC/include" "LIBS+=-L/usr/local/unixODBC/lib -lodbc"
И получим на выходе Makefile. Еще одна проблема с которой я столкнулся это флаги компилятора -Wdate_time и -std=c++1z, которые вызывали ошибку сборки.
На этот момент я уже потратил много времени, чтобы хоть как-то собрать плагин, поэтому эту проблему я решил жестко, просто открыл сгенерированный Makefile и изменил -std=c++1z на -std=c++11, а флаг -Wdate_time просто удалил. Эти пары флагов встречаются в двух местах. Можно установить более свежий gcc, или может кто-то подскажет есть ли возможность указать для qmake какие-то параметры, чтобы использовать c++11 вместо c++17?
Как бы вы ни поступили, теперь можно выполнить:
make
make install
Плагин собран.
Тестовое приложение
Я создал консольное приложение в Qt и написал следующий код для тестирования соединения:
#include <QCoreApplication>
#include <iostream>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
int main(int argc, char *argv[])
{
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
QString connectionString = "DRIVER={ODBC Driver 13 for SQL Server};Server=<host>\\<instance>,<port>;Uid=<login>;Pwd=<password>";
db.setDatabaseName(connectionString);
if(db.open()) {
std::cout << "Connection succes!" << endl;
return 0;
}else{
std::cout << db.lastError().text().toStdString() << endl;
return 1;
}
}
Собираем проект на Virtualbox машине. Запускаем, убеждаемся, что все работает. После этого собираем Release версию программы. Я не буду сейчас описывать процесс деплоя Qt приложений. Возможно это тема для еще одной публикации. Я опишу лишь ключевые моменты.
Вместе с исполняемым файлом вам потребуются дополнительные библиотеки, которые можно посмотреть с помощью ldd. Так же вам потребуется сам плагин, который вы собрали. Он лежит в моем случае в QT_DIR/5.9.1/gcc_64/plugins/sqldrivers и называется libsqlodbc.so. Его необходимо так же утащить за собой. Библиотеки вы можете положить например в /usr/lib и система их подхватит, а с плагинами дело обстоит несколько по-другому. Есть множество способов сказать Qt от куда загружать плагины. Самый простой — это перед запуском определить переменную окружения QT_PLUGIN_PATH.
Запускаем программу, все должно работать.
Заключение
Хотелось бы услышать комментарии по поводу альтернативных решений данного вопроса. С удовольствием дополню/исправлю этот пост.
Поделиться с друзьями