アプリケーション開発ポータルサイト
ServerNote.NET
カテゴリー【C/C++
【Makefile】依存関係ファイル/静的/動的ライブラリ/実行ファイルをまとめてメイク
POSTED BY
2023-07-18

ビルドの自動化はもちろん、プロジェクトの全体構成を説明するにもMakefileは欠かせない存在である。識別子の意味などいつも忘れてしまうのでメモ。

以下、自作のC++クラスライブラリlibcppのMakefileです。
libcpp GitHubはこちら

ShellMakefileGitHub Source
CXX    =  g++
CC_DBG  +=  -g -O2
#STRIP  +=  -s
#CC_OPT  +=  -D_GNU_SOURCE -D_USE_PGSQL -D_USE_MYSQL
CC_OPT  +=  -D_GNU_SOURCE -D_USE_MYSQL
CC_OPT  +=  -DLINUX -D_REENTRANT -D_FORTIFY_SOURCE=2 -fPIC -DPIC -fstack-protector-strong
CC_OPT  +=  -Wformat -Werror=format-security -Wdate-time
CC_INC  +=  -I/usr/local/include
CXXFLAGS  +=  $(CC_DBG) $(CC_OPT) $(CC_INC)
SRCS  =  LFile.cpp LSocket.cpp LPgSQL.cpp LMySQL.cpp G.cpp LCgi.cpp
OBJS  =  ${SRCS:.cpp=.o}
DESTLIB  =  /usr/local/lib
DESTINC  =  /usr/local/include

all:  .deps libcpp.a libcpp.so main.x

.deps:
  $(CXX) -M $(CXXFLAGS) $(SRCS) main.cpp > $@

libcpp.a:  $(OBJS)
  ar rv $@ $?
  ranlib $@

libcpp.so:  $(OBJS)
  $(CXX) -pthread -shared -Wl,--as-needed -Wl,-z -Wl,relro -Wl,-z -Wl,now -Wl,-soname -Wl,$@.1 -o $@.1.0 $^

# env LD_LIBRARY_PATH=`pwd` ./main.x
main.x:  main.cpp libcpp.so.1.0
  $(CXX) $(CXXFLAGS) -o $@ $^ -pthread -lm -lssl -lcrypto -lpq

clean:
  rm -f *.o *.a *.so* *.x .deps

install:  all
  install libcpp.a $(DESTLIB)
  install libcpp.so.1.0 $(DESTLIB)
  ldconfig $(DESTLIB)
  ln -f -s -r $(DESTLIB)/libcpp.so.1 $(DESTLIB)/libcpp.so
  install -m 0644 libcpp.h $(DESTINC)

-include .deps

make
で、
依存関係ファイル.deps
スタティックライブラリlibcpp.a
シェアードライブラリlibcpp.so
テスト実行ファイルmain.x
を一度にビルドします。

それぞれのターゲットだけをビルドしたい場合そのターゲット名を指定。
例)make libcpp.so
ただしlibcpp.soは.depsに依存しているため、.depsのビルドが先に行われます。

make clean
で、すべての生成ファイルを削除。

sudo make install
で、
/usr/local/lib/libcpp.a,libcpp.so、/usr/local/include/libcpp.h
と、システムにインストールされます。

インストール前にローカルでテスト実行ファイルをテストするには
env LD_LIBRARY_PATH=`pwd` ./main.x
とする。スタティックリンクライブラリをテストする場合Makefileを
main.x: main.cpp libcpp.a
と修正する。

makeでビルド後ソースファイル(LCgi.cppなど)やインクルードファイル(.depsで定義)に変更がなければ、もう一度makeとしてもビルドは行われない。ソースを変更した場合そのファイルだけがコンパイルされ、実行ファイルのビルドが行われる。

libparsonlibnkfのビルドMakefileではスタティックとシェアードでソースのコンパイルオプションを変えていたのでオブジェクトファイルも2通り定義したが、どうもシェアードのオプションでスタティック用のコンパイルをしてもリンク・実行に差し支え無さそうだったので、今回オブジェクトファイルは同じにしている(.oで統一、リコンパイルも不要)

以下、コンパイルオプション・Make識別子の説明

-O2:最適化レベル2オプション。コンパイル速度・オブジェクトサイズは大きくなる。

-fPIC:再配置可能とするオプション。シェアードライブラリビルドには必須。

$@:ターゲット名に変換される。

.deps:
  $(CXX) -M $(CXXFLAGS) $(SRCS) main.cpp > $@

では、$@ = .depsになる。

$?:依存関係リストのうちターゲットより変更時刻が新しいものだけ展開される。

libcpp.a:  $(OBJS)
  ar rv $@ $?

では、たとえばLSocket.oだけがlibcpp.aより新しいなら、$? = LSocket.oとなる。.depsにより、LSocket.oはLSocket.cppに依存しているわけだから、LSocket.cppが変更されれば上記arが行われる。

$^:依存関係リストに常に変換される。

main.x:  main.cpp libcpp.so
  $(CXX) $(CXXFLAGS) -o $@ $^ -pthread -lssl -lcrypto -lpq

では、$^ = main.cpp libcpp.so になる。

-include .deps:依存関係ファイル.depsを読み込む。読み込まないとヘッダファイルの変更などが行われても再コンパイルされない。-が重要で、これは対象ファイルが無い場合でもエラーとしない識別子。

-g -O2とするならinstallコマンドに-s(stripオプション)はつけてはならない。デバッグシンボルが消えてしまう。

※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!
ご連絡は以下アドレスまでお願いします★

【キーワード検索】