C++でのmain関数ラッパー方法
gdbserverを用いてリモートアタッチする際に、ラッパーmain関数内にてsleepを入れておき、
その際にアタッチする必要がありました。(sleepを入れておかないと、break pointより先にプロセスが進んでしまいます)
そこで
・元のmain関数が定義されているmain.cppには修正を加えない
という条件のもとで、そのようなラッパーmain関数を作成してみます。
結論から言うと、2つの方法があります。
(他にも方法があるかもしれません)
1つ目の方法
「main関数 ラッパー」などで検索すると、以下のページが見つかると思います。
qiita.com
マクロとincludeを用いた方法です。
これを実際にやってみます。
以下のようなmain.cppがあるとします。
//main.cpp #include <stdio.h> int main(){ printf("main\n"); return 0; }
これをラップするwrapper_main1.cppを作成します。
//wrapper_main1.cpp #include <stdio.h> int original_main(); int main(){ printf("wrapper_main1\n"); original_main(); } #define main original_main #include "main.cpp"
実行すると、
-VirtualBox:~/test$ ./a.out
wrapper_main1
main
のように、wrapper_main1→mainの順に呼ばれます。
wrapper_main1にsleepを入れておけば、目的が達成できます。
プリプロセッサ実行後をみると、
# 3 "wrapper_main1.cpp" int original_main(); int main(){ printf("wrapper_main1\n"); original_main(); } # 1 "main.cpp" 1 int original_main(){ printf("main\n"); return 0; } # 11 "wrapper_main1.cpp" 2
マクロとincludeで上手く元のmain関数をoriginal_mainに書き換え、実行していることがわかります。
2つ目の方法
(今回は主にこちらの方法を紹介する目的で記事を書きました。)
-Wl,--wrapオプションを使うことで、ラッパー関数を呼び出すことができます。
さきほどと同様に以下のmain関数をラップします。
//main.cpp #include <stdio.h> int main(){ printf("main\n"); return 0; }
wrapper_main2.cppを作成します。
#include <stdio.h> extern "C"{ int __real_main(); int __wrap_main(){ printf("wrapper_main2\n"); __real_main(); return 0; } }
(手元の環境ではexternしないと_Z**が関数名にはいってしまい、うまくリンクできませんでした)
ビルドします。
-VirtualBox:~/test$ g++ -Wl,-wrap=main -o wrap2 main.cpp wrapper_main2.cpp
実行します。
-VirtualBox:~/test$ ./wrap2
wrapper_main2
main
この -WL,-wrap=mainがポイントです。
-wrapオプションをリンカに渡すことで、
- オリジナルのmain関数を呼ぶときは __real_main()
- ラッパーしたmain関数を呼ぶときは __wrap_main()
として、呼び出すことができます。
ややこしいですが、普通にmain()と呼ぶと__wrap_main()が、
__real_main()を呼ぶと普通のmain()が呼ばれます。
__wrap_main()内にsleep処理を入れておくことで、目的を達成することができます。
以上2つの方法を紹介しました。
どちらがどう良いか、を語るほどラッパー関数を使用していないのですが、
2つ目のほうが、余計なマクロや複雑なinclude処理をしないので簡単かなと思います。