CMake使用方法

用MinGW和CMake搭建便捷的C/C++开发环境(二)

七、CMake练习
准备工作:在E盘新建一个文件夹cmakeproj,作为工程目录,
在cmakeproj文件夹中,建立src文件夹,用来存放源代码;建立build文件夹,用来构建我的应用程序;
在cmakeproj文件夹中,新建CMakeList.txt文件,我用工程根目录中的CMakeList.txt文件做以下几件事情:
1、指定CMake的最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 
2、设定项目名称

PROJECT(CMakeProj)
3、指定子目录
ADD_SUBDIRECTORY(src)
这里还应当了解两个重要的变量${PROJECT_SOURCE_DIR}和${PROJECT_BINARY_DIR},他们分别是项目源代码目录和项目输出目录,可以用MESSAGE指令输出。
MESSAGE(STATUS "源码目录:" ${PROJECT_SOURCE_DIR})
MESSAGE(STATUS "编译目录:" ${PROJECT_BINARY_DIR})

4、在src文件夹中,建立mylibs和myapps文件夹
在mylibs中,建立mylib.cpp和mylib.h文件,代码如下:

复制代码
mylib.h
// ----------------------------------------------------------------------------------------------------
#ifndef _MYLIB_H
#define  _MYLIB_H

class  MyLib{
public :
 
void  DoSomething();
};

#endif
// ----------------------------------------------------------------------------------------------------
mylib.cpp
// ----------------------------------------------------------------------------------------------------
#include  " mylib.h "
#include 
< iostream >

void  MyLib::DoSomething() {
   std::cout 
<<   " hi~! 我是一条来自MyLib中DoSomething的消息 "   <<  std::endl;
}
// ----------------------------------------------------------------------------------------------------
复制代码

在mylibs文件夹中的CMakeLists.txt文件中写CMake指令:
ADD_LIBRARY(mylibs mylib)

ADD_LIBRARY指令的第一个参数为库文件的名称,这里指定为mylibs,将来make之后,会生成一个名称为libmylibs.a的库文件,第二个参数为源码,可以只写文件名mylib,也可以写mylib.h空格mylib.cpp,如果头文件和源文件的名称一致简写为mylib就可以了。
5、在myapps文件夹中,建立myapp.cpp文件

复制代码
myapp.cpp

#include 
< iostream >
#include 
" mylib.h "

int  main( int  argc,  const   char   * argv[])
{
 MyLib.DoSomething();
 
return   0 ;
}
复制代码

在myapps文件夹中的CMakeLists.txt文件中写CMake指令:
告诉编译器共享库的位置:
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/mylibs)
根据myapp.cpp源文件生称名称为exename的可执行文件:exename.exe
ADD_EXECUTABLE(exename myapp.cpp)
链接可执行文件需要的动态库文件libmylibs.a
TARGET_LINK_LIBRARIES(exename mylibs)

6、构建
在build文件夹中:cmd:cmake –G”MinGW Makefiles” ..  在build文件夹中已经生成了我需要的Makefie,
接下来cmd:mingw32-make
在build文件夹的src文件夹中的myapps文件夹中,成功的生成了名称为exename.exe的可执行文件,在build文件夹的src文件夹中的mylibs文件夹中生成了libmylib.a文件。

CMake使用方法_第1张图片

 

八、CMake练习的深入
在上一步生成了exe文件后,还是有很多不如意的地方,例如exe文件生成的目录并不是我想要的等等等等。还需要对我的构建进行改进。
1、改变目标二进制的输出目录
在工程根目录中的CMakeList.txt文件中增加指令:
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
2、增加版本号
SET(${PROJECT_NAME}_MAJOR_VERSION 0)
SET(${PROJECT_NAME}_MINOR_VERSION 1)
SET(${PROJECT_NAME}_PATCH_LEVEL 0)
但我设置后,在windows中并没有看到效果。去公司在linux下看看。
3、生成共享库
修改src/mylibs/中的CMakeLists.txt文件
ADD_LIBRARY(mylibs SHARED mylib)
ADD_LIBRARY的参数形式为:ADD_LIBRARY (库名称 库类型 源文件)
只需要增加参数SHARED就可以了,在make之后,build/lib/中可生成mylibs.dll文件。
如果想同时生成静态库和共享库,如何实现?

 

九、使用其他库文件
建立一个目录,用来存放一些常用的库(e:/cpplibs)。
(一)sqlite
从最简单的sqlite开始。在E盘建目录cpplibs,在cpplibs文件夹中建立sqlite目录,在sqlite中建立include和lib文件夹,分别存放sqlite3.h文件和libsqlite3.a文件。
在myapps文件夹中的CMakeLists.txt文件中增加:
INCLUDE_DIRECTORIES(d:/cpplibs/sqlite/include)
LINK_DIRECTORIES(d:/cpplibs/sqlite/lib)
TARGET_LINK_LIBRARIES(exename sqlite3 mylibs)
告诉编译器到哪里去找sqlite的头文件和库,连接sqlite3的库文件。
运行cmake和mingw32-make,sqlite3的应用程序可以正常运行了。但是在上面到处写类似d:/cpplibs/sqlite/include这样的路径,如果cpplibs名称改变了,那就太致命了。在项目根目录的CMakeLists.txt文件中定义一个变量:
SET(SQLITE3_BASE d:/cpplibs/sqlite)
将上面两行CMake指令修改为:
INCLUDE_DIRECTORIES(${SQLITE3_BASE}/include)
LINK_DIRECTORIES(${SQLITE3_BASE}/lib)
这样看起来好多了。再次编译时,只要修改一下变量SQLITE3_BASE的值就可以了。

(二)MySQL++
1、定义两个变量MYSQL_BASE和MYSQLPP_BASE,分别存放mysql和mysql++的位置,在myapps文件夹中的CMakeLists.txt文件中增加:
SET(MYSQL_BASE "C:/Program Files/MySQL/MySQL Server 5.1")
SET(MYSQLPP_BASE "E:/MySQL++")
因为CMakeLists.txt的语法是以空格区分参数是否结束的,所以路径加了引号,在CMake的语法中,加不加引号其实都没有关系,但如果值中有空格或分号“;”,还是需要加引号。
2、源码目录(这里是myapps)的CMakeLists.txt文件修改为:

#INCLUDE_DIRECTORIES
#告诉编译器共享库的位置:
#sqlite mysql mysql++
INCLUDE_DIRECTORIES("${SQLITE3_BASE}/include" "${MYSQL_BASE}/include" "${MYSQLPP_BASE}/include")

#LINK_DIRECTORIES
#告诉外部依赖库的搜索路径
#sqlite mysql mysql++
LINK_DIRECTORIES("${SQLITE3_BASE}/lib" "${MYSQLPP_BASE}/lib" "${MYSQL_BASE}/lib")

最后别忘了告诉编译器mysqlpp的依赖项
TARGET_LINK_LIBRARIES(${PROJECT_NAME} "${MYSQLPP_BASE}/lib/libmysqlpp.a")

开始写一些代码试试看,已经可以很顺利的make了。

复制代码
#include  < cstdlib >
#include 
< cstdio >
#include 
< iostream >
#include 
< sqlite3.h >

#include 
< mysql ++ .h >

#include 
" mylib.h "

using   namespace  std;

//  sqlite callback
static   int  callback( void   * NotUsed,  int  argc,  char   ** argv,  char   ** azColName){
  
int  i;
  
for (i = 0 ; i < argc; i ++ ){
    printf(
" %s = %s\n " , azColName[i], argv[i]  ?  argv[i] :  " NULL " );
  }
  printf(
" \n " );
  
return   0 ;
}
//  end sqlite callback


int  main( int  argc,  const   char   * argv[])
{
    
//  mylib
    MyLib().DoSomething();
    
    
//  sqlite
    sqlite3  * db;
    
char   * zErrMsg  =   0 ;
    
int  rc;
    
    
char  sql[ 1024 ] = "" ;
    sprintf(sql, 
" SELECT * FROM table1; " );

    rc 
=  sqlite3_open( " test.db " & db);
    
if  (rc)
    {
       fprintf(stderr, 
" Can't open database: %s\n " , sqlite3_errmsg(db));
       sqlite3_close(db);
       system(
" PAUSE " );
       exit(
1 );
    }
  
    rc 
=  sqlite3_exec(db, sql, callback,  0 & zErrMsg);
    
if  ( rc != SQLITE_OK )
    {
        fprintf(stderr, 
" SQL error: %s\n " , zErrMsg);
    }
    sqlite3_close(db);
    
//  end sqlite

    
//  mysql
    mysqlpp::Connection con( false );

    con.set_option(
new  mysqlpp::SetCharsetNameOption( " gbk " ));

    cout 
<<   " 请输入数据库(root用户)连接密码: " ;
    
string  pwd;
    getline(cin, pwd);

    
if  ( ! con.connect( " mytable " " localhost " " root " , pwd.c_str()))
    {
        cout 
<<   " 无法连接,请检查密码是否正确! "   <<  endl;
        
return   - 1 ;
    }
    
else
    {
        cout 
<<   " shit.终于连上了。 "   <<  endl;
        mysqlpp::Query query 
=  con.query( " select mycol from firsttable " );
        
if  (mysqlpp::StoreQueryResult res  =  query.store()) {
            cout 
<<   " We have: "   <<  endl;
            mysqlpp::StoreQueryResult::const_iterator it;
            
for  (it  =  res.begin(); it  !=  res.end();  ++ it) {
                mysqlpp::Row row 
=   * it;
                cout 
<<   ' \t '   <<  row[ " mycol " <<  endl;
                
//  或者使用列索引
                
// cout << '\t' << row[0] << endl;
            }
        }
        
else  {
            cerr 
<<   " Failed to get mycol list:  "   <<  query.error()  <<  endl;
            
return   1 ;
        }
    }
    
//  end mysql


    system(
" PAUSE " );
    
return  EXIT_SUCCESS;
}
复制代码

(三)wxWidgets
在myapps的CMakeLists.txt文件中:
#wxWidgets
#MinGW 对库的顺序是有要求的,这一点很重要
FIND_PACKAGE(wxWidgets REQUIRED)
INCLUDE(${wxWidgets_USE_FILE})

之后:
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${wxWidgets_LIBRARIES})

下面修改myapp.cpp的代码,写一个wxWidgets的hello world,wxFrame窗口已经呈现在眼前。

myapp.cpp的代码就是wxWidgets官方网站的helloword:

复制代码
/*
 * hworld.cpp
 
*/

#include 
" wx/wx.h "  

class  MyApp:  public  wxApp
{
    
virtual   bool  OnInit();
};

class  MyFrame:  public  wxFrame
{
public :

    MyFrame(
const  wxString &  title,  const  wxPoint &  pos,  const  wxSize &  size);

    
void  OnQuit(wxCommandEvent &   event );
    
void  OnAbout(wxCommandEvent &   event );

    DECLARE_EVENT_TABLE()
};

enum
{
    ID_Quit 
=   1 ,
    ID_About,
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_Quit, MyFrame::OnQuit)
    EVT_MENU(ID_About, MyFrame::OnAbout)
END_EVENT_TABLE()

IMPLEMENT_APP(MyApp)

bool  MyApp::OnInit()
{
    MyFrame 
* frame  =   new  MyFrame( _( " Hello World " ), wxPoint( 50 50 ),
                                  wxSize(
450 , 340 ) );
    frame
-> Show( true );
    SetTopWindow(frame);
    
return   true ;


MyFrame::MyFrame(
const  wxString &  title,  const  wxPoint &  pos,  const  wxSize &  size)
: wxFrame( NULL, 
- 1 , title, pos, size )
{
    wxMenu 
* menuFile  =   new  wxMenu;

    menuFile
-> Append( ID_About, _( " &About... " ) );
    menuFile
-> AppendSeparator();
    menuFile
-> Append( ID_Quit, _( " E&xit " ) );

    wxMenuBar 
* menuBar  =   new  wxMenuBar;
    menuBar
-> Append( menuFile, _( " &File " ) );

    SetMenuBar( menuBar );

    CreateStatusBar();
    SetStatusText( _(
" Welcome to wxWidgets! " ) );
}

void  MyFrame::OnQuit(wxCommandEvent &  WXUNUSED( event ))
{
    Close(TRUE);
}

void  MyFrame::OnAbout(wxCommandEvent &  WXUNUSED( event ))
{
    wxMessageBox( _(
" This is a wxWidgets Hello world sample " ),
                  _(
" About Hello World " ),
                  wxOK 
|  wxICON_INFORMATION,  this );
}
复制代码

编译,运行。

 

总结:

      以前喜欢用vc,vs,但vs越来越庞大,每一次的安装都有如梦魇,相信很多朋友和我一样都有同样的感受。为了有一个轻便的环境,我逐渐转移到Devc++,再到CodeBlocks,但总是会遇到这样或那样的问题没有办法解决。我知道这并不是IDE的问题,而是我不知如何解决。
      当然我并不是反对使用IDE,我本人也很依赖IDE。人类之所以发明工具,是因为工具可以提高生产效率。上面提到的这些IDE都是极品,尤其Visual studio,是我认为最强大的开发工具,确切的说是C#最强大的开发工具,我甚至一度认为没有其他的开发工具可以超越它,即便如此,我还是想知道在vs强大的背后到底是什么?现在我似乎知道了一些:-)。

      学习和使用CMake,开始入手时比较困难,但我才经过总共不超过20个小时的学习,已经基本可以开始用CMake来完成大多数的日常工作了。但是还有一些迷惑,总不能不停的在命令行中敲命令吧,刚开始熟悉命令时多敲几次还过得去,命令已经非常熟悉了,而且使用频率也很高,不停的敲那也太麻烦了,在第三篇学习记录中解决这个问题,地址在这里:

来源:http://www.cnblogs.com/ode/archive/2011/08/04/2152251.html


你可能感兴趣的:(图像处理,科学计算,算法,sqlite,library,mysql,include,编译器,开发工具)