不积小流,无以成江海

海纳百川,有容乃大

Configure.ac 文件解析

原理:Autoconf 是用来产生 “configure” 文档的工具。“configure” 是一个 shell script,它可以自动设定原始程序以符合各种不同平台上 Unix 系统的特性,并且根据系统参数及环境产生合适的 Makefile 文档或是 C 的标头档 (header file),让原始程序可以很方便地在这些不同的平台上被编译出来。Autoconf 会读取 configure.in configure.ac 档然后产生 “configure” 这个 shell script。

configure.in configure.ac 文档的内容是一连串 GNU m4 的巨集,这些巨集经过 autoconf 处理后会变成检查系统特征的 shell script。configure.in configure.ac 内巨集的顺序并没有特别的规定,但是每一个 configure.in configure.ac 档必须在所有巨集前加入 AC_INIT 巨集,然後在所有巨集的最后面加上 AC_OUTPUT 巨集。

一般先用 autoscan 这个工具扫描原始文件以产生一个 configure.scan 文件,再对 configure.scan 作些修改,从而生成 configure.in configure.ac 文件。

阅读全文 »

执行脚本 ./configure

configure:它能根据不同的系统,产生不同的 Makefile,从而使我们的程序具有可移植性。它还有一些参数:

参数 描述
–cache-file=FILE 测试系统的特性,并将结果放到FILE中
–help 输出帮助信息
–no-create 阻止其生成输出文件
–quiet 执行是不做输出
–silent 同上,若设置则不会有任何输出到屏幕
–version 输出automake的版本号
阅读全文 »

这篇帖子很棒!我从百度文库中下载了 此教程,因为未做深度的考证,所以也不知原作者是谁,但在此谢谢作者。以下是作者原文,略有删改,本人有修改部分都已做出备注。


使用过开源 C/C++ 项目的同学们都知道,标准的编译过程已经变成了简单的三部曲:configure/make/make install, 使用起来很方便,不像平时自己写代码,要手写一堆复杂的 Makefile,而且换个编译环境,Makefile 还需要修改(Eclipse 也是这样)。

这么好的东东当然要拿来用了,但 GNU 的 Autotool 系列博大精深,工具数量又多,涉及的语言也多,要是自己从头看到尾,黄花菜都凉了,项目估计早就结束了;上网搜样例倒是有一大堆,但都是“hello world”的样例,离真正完成大型项目的目标还差得远。

没有办法,对照网上的样例,再找几个开源的源码,然后参考各种 Autotools 的手册,花了 2 天时间,终于完成了一个基本可用的 Autotools。为了避免其他 XDJM 也浪费时间,因此将过程总结下来,就算是新年礼物,送给大家!!

阅读全文 »

通用唯一识别码(英语:Universally Unique Identifier,简称 UUID)的标准型式包含 32 个 16 进制数字,以连字号分为五段,形式为 8-4-4-4-12 的 32 个字符。示例:

550e8400-e29b-41d4-a716-446655440000

接下来重点描述在开发中的使用及应用。

在 C++ 中的使用

C++ 原生(C++03、C++11/0x)并不支持 UUID。所以要想在 C++ 代码中生成 UUID,如果要求跨平台推荐使用第三方库 Boost UUID,要么结合各自的平台,使用系统 API。以下方法整理自互联网,除 Boost Uuid 和 libuuid 使用过之外,其他的未亲自试验。

UUID generation using Boost in C++

在 StackOverflow 上的一个例子:跳转链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

#include <boost/uuid/uuid.hpp> // uuid class
#include <boost/uuid/uuid_generators.hpp> // generators
#include <boost/uuid/uuid_io.hpp> // streaming operators etc.

int main()
{
boost::uuids::random_generator generator;

boost::uuids::uuid uuid1 = generator();
std::cout << uuid1 << std::endl;
boost::uuids::uuid uuid2 = generator();
std::cout << uuid2 << std::endl;

return 0;
}

如果以上例子满足不了你的需求,需要在更复杂的情景下使用,请移步 Boost Uuid 官方文档

Qt QUuid

参考来源

Qt 是一个跨平台的 C++ 编程框架,QUuid 类实现了 UUID 的生成、比较、转换等功能。

函数 QUuid createUuid(),可用于生成 UUID。示例如下:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <QUuid>
#include <QString>

int main()
{
QUuid uuid = QUuid::createUuid();
std::cout << qPrintable(uuid.toString()) << std::endl;
return 0;
}

Linux 下生成 UUID

Shell

Unix/Linux 环境中大都有一个名为 uuidgen 的小工具,运行即可生成一个 UUID 到标准输出。读取文件 /proc/sys/kernel/random/uuid 即得UUID,例如:

cat /proc/sys/kernel/random/uuid

libuuid

参考来源

libuuid 是一个用于生成 UUID 的 C 库,具体用法参考 http://linux.die.net/man/3/libuuid,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <uuid/uuid.h>

int main(int argc, char **argv)
{
uuid_t uuid;
char str[36];

uuid_generate(uuid);
uuid_unparse(uuid, str);

printf("%s\n", str);

return 0;
}

在 Linux 下编译时需要链接 uuid 库

gcc -o uuid uuid.c -luuid

问题: 在什么系统下自带?在什么系统中需要另行安装?

在 Ubuntu 中,可以用下面的命令安装 libuuid:

sudo apt-get install uuid-dev

Windows 下生成 UUID

CoCreateGuid

参考来源

Windows 下提供了函数 CoCreateGuid 用于生成 GUID。需要使用的头文件是 #include <objbase.h>,需要链接的库是 ole32.lib,函数原型为:HRESULT CoCreateGuid(GUID *pguid); ,GUID 的原型为

1
2
3
4
5
6
7
typedef struct _GUID
{
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;

UuidCreate

参考来源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma comment(lib, "rpcrt4.lib")  // UuidCreate - Minimum supported OS Win 2000
#include <windows.h>
#include <iostream>

using namespace std;

int main()
{
UUID uuid;
UuidCreate(&uuid);
char *str;
UuidToStringA(&uuid, (RPC_CSTR*)&str);
cout<<str<<endl;
RpcStringFreeA((RPC_CSTR*)&str);
return 0;
}

在 Java 中使用

工作中偶尔会写一些 Java 的项目,所以也捎带整理一下。

在 MySQL 中

MySQL 本身是带有生成 uuid 功能的。也就是我们惯用的整数递增作为主键,其实是可以用 uuid 替代的。可以在一条记录插入之前写触发器,调用 UUID() 函数生成 uuid。

C/C++ 的 socket 编程。开篇

  1. socket 编程貌似是从 *nix 到的 windows?
  2. socket 编程源于 C,但 C++ 似乎并没有原生的支持,依旧是 C 语言下的 socket 编程?
  3. C++ 的网络编程,包含哪些具体的内容?单单是 socket 吗? socket 编程不应该是更接近 C 语言吗?

socket 编程,入门学习非常推荐吴秦的 Linux Socket编程(不限Linux)。当做学习 socket 编程的第一篇完全足够,甩开网上其他的帖子一万八千里,强烈推荐。本意是整理 socket 的学习笔记,但有上述帖子完全足够,在此只记录一些“边边角角”的零碎知识。

手册推荐:Beej’s Guide to Network Programming

htonl() 函数、htons() 函数

在吴秦的博客里重点强调了主机字节序(host byte order)与网络字节序(network byte order)的,上述两个函数就是用来实现两者之间的转换的。参考 Beej’s Guide to Network Programming 我们能够找到以下函数原型:

1
2
3
4
5
6
#include <netinet/in.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

不需要死记硬背,函数的命名通俗易懂。强调一下,转换 ip 地址使用长整型转换函数,转换 port 使用短整型转换函数。我在码代码学习时,误用 htonl(6666); 转换端口编译通过,运行时也不报错,启动多个服务程序也不报错 ps 正常情况重复启动服务程序时会报错“端口已经占用”。

INADDR_ANY

详细解释参考 understanding INADDR_ANY for socket programming - c。在此只强调一点,INADDR_ANY 表示的是一个服务器上所有的网卡。

inet_pton() 函数

IP地址转换函数,可以在将 IP 地址在“点分十进制”和“二进制整数”之间转换。在 Beej’s Guide to Network Programming 我们找到的描述以及函数原型:

Convert IP addresses to human-readable form and back.

1
2
3
4
5
6
#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size);

int inet_pton(int af, const char *src, void *dst);

强调一点,inet_pton() 同样支持 “localhost”。

inet_addr() 函数

Convert IP addresses from a dots-and-number string to a struct in_addr and back

1
2
3
4
5
6
7
8
9
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// ALL THESE ARE DEPRECATED! Use inet_pton() or inet_ntop() instead!!

char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);

我们可以看到其中的注释,这三个函数即将淘汰。

学习 libevent

疑问

  1. select() 函数第一个参数为什么要 maxfd+1?不理解 官方手册 中讲述 select() 低效的这段话:

    On the userspace side, …But on the kernel side,…

  2. 为什么在 Example: select()-based ROT13 server 中需要 make_nonblocking() ?为什么 Example: A low-level ROT13 server with Libevent 中需要 evutil_make_socket_nonblocking()

  3. setvbuf(stdout, NULL, _IONBF, 0); 的意义?

资源

最初步的认识,最简单的例子:使用libevent输出Hello

(niel)这里只提到了 strcut event_basestruct event。给出的简单示例代码里,有一处瑕疵: event_base_set() 函数属于过时的函数,在 2.0 之前的版本中配合 event_set() 使用,在 2.0 及其之后的版本中这两者被 event_new() 替代,所以作者混用 event_new() + event_base_set() 表明了作者并未多花时间学习。

接下来,我们可以学习一下:libevent入门教程:Echo Server based on libevent

(niel)这篇博客循序渐进,讲到了 strcut buffevent 及其相关操作。美中不足的是作者在介绍过程中穿插记录了自己的疑惑,新手读起来打破了学习的连贯性,本就在学习新知识,却也要困于作者的“泥潭”。只能说这真的只是作者的学习笔记,并未从读者的角度做考虑。总的来说,帖子很不错!初次学习时,这些问题的存在让人很难受,影响学习进度、学习动力;但熟悉作者讲的知识之后,这些问题反而才是“金子”,认真思考这些问题。

接下来推荐的学习资源就是官方手册了:Programming with Libevent

(niel)虽然是用英文写的,但阅读起来毫无障碍,很容易理解。marks C0、C1、R0 ~ R4、R8 认真阅读;R5、R6 重点关注了小部分函数,其余走马观花浏览了一下;R6a、R7、R9 三节没有看。开发过程中,查阅函数原型肯定是得翻这个手册的!

Libevent 官方文档学习笔记,这篇帖子可以看一看,和自己读英文手册理解的相互佐证。

Libevent学习笔记(一):基本使用,检验自己的学习成果。

总的来说,后面这两篇帖子并不适合用来学习。更多的定位于作者知识的整理,并不是面向新手的入门介绍。

2015年12月22日 14:48:52

这个标题《Makefile 自动生成》 8 号立的,拖到今天刚好两周。ps 2017/8/24 14:04:25 删改了 2/3 的内容,改为现在的标题。

一方面因为最近在忙别的工作,整理数据库表结构的;另一方面,是直到今天,对于自动生成 Makefile 操作依旧懵懵懂懂,在实际项目中无法使用,还是自己手动写 Makefile 文件。下面进入主题。

Makefile 自动生成,实际项目中接触到的工具有:easymake、cmake 和 autotools。 在这里只整理 autotools。

autotools 作为重点学习,所以发现了很多篇不错的帖子。

  1. 编译利器:大型项目如何使用Automake和Autoconf完成编译配置(ver+0.6) 内容很棒,却找不到好的排版,将其摘入自己博客
  2. 概念:GNU构建系统和Autotool实践:GNU构建系统 作者整理的真心不错,专业功底、语言描述、文章结构都很赞;
  3. 使用autotools生成Makefile学习笔记 不能当做一篇学习的帖子,其“常用功能分析”一节可以作为参考手册,认清知识点
阅读全文 »

2015年11月6日 16:57:34

最全的学习材料当然是 GCC 的官方文档。如果有耐心但是英语不好的话,可以参看一下 这个网站。先说

gcc/g++ 执行的四个过程:

  1. gcc -E 仅作预处理,即只激活预处理,不进行编译、汇编和链接 {通常以什么为后缀?}

    $gcc -E main.c -o main.i

  2. gcc -s 编译到汇编语言,不进行汇编和链接,即只激活预处理和编译,生成汇编语言

    $gcc -S main.i -o main.s #参数-S,大写

  3. gcc -c 编译、汇编到目标代码,不进行链接,即只激活预处理、编译和汇编功能,生成目标文件(.o)

    $gcc -c main.s -o main.o

  4. 生成,到执行文件 (根据依赖关系链接各目标文件,生成最终的执行程序)

    $gcc main.o printf1.o printf2.o -o main

阅读全文 »

2015年12月8日 16:48:31

此中测试代码见笔记 《Makefile入门》

Makefile 之执行过程

  1. 依次读取变量“MAKEFILES”定义的 makefile 文件列表
  2. 读取工作目录下的 makefile 文件(根据命名的查找顺序“GNUmakefile”,“makefile”,“Makefile”,首先找到那个就读取那个)
  3. 依次读取工作目录 makefile 文件中使用指示符“include”包含的文件
  4. 查找重建所有已读取的 makefile 文件的规则(如果存在一个目标是当前读取的某一个 makefile 文件,则执行此规则重建此 makefile 文件,完成以后从第一步开始重新执行)
  5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支
  6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
  7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)
  8. 执行“终极目标”所在的规则
阅读全文 »

2016年1月4日 10:05:04

shell 及环境变量 -1.4 其他

参数置换

shell提供了参数置换能力以便用户可以根据不同的条件来给变量赋不同的值。参数置换的变量有四种,这些变量通常与某一个位置参数相联系,根据指定的位置参数是否已经设置类决定变量的取值,它们的语法和功能分别如下。

  • 变量=${参数-word}:如果设置了参数,则用参数的值置换变量的值,否则用 word 置换。即这种变量的值等于某一个参数的值,如果该参数没有设置,则变量就等于 word 的值。
  • 变量=${参数=word}:如果设置了参数,则用参数的值置换变量的值,否则把变量设置成 word 然后再用 word 替换参数的值。注意,位置参数不能用于这种方式,因为在 shell 程序中不能为位置参数赋值。
  • 变量=${参数?word}:如果设置了参数,则用参数的值置换变量的值,否则就显示 word 并从 shell 中退出,如果省略了 word,则显示标准信息。这种变量要求一定等于某一个参数的值,如果该参数没有设置,就显示一个信息,然后退出,因此这种方式常用于出错指示。
  • 变量=${参数+word}:如果设置了参数,则用 word 置换变量,否则不进行置换。
阅读全文 »
0%