2023-07-23
モジュールをCでなくC++言語で書いた場合、単純にフラグに-lstdc++をつけるだけではだめで、Apache再起動時にundefined symbol: __gxx_personality_v0またはCan't locate API module structureなどと言われ無視されてしまう。
C++を使う場合apxs2コマンドでなくMakefileを修正してmakeでコンパイル、インストールを行う。
1、ソースファイル名の変更
.cファイルは.cppファイルに変更する。
mv mod_mytest.c mod_mytest.cpp
2、サンプルC++ソースコード
ap_関数,AP_変数は元々Cでの利用を想定しているため、C++で書くにはいくつかルールがある。
ためしにstd::stringを使って日本語文字を出力しつつ、処理時間をerror_logに出力するサンプルとした。
C/C++ | mod_mytest.cpp | GitHub Source |
#include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include "http_log.h" #include "util_script.h" #include <string> extern "C" { #ifdef APLOG_USE_MODULE APLOG_USE_MODULE(mytest); #endif }; /* The sample content handler */ static int mytest_handler(request_rec *r) { if (strcmp(r->handler, "mytest")) { return DECLINED; } // r->content_type = "application/json; charset=utf-8"; r->content_type = "text/plain; charset=utf-8"; if (r->header_only){ return OK; } struct timeval tv_fr,tv_to; double tm_fr,tm_to; gettimeofday(&tv_fr, NULL); ap_rputs("The sample page from mod_mytest.c\n", r); std::string s = std::string("てすとばる"); ap_rprintf(r, "てすときー = [%s]\n", s.c_str()); gettimeofday(&tv_to, NULL); tm_fr = (((double)tv_fr.tv_sec)*((double)1000000)+((double)tv_fr.tv_usec)); tm_to = (((double)tv_to.tv_sec)*((double)1000000)+((double)tv_to.tv_usec)); ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, "time: %lf MICROSEC (%lf MSEC)",tm_to - tm_fr,(tm_to - tm_fr) / 1000); return OK; } static void mytest_register_hooks(apr_pool_t *p) { ap_hook_handler(mytest_handler, NULL, NULL, APR_HOOK_MIDDLE); } extern "C" { /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA mytest_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ NULL, /* table of config file commands */ mytest_register_hooks /* register hooks */ }; };
2つの箇所をextern Cで囲う。さらに、Cでは必須ではなかった、include直後のモジュール宣言(APLOG_USE_MODULE(mytest)の箇所)が、ap_log_rerrorなどでログ出力する場合は必須となる。宣言しなければ、コンパイル時に
/usr/include/apache2/http_log.h:166:30: error: ‘aplog_module_index’ was not declared in this scope #define APLOG_MODULE_INDEX (*aplog_module_index)
などとコンパイルエラーになる。このことは、/usr/include/apache2/http_log.hに、
#ifdef __cplusplus /** * C++ modules must invoke ::APLOG_USE_MODULE or ::AP_DECLARE_MODULE in * every file which uses ap_log_* before the first use of ::APLOG_MARK * or ::APLOG_MODULE_INDEX. * (C modules *should* do that as well, to enable module-specific log * levels. C modules need not obey the ordering, though). */
と記載があり、C++でap_logを使いたくばAPLOG_USE_MODULEを宣言せよとのアドバイスが書かれている。
3、Makefileの修正
初回作成時のapxs2コマンドによりMakefileは自動生成されているはずである。これのLIBS記述のあるあたりに以下を追記する。
vi Makefile # the used tools #APACHECTL=apachectl APACHECTL=/etc/init.d/apache2 # additional defines, includes and libraries #DEFS=-Dmy_define=my_value #INCLUDES=-Imy/include/dir #LIBS=-Lmy/lib/dir -lmylib CC=g++ CXX=g++ LIBS=-L/usr/local/lib -lstdc++
APACHECTL=/etc/init.d/apache2としているのは、組み込みコマンドapachectlでは子プロセスの再起動しかしてくれずモジュール変更が反映されなかったのでinit.dを使うこととした。
4、ビルド、インストール
make clean make sudo make install
途中の出力で、libtool: compile: g++などと、ちゃんとg++コマンドでコンパイルされている旨が出力されているはず。
5、/etc/apache2/mods-available/mytest.loadでライブラリを直接ロードする
-lstdc++としたのに何故か無視されるならばLoadModule直前に外部ライブラリファイルを直接ロードする記述をしてしまえば良い。
https://theunixtips.com/howto-develop-apache-module-in-c/
に、ヒントが載っていた。
cd /etc/apache2/mods-available vi mytest.load LoadFile /usr/lib/x86_64-linux-gnu/libstdc++.so.6 LoadModule mytest_module /usr/lib/apache2/modules/mod_mytest.so
LoadFileディレクティブで直接ライブラリファイルをロード。この方法なら、前回のredisライブラリも/usr/local/lib/libhiredis.soと直接記述してしまえばMakefileで同じようにビルドできそうである。
6、Apache再起動、テスト
さきほどMakefileを修正したので、
sudo make restart
でいける。インストール・再起動を同時に行う場合
sudo make reload
でいける。
ここでエラーが出なければ、無事C++のLIBが読み込まれてモジュールが有効になった。
あとは前回と変更なく下記URI設定になっているとして、
<virtualhost> (中略) <location> SetHandler mytest </location> </virtualhost>
http://192.168.1.55/mytest
などと打って
The sample page from mod_mytest.c てすときー = [てすとばる]
と表示されれば、C++の証であるstd::stringクラスの利用ができていることとなる。
さらにerror_logには、
[Mon Jun 22 20:56:18.457636 2020] [mytest:crit] [pid 10166:tid 140352675399424] [client 172.18.255.116:55740] time: 12.000000 MICROSEC (0.012000 MSEC)
と、実行時間計測のap_logが無事出力されているのが確認できた。
※本記事内容の無断転載を禁じます。
ご連絡は以下アドレスまでお願いします★
Windowsのデスクトップ画面をそのまま配信するための下準備
WindowsでGPUの状態を確認するには(ASUS系監視ソフトの自動起動を停止する)
CORESERVER v1プランからさくらインターネットスタンダートプランへ引っ越しメモ
さくらインターネットでPython MecabをCGIから使う
さくらインターネットのPHPでAnalytics-G4 APIを使う
インクルードパスの調べ方
【Git】特定ファイルを除外する.gitignore
【Ubuntu/Debian】NVIDIA関係のドライバを自動アップデートさせない
【Python】Spacyを使用して文章から出発地と目的地を抜き出す
【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法
Windows11+WSL2でUbuntuを使う【2】ブリッジ接続+固定IPの設定
Windows版Google Driveが使用中と言われアンインストールできない場合
VirtualBoxの仮想マシンをWindows起動時に自動起動し終了時に自動サスペンドする
【Apache】サーバーに同時接続可能なクライアント数を調整する
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
Googleファミリーリンクで子供の端末の現在地がエラーで取得できない場合
【Linux】iconv/libiconvをソースコードからインストール
Ubuntu Server 21.10でイーサリアムブロックチェーン【その5】