在linux下完成一个GNU风格的程序

最近需要在linux下完成项目编码,因此记录一下编码心得。(选择ubuntu14.04版本,04代表稳定版本,amd64代表64位,本文使用163源)

-------------------------------------------------------------------------------------------

计划:

1.完成GNU风格helloworld。

2.熟悉libconfig库,完成参数解析。

3.完成单例模式,封装算法功能

4.熟悉libevent库,并添加事件响应。

-------------------------------------------------------------------------------------------

1.GNU风格,命令行程序hello

如何写一个 GNU 风格的命令行程序: https://segmentfault.com/a/1190000004321899

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)增加该句是为了屏蔽掉无输入的情形(跟随功能而言)。

 

posted @ 2018-01-09 15:48  secondwatch  阅读(254)  评论(0编辑  收藏  举报