在linux下完成一個GNU風格的程序

最近須要在linux下完成項目編碼,所以記錄一下編碼心得。(選擇ubuntu14.04版本,04表明穩定版本,amd64表明64位,本文使用163源)linux

-------------------------------------------------------------------------------------------ios

計劃:算法

1.完成GNU風格helloworld。ubuntu

2.熟悉libconfig庫,完成參數解析。segmentfault

3.完成單例模式,封裝算法功能數據結構

4.熟悉libevent庫,並添加事件響應。函數

-------------------------------------------------------------------------------------------工具

1.GNU風格,命令行程序hello測試

如何寫一個 GNU 風格的命令行程序: https://segmentfault.com/a/1190000004321899this

Automake的標準工程組織 :http://blog.csdn.net/sufwei/article/details/50515873

本文參考了上述2篇較爲經典的文章,操做步驟以下。

autotools是一系列的編譯工具,可用過一句指令來安裝它們。

>sudo apt-get install autoconf

驗證:which aclocal,which autoscan,which autoconf,which autoheader,which automake。若是都有具體的路徑返回,則安裝成功。

a)創建根文件夾,~/DP/,創建project文件夾存放工程代碼。通常來講,應該添加下面這些目錄文件。

(1) 必選:
m4: 第三方或本身寫的用於configure.in中的宏
doc: 各類文檔
src: 源碼頂層目錄(裏面怎麼細分是本身的事)
config: 放置configure過程當中的一些文件,使得頂層目錄不那麼多文件

>mkdir src doc config m4

編碼文件,configure.ac

dnl Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(Eproxy,1.0,watch_ch@163.com)
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([config])

AM_INIT_AUTOMAKE([foreign -Wall])
AC_PROG_CC
AC_PROG_CXX

PKG_CHECK_MODULES(WHEEL,[glib-2.0])

AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES(Makefile src/Makefile)
AC_OUTPUT

編碼文件,Makefile.am

ACLOCAL_AMFLAGS=-I m4
SUBDIRS=src

b)在src下,先完成cpp的helloworld編寫和src/Makefile.am編寫(拷貝下參考文中的部分說法)

GNU Autotools 是一個工具集,其中比較重要的工具備 autoconf, aclocal, automake, libtool,此外還有一些輔助工具,例如 autoscan, autoheader 之類。還有一個工具 pkg-config ,雖然它不屬於 GNU Autotools,但也是很是重要。這些工具提供了一些可在 configure.ac 文件中調用的 m4 宏。例如,以 AC_ 爲前綴的宏都是 autoconf 提供的,以 AM_ 爲前綴的宏是 automake 提供的,以 PKG_ 爲前綴的宏是 pkg-config 提供的。因此,要想弄明白這些宏的含義,就使用 info 去查各個工具的手冊。例如,要弄清楚 AC_CONFIG_AUX_DIR,就須要 info autoconf。若是不懂 info 命令的用法,那麼你應該 info info。

既然在 AC_CONFIG_FILES 宏參數中設定未來要經過 configure 腳本生成 Makefile 與 src/Makefile 文件,那麼就必須提供相應的 Makefile.am 與 src/Makefile.am 文件:

eproxyd.cpp

#include<iostream>
using namespace std;

int main()
{
	cout<<"hello Gnu";
	return 0;
}

 src/Makefile.am

bin_PROGRAMS=eproxyd
eproxyd_SOURCES=eproxyd.cpp

eproxyd_LDADD = $(WHEEL_LIBS)
eproxyd_CFLAGS= $(WHEEL_CFLAGS)
eproxyd_CPPFLAGS= $(WHEEL_CFLAGS)

 c)到這裏,源碼部分的代碼就已經寫完,接下來須要用automake工具進行編譯了,咱們這裏寫個腳原本快速完成相關工做。

 定位到project目錄下,編碼autogen.sh,並更改運行模式,chmod 777 autogen.sh。

#!/bin/sh
aclocal
autoheader
automake --add-missing
autoconf

 運行以後,執行./configure,並按照要求安裝依賴的工具庫。

例如,我用到了glib-2.0,且是另外一個庫的一部分(glib is a part of : libgtk2.0-dev),我遇到了依賴的錯誤,試了下aptitude(sudo aptitude install libgtk2.0-dev),最後用換源解決的(最初使用了ubuntu14.10版本,然而更新源時遇到很嚴重的問題,update以後變成16.10,且屏幕的最上方的狀態欄每半秒變大縮小一次。重裝64位14.04穩定版解決)。

>sudo apt-get install libgtk2.0-dev

 此時,makefile文件便生成出來。在project下執行make,會在src中生成咱們剛纔定義的eproxyd。測試下執行,獲得「hello Gnu」。

2.增長參數解析

接下來咱們就能夠對剛纔的helloworld程序進行擴充了。

其實,在上面的文件configure.ac中,已經存在了一行宏命令 PKG_CHECK_MODULES(WHEEL,[glib-2.0]) ,它表明的意思是,利用pkg工具導入glib-2.0庫。terminal中可用下屬指令查看支持那些庫(我暫時還沒用到)。例如,PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.4)  。

pkg-config --list-all

 給工程添加依賴庫有幾種方式,參考http://socol.iteye.com/blog/580416,有pkg,-I-L,貌似還有種pc形式的。(遇到再回來更新)

迴歸話題,我但願個人程序可以支持下面這種調用形式:

src/eproxyd --inport =6666 --outport=6667 --log="~/eplog/" 

src/eproxyd --i =6666 --o=6667 --l="~/eplog/"

這種狀況下,咱們能夠調用 GLib 庫中的命令行選項解析器來完成。

初步代碼結構以下,eproxyd.cpp

#include<cstdlib>
#include<glib.h>

#include<iostream>
using namespace std;

static gint zero_inport = 6660;
static gint zero_outport = 6661;
static gchar *zero_log="~/log/";

static GOptionEntry eproxyd_entries[]={
    {"inport",'i',0,G_OPTION_ARG_INT,&zero_inport,"Set <chunk> as the inport to receive SQLs.","<chunk>"},
    {"outport",'o',0,G_OPTION_ARG_INT,&zero_outport,"Set <chunk> as the outport to send encrypted SQLs.","<chunk>"},
    {"log",'l',0,G_OPTION_ARG_STRING,&zero_log,"the log file will be stored at <locate>/log","<locate>"},
    {NULL}
};


bool prepare(int argc,char**argv);
bool work();


int main(int argc,char**argv)
{
    bool IsPre = prepare(argc,argv);
    if(!IsPre){
        g_error("prepare fail!");
        exit(1);
    }
    g_print("Msg: inport=%d,outport=%d,log=%s\n",&zero_inport,&zero_outport,&zero_log);    

    work();
    return 0;
}

bool prepare(int argc,char**argv){
    cout<<"prepare"<<endl;
    GOptionContext *context=g_option_context_new("An integrated proxy to rewrite SQLs.");
    g_option_context_add_main_entries(context,eproxyd_entries,NULL);
    GError *error=NULL;
    if(!g_option_context_parse(context,&argc,&argv,&error)){
        g_error("Command line option parser failed:",error->message);
        return false;
    }
    if(argv[1]==NULL) g_error("You should give params! -h for help\n");
    g_option_context_free(context);
    return true;
}

bool work(){
    cout<<"work"<<endl;
    return true;
}

同時,把cpp文件中新增的函數,加入到eproxyd.h中作申明。

#ifndef EPROXYD_H
#define EPROXYD_H
bool prepare(int argc,char**argv);
bool work();
#endif

上面代碼使用到了GLIB中的幾個數據結構,值得注意的是,if(argv[1]==NULL)增長該句是爲了屏蔽掉無輸入的情形(跟隨功能而言)。

相關文章
相關標籤/搜索