zoukankan      html  css  js  c++  java
  • [原创]用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练习的深入
    在上一步生成了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(5050),
                                      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

    参考资料:
    1、CMake文档
    2、CMake实践.pdf
    3、http://bbs.osgchina.org/viewthread.php?tid=1189 
         http://bbs.osgchina.org/viewthread.php?tid=1229  

  • 相关阅读:
    学习python第二天数据库day1
    学习python第一天总纲
    Mac 键盘快捷键
    报错 Filtered offsite request
    mysql 顺序问题
    implode 把数组 组成一个字符串
    TP view中跳转到某个控制器
    生成商品的唯一货号
    数组排序
    判断文件是否存在 删除文件
  • 原文地址:https://www.cnblogs.com/ode/p/2147089.html
Copyright © 2011-2022 走看看