2024-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が無事出力されているのが確認できた。
※本記事内容の無断転載を禁じます。
ご連絡は以下アドレスまでお願いします★
Wav2Lipのオープンソース版を改造して外部から呼べるAPI化する
Wav2Lipのオープンソース版で静止画の口元のみを動かして喋らせる
【iOS】アプリアイコン・ロゴ画像の作成・設定方法
オープンソースリップシンクエンジンSadTalkerをAPI化してアプリから呼ぶ【2】
オープンソースリップシンクエンジンSadTalkerをAPI化してアプリから呼ぶ【1】
【Xcode】iPhone is not available because it is unpairedの対処法
【Let's Encrypt】Failed authorization procedure 503の対処法
【Debian】古いバージョンでapt updateしたら404 not foundでエラーになる場合
ファイアウォール内部のWindows11 PCにmacOS Sequoiaからリモートデスクトップする
【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法
進研ゼミチャレンジタッチをAndroid端末化する
VirtualBoxの仮想マシンをWindows起動時に自動起動し終了時に自動サスペンドする
Googleスプレッドシートを編集したら自動で更新日時を入れる
Androidホームで左にスワイプすると出てくるニュース共を一切表示させない方法
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
Linuxでtar.xz形式のファイルを解凍する
Python venv(仮想環境作成)でError: Command returned non-zero exit status 1のエラー対処法
Windows11のコマンドプロンプトでテキストをコピーする