記錄一次從MinGw轉到MSVC編譯器的錯誤經歷
MinGW和MSVC相容度並不那麼好,由於中文的問題,sa一直使用的是MinGW來進行編譯,但說實話,在windows上MinGW編譯出來的程式在體積和速度上和MSVC還是有點差距的,因此,sa最終版打算使用msvc編譯器。
於是,前幾天用Qt5.9 MSVC2015版進行了一下編譯結果發現了許多問題,有語法的問題,也有非常討厭的連結問題。
下面是一些記錄:
-
MinGW比MSVC寬鬆很多,類似於需要返回值得函式,如果不返回值MinGW不會產生錯誤,只會進行警告,MSVC則會直接報錯
-
編寫庫時,模板類是不能匯出的,我在編寫時並沒留意這點,模板類也進行了匯出,MSVC會報錯,MinGW毫無提示直接忽略,這點MSVC貌似處理更合理
然後遇到了該死的連結問題,首先遇到了莫名其妙的重定義問題error LNK2005
:
- 在連結上原本能通過MinGW成功連結,但在MSVC卻出現了
error LNK2005
錯誤,sa使用的繪圖引擎是qwt
,在signACommonUI
庫中定義瞭如下函式:
完整程式碼見:master/src/signACommonUI/Chart2D/SAFigureOptCommands.h 的SAFigureReplaceSeriesDataInIndexsCommand
template<typename T,typename TQwtSeries>
class SAFigureReplaceSeriesDataInIndexsCommand : public SAFigureOptCommand
{
public:
SAFigureReplaceSeriesDataInIndexsCommand(SAChart2D* chart
,QwtSeriesStore<T> *curve
,const QString &cmdName
,const QVector<int >& inRangIndexs
,const QVector<T>& inRangNewData
, QUndoCommand *parent = Q_NULLPTR);
SAFigureReplaceSeriesDataInIndexsCommand(SAChart2D* chart
,QwtSeriesStore<T> *curve
,const QString &cmdName
,const QVector<int>& inRangIndexs
,const QVector<T>& inRangOldData
,const QVector<T>& inRangNewData
, QUndoCommand *parent = Q_NULLPTR);
virtual void redo();
virtual void undo();
private:
QVector<T> m_inRangOldData;
QVector<int> m_inRangIndexs;
QVector<T> m_inRangNewData;
QwtSeriesStore<T> *m_curve;
};
...
///
/// \brief 序列資料QPointF的替換
///
class SA_COMMON_UI_EXPORT SAFigureReplaceXYSeriesDataInIndexsCommand
: public SAFigureReplaceSeriesDataInIndexsCommand<QPointF,QwtPointSeriesData>
{
public:
using SAFigureReplaceSeriesDataInIndexsCommand::SAFigureReplaceSeriesDataInIndexsCommand;
};
///
/// \brief 序列資料QwtPlotMultiBarChart的替換
///
class SA_COMMON_UI_EXPORT SAFigureReplaceMultiBarSeriesDataInIndexsCommand
: public SAFigureReplaceSeriesDataInIndexsCommand<QwtSetSample,QwtSetSeriesData>
{
public:
using SAFigureReplaceSeriesDataInIndexsCommand::SAFigureReplaceSeriesDataInIndexsCommand;
};
連結錯誤提示:
qwtd.lib(qwtd.dll) : error LNK2005: "public: void __thiscall QwtSeriesStore<class QwtSetSample>::setData(class QwtSeriesData<class QwtSetSample> *)" ([email protected][email protected]@@@@[email protected]@@@@@Z) 已經在 SAFigureOptCommands.obj 中定義
....
這裡所有呼叫QwtSeriesStore的
setData`處都有連結錯誤提示
看提示就是重定義了QwtSeriesStore<class QwtSetSample>::setData
函式,這個函式在模板類的redo()
函式裡呼叫:
template<typename T,typename TQwtSeries>
void SAFigureReplaceSeriesDataCommand<T,TQwtSeries>::redo()
{
......
m_curve->setData(new TQwtSeries(curveDatas));
}
完整程式碼見:SAFigureOptCommands.h 的SAFigureReplaceSeriesDataInIndexsCommand
說明編譯器認為我又定義過QwtSeriesStore<class QwtSetSample>::setData
函式,看一下資訊,說的是qwtd.lib
中的QwtSeriesStore
的setData
函式在我寫的這個類之後編譯的,也就是說,編譯器先編譯了我寫的這個類,再去看qwtd.lib
發現有重複符號。
解決方法就是引用qwtd.lib
含有這些例項化模板的類的標頭檔案,讓編譯器知道,這些模板的例項化已經在qwtd.lib
中存在了。
終於是把signACommonUI
庫編譯完成,接下來到主程式signA
,結果又有連結錯誤:LNK2019
和LNK2001
mainwindow.obj:-1: error: LNK2019: 無法解析的外部符號 "__declspec(dllimport) public: __thiscall SAWaitCursor::SAWaitCursor(void)" ([email protected]@[email protected]),該符號在函式 "private: void __thiscall MainWindow::initPlugin(void)" ([email protected]@@AAEXXZ) 中被引用
SAChartDatasViewWidget.obj:-1: error: LNK2001: 無法解析的外部符號 "__declspec(dllimport) public: __thiscall SAWaitCursor::SAWaitCursor(void)" ([email protected]@[email protected])
一看就是編譯器沒找到SAWaitCursor
,具體程式碼見:master/src/signACommonUI/SAWaitCursor.h和master/src/signACommonUI/SAWaitCursor.cpp
在你看到之前其實只有一個頭檔案:
class SA_COMMON_UI_EXPORT SAWaitCursor
{
public:
SAWaitCursor()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
~SAWaitCursor()
{
QApplication::restoreOverrideCursor();
}
void setWaitCursor()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
void setCursor(const QCursor cur = QCursor(Qt::WaitCursor))
{
QApplication::setOverrideCursor(cur);
}
void release()
{
QApplication::restoreOverrideCursor();
}
};
#ifndef SA_SET_AUTO_WAIT_CURSOR
#define SA_SET_AUTO_WAIT_CURSOR() \
SAWaitCursor __sa__wait__cursor;\
Q_UNUSED(__sa__wait__cursor);
#endif
略一思索,可能是沒有cpp導致的問題,於是新建對應的cpp檔案,並把在標頭檔案實現的內容寫到cpp中,編譯出來的lib和原來的大小居然也不一樣,這樣順利完成了signA的編譯