CodeBlocks學習 如何編譯多個目標
呵,說多個目標,還不如說是如何在一個工程中,編譯不同的動態庫。想想MFC中一個動態庫就是一個工程,當動態庫多的時候,覺得管理不是很好,CodeBlocks支持在一個工程中,可以編譯多個動態庫,以下是我的學習體會。
之所以會有這樣的需求,主要是因爲我在用了ECLIPSE之後,覺得其plugin功能真的很強大,再者,CodeBlocks也是基於plugin框架架構的,所以想具體的學習一下,基於wxWidgets的plugin程序框架設計。
在學習過程中,我發現,一個工程一個庫,這個管理不太方便。於是,就想可不可以在同一個工程中,編譯不同的目標動態庫?經過一番摸索,CodeBlocks可以實現我的需求。以下將方法記錄下來,以備查閱。
- 創建一個wxStudy工程,增加4個文件到工程,
#ifndef WX_MAIN_APP_H
#define WX_MAIN_APP_H
#include <wx/app.h>
class MainApp : public wxApp
{
public:
MainApp();
public:
virtual bool OnInit();
private:
void InitFrame();
};
DECLARE_APP(MainApp)
#endif
#include "mainApp.h"
#include "MainFrame.h"
IMPLEMENT_APP(MainApp)
MainApp::MainApp()
{
}
bool MainApp::OnInit()
{
InitFrame();
return true;
}
void MainApp::InitFrame()
{
MainFrame* pMainFrm = new MainFrame(_T("MainFrame"));
pMainFrm->Show(true);
}
#ifndef MAIN_FRAME_H
#define MAIN_FRAME_H
#include <wx/frame.h>
//#include <wx/wx.h>
class MainFrame : public wxFrame
{
public:
MainFrame(const wxString& strTitle);
private:
void InitCtrl();
private://event
void OnAbout(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
//測試動態庫
void OnShowMessage(wxCommandEvent& event);
private:
DECLARE_EVENT_TABLE()
};
#endif
#include "MainFrame.h"
#include <wx/menu.h>
//#include <wx/string.h>
#include <wx/msgdlg.h>
#include <wx/dynlib.h>
#include <wx/filefn.h>
#include <wx/filename.h>
#include "maindef.h"
//EVENT DECLARE
BEGIN_EVENT_TABLE(MainFrame,wxFrame)
EVT_MENU(wxID_EXIT,MainFrame::OnQuit)
EVT_MENU(wxID_ABOUT,MainFrame::OnAbout)
EVT_MENU(wxID_TEST_DLL,MainFrame::OnShowMessage)
END_EVENT_TABLE()
//END EVENT DECLARE
MainFrame::MainFrame(const wxString& strTitle)
:wxFrame(NULL,wxID_ANY,strTitle)
{
InitCtrl();
}
void MainFrame::InitCtrl()
{
wxMenu* pMenu = new wxMenu();
pMenu->Append(wxID_EXIT,_T("Exit"));
pMenu->Append(wxID_ABOUT,_T("About"));
pMenu->Append(wxID_TEST_DLL,_T("測試動態庫"));
wxMenuBar* pMenuBar = new wxMenuBar();
pMenuBar->Append(pMenu,_T("File"));
SetMenuBar(pMenuBar);
}
/*
* 退出程序
* @param wxCommandEvent& event
*/
void MainFrame::OnQuit(wxCommandEvent& event)
{
Close();
}
void MainFrame::OnAbout(wxCommandEvent& event)
{
wxString strMsg(_T("wxWidgets study."));
wxString strCaption(_T("關於"));
wxMessageBox(strMsg, strCaption, wxOK | wxICON_INFORMATION,this);
//wxMessageBox("Quit program?", "Confirm",wxYES_NO | wxCANCEL, this);
}
void MainFrame::OnShowMessage(wxCommandEvent& event)
{
//wxString dir(wxGetWorkingDirectory());
//wxMessageBox(dir,_T("dir"),wxOK);
wxChar name[MAX_PATH] = {0};
GetModuleFileName(0L, name, MAX_PATH);
//wxMessageBox(name,_T("dir"),wxOK);
wxFileName fname(name);
wxString strPath(fname.GetPath(wxPATH_GET_VOLUME));
wxDynamicLibrary lib;
wxString libfile(strPath << _T("/plugins/msgplugin/msgplugin.dll"));
lib.Load(libfile);
if(!lib.IsLoaded())
{
wxMessageBox(libfile << _T(" load error."),_T("Error"),wxOK | wxICON_ERROR);
return;
}
typedef int (*ShowMessageProc)(const wxString&);
ShowMessageProc ShowMessage = (ShowMessageProc)lib.GetSymbol(_T("ShowMessage"));
if(NULL == ShowMessage)
{
wxMessageBox(_T("don't call the method: ShowMessag"), _T("Error"),
wxOK | wxICON_ERROR);
return;
}
ShowMessage(_T("call from ") + libfile);
}
2.創建動態庫所需要的文件src/plugins/msgplugin/msh.h;src/plugins/msgplugin/msh.cpp
#ifndef MSG_H_INCLUDED
#define MSG_H_INCLUDED
#include "../pluginset.h"
#include <wx/string.h>
BEGIN_EXPORT_LANGUAGE()
int PLUGIN_EXPORT ShowMessage(const wxString& msg);
END_EXPORT_LANGUAGE()
#endif // MSG_H_INCLUDED
#include "msg.h"
#include <wx/msgdlg.h>
int ShowMessage(const wxString& msg)
{
wxMessageBox(msg,_T("msg"));
return 0;
}
3.設置編譯目標 ,File->new -> build target...,如下圖所示:
選擇 Dynamic Link library,編譯動態庫,點GO,next,如下圖:
輸入msgplugin後,點Finish,這樣我們就創建了一個編譯目標,但這還不夠,因爲,還沒有爲此目標增加任何的源文件,接下來,增加源文件。
在工程樹上點右鍵,選擇Properties->Build targets選項卡,如下圖,你會看到我們輸入的編譯目標(debug_msgplugin):
在build target files中,選擇我們的源文件,如下圖:
呵,離成功還差一步了,接下來,我們要做的就是定義__declspec(__dllexport)或是__dllimport,爲什麼了,在工程中,我們增加一個pluginset.h的文件,文件內容如下:
#ifndef PLUGINSET_H
#define PLUGINSET_H
//windows平臺下,動態庫的前輟定義
#ifdef __WXMSW__
#ifndef PLUGIN_EXPORT
#ifdef EXPORT_LIB
#define PLUGIN_EXPORT __declspec(__dllexport)
#else // !EXPORT_LIB
#if BUILDING_PLUGIN
#define PLUGIN_EXPORT __declspec(__dllexport)
#else // !BUILDING_PLUGIN
#define PLUGIN_EXPORT __declspec(__dllimport)
#endif // BUILDING_PULGIN
#endif // EXPORT_LIB
#endif // PLUGIN_EXPORT
#else
#define PLUGIN_EXPORT
#endif
//導出方式是c方式還是c++方式
#ifdef PLUGIN_EXPORT_C
#define BEGIN_EXPORT_LANGUAGE() extern "C" {
#define END_EXPORT_LANGUAGE() }
#else
#define BEGIN_EXPORT_LANGUAGE()
#define END_EXPORT_LANGUAGE()
#endif
#endif // PLUGINSET_H
定義要導出的方法,如下:
#define MSG_H_INCLUDED
#include "../pluginset.h"
#include <wx/string.h>
BEGIN_EXPORT_LANGUAGE()
int PLUGIN_EXPORT ShowMessage(const wxString& msg);
END_EXPORT_LANGUAGE()
#endif // MSG_H_INCLUDED
好了,我們可以編譯了,但是在編譯之前,我們來分析一下,pluginset.h中的定義:
//windows平臺下,動態庫的前輟定義
#ifdef __WXMSW__
#ifndef PLUGIN_EXPORT
#ifdef EXPORT_LIB
#define PLUGIN_EXPORT __declspec(__dllexport)
#else // !EXPORT_LIB
#if BUILDING_PLUGIN
#define PLUGIN_EXPORT __declspec(__dllexport)
#else // !BUILDING_PLUGIN
#define PLUGIN_EXPORT __declspec(__dllimport)
#endif // BUILDING_PULGIN
#endif // EXPORT_LIB
#endif // PLUGIN_EXPORT
#else
#define PLUGIN_EXPORT
#endif
……如果定義了BUILDING_PLUGIN,則以動態庫的方式導出……
//導出方式是c方式還是c++方式
#ifdef PLUGIN_EXPORT_C
#define BEGIN_EXPORT_LANGUAGE() extern "C" {
#define END_EXPORT_LANGUAGE() }
#else
#define BEGIN_EXPORT_LANGUAGE()
#define END_EXPORT_LANGUAGE()
#endif
如果定義了PLUGIN_EXPORT_C,則以C的方式輸出
所以,我們還要在設置一下編譯器的選項,如下:點右鍵->properties->build target -> build options ,如下圖,選擇debug_msgplugin在#defines中,輸入 BUILDING_PLUGIN,PLUGIN_EXPORT_C,好的,至此爲止,我們的動態庫就可以編譯了
編譯,如下圖:選擇debug_msgplugin
接着build就可以了