Russian Qt Forum

Компиляторы и платформы => Компиляторы => Тема начата: Николай от Июнь 28, 2016, 17:06



Название: Миграция с MinGW на MSVC2015
Отправлено: Николай от Июнь 28, 2016, 17:06
Добрый день всем!
Пытаюсь перевести  проект (динамическую библиотеку) с MinGW на MSVC2015.

На MinGW никаких проблем не было.
На MCVC2015 при сборке сыпется предупреждениями и ошибками:

Цитировать
предупреждение: C4190: 'getVersion' has C-linkage specified, but returns UDT 'QString' which is incompatible with C
предупреждение: C4190: 'selectDates4Report' has C-linkage specified, but returns UDT 'QStringList' which is incompatible with C

ошибка: C2526: 'selectDepts': C linkage function cannot return C++ class 'QList<QList<QString>>'
предупреждение: C4190: 'drawGraph' has C-linkage specified, but returns UDT 'QImage' which is incompatible with C

.pro
Код:
greaterThan(QT_MAJOR_VERSION, 4) {
  QT += widgets
  DEFINES += HAVE_QT5
}
TEMPLATE =  lib
TARGET   =  rsrcs
QT += sql network
CONFIG   += shared dll plugin

DEFINES  += D_SHARED_LIB
SOURCES  =  src/rsrcs.cpp

HEADERS  =  src/rsrcs.h


DESTDIR  =  ../../core/bin/


OBJECTS_DIR = build/
MOC_DIR = build/
RCC_DIR = build/

TRANSLATIONS += ../../core/bin/l10n/rsrsc_ru.ts
message($$DEFINES)


.h
Код:

#include <QtGlobal>
#include <QtCore>
#include <QDebug>


//---minGW
/*#ifdef D_SHARED_LIB
        #define D_SHARED_LIB_EXPORT Q_DECL_EXPORT
#else
        #define D_SHARED_LIB_EXPORT Q_DECL_IMPORT

#endif
*/
//---msvc

#ifdef D_SHARED_LIB
        #define D_SHARED_LIB_EXPORT __declspec(dllexport)
#else
        #define D_SHARED_LIB_EXPORT __declspec(dllimport)
#endif


//SHARED FUNCTIONS_______________________________________________________________________
extern "C" D_SHARED_LIB_EXPORT const QString getVersion();

extern "C" D_SHARED_LIB_EXPORT const QStringList selectDates4Report(QWidget *parent);

extern "C" D_SHARED_LIB_EXPORT const QList< QList<QString> > selectDepts(const QStringList &connectionParameters, bool multiSelection, bool showDeletedItems, int id_firm, QWidget *parent, Qt::WindowState state);
extern "C" D_SHARED_LIB_EXPORT const QList< QList<QString> > selectPosts(const QStringList &connectionParameters,  bool multiSelection, bool showDeletedItems, int id_firm, int id_dept, QWidget *parent, Qt::WindowState state);
extern "C" D_SHARED_LIB_EXPORT QImage drawGraph(const QStringList &names,const QList<double> &values,int itemsLimit);




Прошу помощи. Буду рад любой полезной информации


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: ssoft от Июнь 28, 2016, 17:39
extern "C" явно лишняя, так как в чистом Си отсутствуют шаблоны и классы.
MinGW игнорирует эту запись, а MSVC - нет.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Николай от Июнь 29, 2016, 14:11
extern "C" явно лишняя, так как в чистом Си отсутствуют шаблоны и классы.
MinGW игнорирует эту запись, а MSVC - нет.


https://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application/ru (https://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application/ru)

Цитировать
QLibrary может использоваться для загрузки разделяемых библиотек в момент выполнения. В этом случае достаточно иметь доступ только к .dll, доступ к заголовкам и .lib файлу(ам) не требуется.

Следующий пример показывает, как установить библиотеку для использования с QLibrary. Для разрешения имен функций, они должны быть экспортированы из библиотеки как C функции (т.е. без искажения имени). Это означает, что функции должны быть обернуты в блок extern "C", в случае если библиотека скомпилирована компилятором C.


Или это к MSVC не относится, так это C++, а не C?


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Igors от Июнь 29, 2016, 14:58
extern "C" нужно если Вы хотите сами находить/дергать ф-ции по имени (в примере library.resolve("createWidget1").
Обычно необходимости в этом нет. Убираете extern C и просто компилите библиотеку. Получаете (помимо dll) небольшой lib файл (фактически обертку), вот его подключаете к проекту который использует либу.

Цитировать
предупреждение: C4190: 'selectDates4Report' has C-linkage specified, but returns UDT 'QStringList' which is incompatible with C
Такие предупреждения надо все убрать, обычно они означают crash на выполнении


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Old от Июнь 29, 2016, 16:36
extern "C" нужно если Вы хотите сами находить/дергать ф-ции по имени (в примере library.resolve("createWidget1").
Нет. extern "C" указывает компилятору использовать сишный манглинг имен, вместо плюсового (в котором кодируются и аргументы).
Находить и дергать можно любые экспортируемые функции, что сишные, что плюсовые.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Николай от Июнь 29, 2016, 17:05
extern "C" нужно если Вы хотите сами находить/дергать ф-ции по имени (в примере library.resolve("createWidget1").
Обычно необходимости в этом нет. Убираете extern C и просто компилите библиотеку. Получаете (помимо dll) небольшой lib файл (фактически обертку), вот его подключаете к проекту который использует либу.

Цитировать
предупреждение: C4190: 'selectDates4Report' has C-linkage specified, but returns UDT 'QStringList' which is incompatible with C
Такие предупреждения надо все убрать, обычно они означают crash на выполнении

Спасибо за совет, но я использую QLibrary для загрузки этой разделяемой библиотеки вот таким образом:
Цитировать
QLibrary lib(qApp->applicationDirPath()+QDir::separator()+"rsrcs");
if(lib.load())
{
            typedef const QList <QList<QString> > (*MyClass)(const QStringList &,bool,bool,int,QWidget *,Qt::WindowState);
            MyClass myFunction = (MyClass) lib.resolve("selectDepts");
            if(myFunction)
            {...}
}

И если убрать extern "C" функция просто не вызывается, т.е.  lib.resolve("selectDepts") не находит указанную процедуру  :(


можно ли как-то заставить MSVC не ругаться на QList<QList<QString>> и на возврат результата формате QImage в функции drawGraph?
Цитировать
C linkage function cannot return C++ class 'QList<QList<QString>>

Цитировать
'drawGraph' has C-linkage specified, but returns UDT 'QImage' which is incompatible with C

Подскажите, как правильно писать такие вещи?


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: kuzulis от Июнь 29, 2016, 18:33
Эмм... для этих целей используют плагины.



Название: Re: Миграция с MinGW на MSVC2015
Отправлено: kai666_73 от Июнь 30, 2016, 01:20
Вах  :o
Kaкие нафиг QLibrary, какие плагины?

Igors верно глаголит...

Случай простейший - есть все необходимые исходники.
Все что нужно - это собрать библиотеку с необходимыми экспортируемыми функциями и использовать эту библиотеку без всяких выкрутасов. Соответственно, все extern "С" из библиотеки надо повыпиливать, а мудренные вызывы библиотечных функций заменить просто вызовами...


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Old от Июнь 30, 2016, 05:56
Kaкие нафиг QLibrary, какие плагины?

Все что нужно - это собрать библиотеку с необходимыми экспортируемыми функциями и использовать эту библиотеку без всяких выкрутасов.
А если реализаций этих функций несколько и для работы нужно загружать определенную, в зависимости от каких-то параметров?

Вот у ТС похоже такая ситуация (судя по первой функции getVersion). К сожалению ему нужно для msvc, а опускаться до этого нет никакого желания. Возможно, проще будет действительно реализовать это как систему плагинов, которые экспортируют единственную функцию, конструирующую объект и возвращающую указатель на него. А все эти функции будут методами.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: kuzulis от Июнь 30, 2016, 08:23
Цитировать
Kaкие нафиг QLibrary, какие плагины?

1. Если грузить нужно динамически либу - в этом случае лучше именно плагины.
2. Если можно не грузить при помощи QLibrary, а линковатся - в этом случае достаточно import/export без всяких extern C.

PS: Как-бы ТС упоминал только о QLibrary => 1й вариант предпочтительнее... о линковке речи не было.





Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Николай от Июнь 30, 2016, 08:39
Kaкие нафиг QLibrary, какие плагины?

Все что нужно - это собрать библиотеку с необходимыми экспортируемыми функциями и использовать эту библиотеку без всяких выкрутасов.
А если реализаций этих функций несколько и для работы нужно загружать определенную, в зависимости от каких-то параметров?

Вот у ТС похоже такая ситуация (судя по первой функции getVersion). К сожалению ему нужно для msvc, а опускаться до этого нет никакого желания. Возможно, проще будет действительно реализовать это как систему плагинов, которые экспортируют единственную функцию, конструирующую объект и возвращающую указатель на него. А все эти функции будут методами.

Именно так. Я портирую проект с Qt 4.8 на Qt 5.7. С MinGW проблем не было ни на windows, ни на linux. Но в проекте кое-где использовался QHttp, который в Qt5x выпилили, а WebEngine не поддерживается MinGW. Отсюда и необходимость перехода с MinGW на MSVC2015.
В проекте итак используется плагинная система. есть основное ядро и есть плагины. Функции данной библиотеки должны дергаться и ядром и плагинами. Поэтому и вынесены в отдельную dll. А вызывать из плагина другой плагин как-то не эстетично же).

Вот здесь описан же способ Using QLibrary to load the shared library
http://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application (http://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application)
и пока сидел на mingw все работало как надо. И в чем сейчас затык с mcvc2105 не могу понять  :(


Цитата: Old
К сожалению ему нужно для msvc, а опускаться до этого нет никакого желания
А чем плох этот C++ компилятор из Visual Studio 2015? И какие есть альтернативы тогда?


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Racheengel от Июнь 30, 2016, 09:07
У нас в заголовках дллок используется такое решение:

#if defined _MSC_VER || defined __MINGW32__ || defined __MINGW64__
   #define I_FUNCTION_EXPORT __declspec(dllexport)
#elif defined __GNUC__
   #define I_FUNCTION_EXPORT __attribute__ ((visibility("default")))
#else
   #define I_FUNCTION_EXPORT
#endif

И каждый класс помечается как I_FUNCTION_EXPORT.

Но вообще  __declspec(dllexport) это грязный хак от микрософта, по хорошему компилятор должен сам понимать, что экспортировать, а что нет.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Igors от Июнь 30, 2016, 09:12
Спасибо за совет, но я использую QLibrary для загрузки этой разделяемой библиотеки вот таким образом:
Цитировать
QLibrary lib(qApp->applicationDirPath()+QDir::separator()+"rsrcs");
if(lib.load())
{
            typedef const QList <QList<QString> > (*MyClass)(const QStringList &,bool,bool,int,QWidget *,Qt::WindowState);
            MyClass myFunction = (MyClass) lib.resolve("selectDepts");
            if(myFunction)
            {...}
}

И если убрать extern "C" функция просто не вызывается, т.е.  lib.resolve("selectDepts") не находит указанную процедуру  :(
Ну хорошо, допустим надо "только так" (по имени). Тогда вместо selectDepts надо подставить "mangled" имя. Откомпилите dll (без extern C) и посмотрите список экспортируемых ф-ций напр с помощью depends.exe. Там должно быть какое-то калечное/накрученое, но содержащее selectDepts - вот его и подставьте в resolve

Это конечно коряво, но иначе надо менять вызовы чтобы не было возврата структур, напр так
Код
C++ (Qt)
extern "C" D_SHARED_LIB_EXPORT void selectDepts2(QList< QList<QString> > & outList,
const QStringList &connectionParameters,... )
{
 outList = selectDepts(connectionParameters..);
}
 
Что не смертельно (хотя и неприятно)

Подскажите, как правильно писать такие вещи?
Насколько помню, стандарт не регламентирует поведение определяемое типом линковки, т.е. MSVC имеет право на свою реализацию/правила.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Old от Июнь 30, 2016, 09:14
Функции данной библиотеки должны дергаться и ядром и плагинами. Поэтому и вынесены в отдельную dll.
Тогда вы их можете оформить как экспортируемые и подключать эту библиотеку как я ядру, так и к плагинам. Никакой ручной загрузки и поиска точек входа не понадобиться.

А вызывать из плагина другой плагин как-то не эстетично же).
Посмотрите на QtCreator. :)

А чем плох этот C++ компилятор из Visual Studio 2015? И какие есть альтернативы тогда?
Тем, что он не умеет в современный C++ и вообще кладет на стандарты.
А альтернативы те-же - MinGW или еще можно интеловский компилятор попробовать.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Racheengel от Июнь 30, 2016, 10:49
Интел дорого, МинГВ медленный и капризный.
Студия экспресс довольно быстрая и оптимирует неплохо.
И с++11 она понимает.


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Old от Июнь 30, 2016, 11:18
И с++11 она понимает.
Ну слава Богу... 2016 год на дворе. :)


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: kai666_73 от Июнь 30, 2016, 12:17
А теперь Old истину глаголит.
Линкуйте библиотеку к основному коду и к плагинам, которые ее используют; и будет вам счастье  :)


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Igors от Июнь 30, 2016, 13:18
Линкуйте библиотеку к основному коду и к плагинам, которые ее используют; и будет вам счастье  :)
Цитировать
Грузите апельсины бочками
Братья Карамазовы


Название: Re: Миграция с MinGW на MSVC2015
Отправлено: Akon от Июль 15, 2016, 15:03
...
Но вообще  __declspec(dllexport) это грязный хак от микрософта, по хорошему компилятор должен сам понимать, что экспортировать, а что нет.
А это очевидно? Допустим, длл имеет файл 'unit1.c', в котором есть пара функций
Код:
int foo_public() { return 0; }
static int foo_private() { return 0; }
Первая будет доступна другим модулям этой длл, вторая - нет, и с ней все очевидно - это приватная функция в либе. Далее уже перед линкером встает вопрос - делать ли первую функцию экспортируемой из самой длл или нет? Насколько я помню, gcc по-умолчанию отвечает да.

__declspec(dllimport) также служит для оптимизации - генерирует более эффективный косвенный вызов в одну инструкцию
Код:
call DWORD PTR __imp_foo_public  ; __imp_foo_public - слот в секции импорта приложения