前回は単独のプロジェクトでソースコードも1つだったので、
今回はスタティックライブラリを使用しての複数のソースコードで動作を試してみたい思います。
準備
前回はソースコード単独でビルドできる状態だったので、実行体の生成のため gcc を呼び出すコードを書いていました。
今回からは複数のコードやライブラリのリンクと言ったことも考慮するためにこの部分を make コマンドを実行するように変更しました。
これにより Makefile さえエディットすれば、ソースコードの変更に対応できるようになります。注意点としては VisualStudio でのプロジェクトへのソースコードの追加と、Makefile の中身は同期されないので、手動(もしくは他の手段で)同期をとる必要があるかもしれません。ただ大事なのは Makefile なのでこちらをエディットすることを守ればなんとかなりそうです。
具体的にはプロジェクトのプロパティで Build Command Line を以下のように変更しました。(実際にはこれを1行で記入してください)
(デバッグビルド時) $(SecureShellExecutable) $(RemoteUserName)@$(RemoteHostName) -i $(PrivateKey) "cd $(RemoteWorkingDirectory);make DEBUG=1" (リリースビルド時) $(SecureShellExecutable) $(RemoteUserName)@$(RemoteHostName) -i $(PrivateKey) "cd $(RemoteWorkingDirectory);make"
またプロジェクトに登録したファイルの転送は考えたくなかったので、Linux で Samba を導入し、共有フォルダに VisualStudio のプロジェクトを作るようにしています。
続いてスタティックライブラリの準備にとりかかります。
スタティックライブラリを使う場合
今回はテストのため他のライブラリを生成するフェーズも1つの Makefile にまとめてしまいました。これでライブラリとアプリケーションのビルド&リンクしてデバッグのテストを行いたいと思います。
テストプログラム
簡単ですが以下のようなものを作成してテストしてみます。
main.cpp と libFuncA.cpp として作成し、libFuncA.cpp はライブラリを生成、その結果をmain.cpp にリンクしてアプリケーションにするという感じです。
#include#include "myutil.h" void testResult() { int a = 0; printf("testResult.\n"); a = MYUTIL_testFuncA(10, 20); printf("testFunc %d\n", a); } int main(int argc, char* argv[]) { testResult(); return 0; }
#include "myutil.h" int MYUTIL_testFuncA(int a, int b) { int r = 0; r += a; r += b; return r; }
これらをコンパイルするのは Makefile に記述して make コマンドに任せています。
この Makefile については以下のようにしました。
.PHONY: all clean CC = g++ CXXFLAGS = -Wall OBJDIR = ./obj INCDIR = ./include LIBDIR = ./lib APPBASE = appdemo LIBBASE = myutil INCS = \ ./myutil/include SRCS = \ ./src/main.cpp LIBSRCS = \ ./myutil/src/libFuncA.cpp ifeq ($(DEBUG),1) TARGET = $(APPBASE)d CXXFLAGS += -g -O0 LIBNAME = $(LIBBASE)d BUILD_CFG = debug else TARGET = $(APPBASE) LIBNAME = $(LIBBASE) BUILD_CFG = release endif LIBTARGET = $(LIBDIR)/lib$(LIBNAME).a LIBOBJS = $(addprefix $(LIBDIR)/obj/$(BUILD_CFG)/,$(LIBSRCS:.cpp=.o)) LIB_INCLUDES = $(addprefix -I,$(INCS)) all : $(TARGET) $(LIBTARGET) : $(LIBOBJS) ar vsrc $@ $< $(LIBOBJS) : $(LIBSRCS) @mkdir -p $(dir $@) g++ $(CXXFLAGS) -c $^ -o $@ $(LIB_INCLUDES) APPOBJS = $(addprefix $(OBJDIR)/$(BUILD_CFG)/,$(SRCS:.cpp=.o)) $(APPOBJS) : $(SRCS) @mkdir -p $(dir $@) g++ $(CXXFLAGS) -c $^ -o $@ $(LIB_INCLUDES) LIBS = $(addprefix -l,$(LIBNAME)) LIBDIRS = $(addprefix -L,$(LIBDIR)) $(TARGET) : $(APPOBJS) $(LIBTARGET) g++ -o $@ $(APPOBJS) $(LIBS) $(LIBDIRS) clean: @rm -rf $(APPBASE) $(APPBASE)d $(OBJDIR) $(LIBDIR)
フォルダ構造としてはこのような感じです。
--application +-- src | +-- main.cpp +-- myutil | +-- include | | +-- myutil.h | +-- src | +-- libFuncA.cpp +-- lib +-- libmyutild.a
これらを用いて VisualStudio からビルドを行ってみたところ、以下のように成功しています。
このプロジェクトには main.cpp しか登録していませんが、Makefile により testFuncA.cpp もコンパイルされていることが確認できます。
この状態で、main.cpp にブレークポイントを設定し、 testFuncA.cpp にステップインができることを確認してみます。
これはブレークポイントで停止後にステップインで潜ったところです。
プロジェクトに登録していませんが testFuncA.cpp を見つけ出して表示できています。
実用のために
今回試してみてわかったことから、以下の点が実用とする際には変更・注意が必要だと思いました。
ライブラリ・アプリのプロジェクト分離
今回動作テストのため1つのMakefile に押し込んでしまいました。
実際に使う場合にはライブラリを生成する部分を他の Makefile に分離して、VisualStudio で他のプロジェクトを生成しておくというのが必要になると思います。
こうしておくことで、ライブラリのビルド、アプリケーションのビルドを Visual Studio から制御することができます。
ステップインで関数に入れない
自分ライブラリの関数にステップインができないこともありました。
このときの問題点は、ライブラリの中にソースコードのファイルパス情報が入っていないのが原因でした。
ファイルパスの格納の方法に依存するのか、Visual Studio ではステップインできないが、直接 gdb を実行するとできるということにも遭遇しました。
間違いなくいえるのは、オブジェクトファイルやライブラリにソースコードのファイルパス情報が影響していると言うことなので、ここを丁寧に探っていくと解決できるかもしれません。
まとめ
自分ライブラリの使った場合に、うまくいかない場合にはちょっと手こずる感じではありますが、うまく動いている範囲ではかなり開発効率があがりそうです。今まではこのようなターゲットをLinuxとする状況では eclipse で gdb を使うのが Windows で は1択でしたが、次の選択肢となりそうな気配です。
今はターゲットで gdb を呼んでいますが、これが gdbserver を使えるようになれば、デバッグ情報はローカルで、ターゲットには最小限のバイナリでデバッグができるようになるため、対応してほしいなぁと期待しているところです。
コメント
すみません、このmakefileは何処にどうやって配置すれば良いのでしょうか。
VSからmakefileを追加しようとしたのですが追加できる項目の一覧に見当たらず、どうするのが正しい方法なのか分からなかったもので。
自分がトライした手順も正しい方法かはわかりませんが、
Makefile は VisualStudio で作成せずに、他のテキストエディタで作成しました。
またこの Makefile は VisualStudio のプロジェクトに追加しませんでした。
Makefile の配置場所は、$(RemoteWorkingDirectory) で示される場所に配置します。
(その後の make コマンドで -f オプションで Makefile の場所を指定することもできるとは思います)
情報ありがとうございます。
そうなんですね・・・、教えていただいた方法でトライしてみます!