3.9 用C++语言编写HTTP模块

Nginx及其官方模块都是由C语言开发的,那么能不能使用C++语言来开发Nginx模块呢?C语言是面向过程的编程语言,C++则是面向对象的编程语言,面向对象与面向过程的优劣这里暂且不论,存在即合理。当我们由于各种原因需要使用C++语言实现一个Nginx模块时(例如,某个子功能是用C++语言写成,或者开发团队对C++语言更熟练,又或者就是喜欢使用C++语言),尽管Nginx本身并没有提供相应的方法支持这样做,但由于C语言与C++语言的近亲特性,我们还是可以比较容易达成此目的的。

首先需要弄清楚相关解决方案的设计思路。

❑不要试图用C++编译器(如G++)来编译Nginx的官方代码,这会带来大量的不可控错误。正确的做法是仍然用C编译器来编译Nginx官方提供的各模块,而用C++编译器来编译用C++语言开发的模块,最后利用C++向前兼容C语言的特性,使用C++编译器把所有的目标文件链接起来(包括C编译器由Nginx官方模块生成的目标文件和C++编译器由第三方模块生成的目标文件),这样才可以正确地生成二进制文件Nginx。

❑保证C++编译的Nginx模块与C编译的Nginx模块互相适应。所谓互相适应就是C++模块要能够调用Nginx框架提供的C语言方法,而Nginx的HTTP框架也要能够正常地回调C++模块中的方法去处理请求。这一点用C++提供的extern"C"特性即可实现。

下面详述如何实现上述两点内容。

3.9.1 编译方式的修改

Nginx的configure脚本没有对C++语言编译模块提供支持,因此,修改编译方式就有以下两种思路:

1)修改configure相关的脚本。

2)修改configure执行完毕后生成的Makefile文件。

我们推荐使用第2种方法,因为Nginx的一个优点是具备大量的第三方模块,这些模块都是基于官方的configure脚本而写的,擅自修改configure脚本会导致我们的Nginx无法使用第三方模块。

修改Makefile其实是很简单的。首先我们根据3.3.2节介绍的方式来执行configure脚本,之后会生成objs/Makefile文件,此时只需要修改这个文件的3处即可实现C++模块。这里还是以mytest模块为例,代码如下。


CC=gcc

CXX=g++

CFLAGS=-pipe-O-W-Wall-Wpointer-arith-Wno-unused-parameter-Wunused-function-Wunused-variable-Wunused-value-Werror-g

CPP=gcc-E

LINK=$(CXX)

……

objs/addon/httpmodule/ngx_http_mytest_module.o:$(ADDON_DEPS)\

../sample/httpmodule/ngx_http_mytest_module.c

$(CXX)-c$(CFLAGS)$(ALL_INCS)\

-o objs/addon/httpmodule/ngx_http_mytest_module.o\

../sample/httpmodule/ngx_http_mytest_module.cpp

……


下面解释一下上述代码中修改的地方。

❑在Makefile文件首部新增了一行CXX=g++,即添加了C++编译器。

❑把链接方式LINK=$(CC)改为了LINK=$(CXX),表示用C++编译器做最后的链接。

❑把模块的编译方式修改为C++编译器。如果我们只有一个C++源文件,则只要修改一处,但如果有多个C++源文件,则每个地方都需要修改。修改方式是把$(CC)改为$(CXX)。

这样,编译方式即修改完毕。修改源文件后不要轻易执行configure脚本,否则会覆盖已经修改过的Makefile。建议将修改过的Makefile文件进行备份,避免每次执行configure后重新修改Makefile。

注意 确保在操作系统上已经安装了C++编译器。请参照1.3.2节中的方式安装gcc-c++编译器。