Nginx使用纯C语言开发,默认使用GCC编译,如何使用C++开发Nginx模块或者在开发的Nginx模块中引入C++库呢?
首先介绍下C和C++混合编程的背景知识。
我们知道C++ 是在 C 语言的基础上发展起来的。在某种程度上,我们可将 C++ 看做 C 的一种扩展。在本质上,二者的数据类型和函数调用惯例都是一致的, C 与 C++ 混合编译也是很自然的事情。
二者的区别仅在于编译后函数的名字不同──C 简单地使用函数名而不考虑参数的个数或类型,而 C++ 编译后的函数名则总是将参数类型列表作为其一部分。尽管如此,C++ 提供了特殊的机制来声明 C 函数,这意味着一个 C++ 程序可以直接声明和调用 C 函数。
C++调用C函数
C++调用C实现的函数func_implement_by_c时,在C++代码里的函数声明必须用extern “C” 前缀:
/* * file name: cpp_caller.cpp */ extern "C" void func_implement_by_c(char *str); void cpp_caller() { func_implement_by_c("I'm from CPP"); } int main() { cpp_caller(); }
C调用C++函数
C如果要调用C++的代码,特别是要调用类的成员函数,一般需要把C++函数封装成C样式的函数:
/** * file name: c_wapper_of_member_func.cpp */ void c_wapper_of_member_func(char *str) { class TestClass; TestClass a; a.member_func(str); }
在C中调用时,也是需要在函数声明前加extern “C”前缀:
/** * file name: c_caller.c */ extern "C" void c_wrapper_of_member_func(char *str); void c_caller() { c_wrapper_of_member_func("I'm from C"); } int main() { c_caller(); }
下面我们理一下Nginx C++模块相关解决方案的设计思路。
首先,不要试图用C++编译器(如G++)来编译Nginx的官方代码,这会带来大量的不可控错误。正确的做法是仍然用C编译器来编译Nginx官方提供的各模块,而用C++编译器来编译用C++语言开发的模块,并打包成静态库。然后利用C和C++混合编程的思路,将C++写成的模块封装成C样式的接口来和Nginx的其他模块进行交互。
1. C++模块使用Nginx的头文件,需要使用extern “C” 包起来
#ifdef __cplusplus extern "C" { #endif #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> #include <nginx.h> #ifdef __cplusplus } #endif
2. 将C++模块封装成C样式的接口,将模块注册到Nginx中
3. 修改C++模块的配置文件(模块目录下的config文件),实现最终的编译
在CORE_INCS中条件增加头文件路径,在CORE_LIBS中增加库文件的路径,并增加”-lstdc++”链接选项:
比如,我们用C++实现的Nginx模块代码最终打包成静态库libcpp_module.a,则配置文件修改如下:
ngx_feature="http_push_stream_module" ngx_feature_name= ngx_feature_run=no ngx_feature_incs= ngx_feature_path= ngx_feature_libs= ngx_feature_test= CPP_MODULE_DIR="/data/packages/nginx-push-stream-module/cpp-module" ngx_addon_name=ngx_http_push_stream_module HTTP_MODULES="$HTTP_MODULES ngx_http_push_stream_module" CORE_INCS="$CORE_INCS \ $ngx_addon_dir/src \ $ngx_addon_dir/include \ $CPP_MODULE_DIR" CORE_LIBS="$CORE_LIBS -L$CPP_MODULE_DIR -lstdc++ -lcpp_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ ${ngx_addon_dir}/src/ngx_http_push_stream_module.c" have=NGX_HTTP_HEADERS . auto/have . auto/feature #if not have sha1 or do not want to use WebSocket comment the lines bellow USE_SHA1=YES have=NGX_HAVE_SHA1 . auto/have