とりあえず Makefile を書くとしたらこんな感じでしょうか。(インデントはタブにしてください。)
Makefile
1 TARGET = a.out
2 SRCS = opencv.cpp
3 OBJS = $ ( SRCS : .cpp = .o )
4
5 CXXFLAGS = -std = c++11 `pkg-config --cflags opencv4`
6 LDFLAGS = `pkg-config --libs opencv4`
7
8 $ (TARGET) : $ ( OBJS )
9 $ ( CXX ) $ ( LDFLAGS ) $ ( OBJS ) -o $ ( TARGET )
10
11 clean :
12 $ ( RM ) $ ( TARGET ) $ ( OBJS )
使い方は、make と打つとコンパイル・リンクが行われます。
$ make
c++ -std=c++11 `pkg-config --cflags opencv4` -c -o opencv.o opencv.cpp
c++ `pkg-config --libs opencv4` opencv.o -o a.out
$ ./a.out
また、make clean と打つとコンパイルしたものが削除されます。
$ make clean
rm -f a.out opencv.o
Makefile の前に、まず C や C++ の分割コンパイルについて説明します。
例えば main.cpp と sub.cpp から a.out を作る場合、次のコマンドを打ちますよね。
$ c++ main.cpp sub.cpp -o a.out
これを、次のようにコンパイルとリンクを分けて実行することもできます。
この場合、main.cpp と sub.cpp をそれぞれコンパイルして main.o と sub.o が作られ、最後に main.o と sub.o をリンクして a.out が作られます。
(上のように一行で実行する場合も、実は内部でコンパイルとリンクが行われています。)
$ c++ -c main.cpp -o main.o
$ c++ -c sub.cpp -o sub.o
$ c++ main.o sub.o -o a.out
また、pkg-config ですが、普通に実行するとこんな感じになります。
-I はコンパイラに対するオプションで、#include <〜> するファイルのありかを指定します。
-L と -l はリンカに対するオプションで、-L がライブラシの場所を、-l はリンクするライブラリをしていします。
$ pkg-config --cflags opencv4
-I/usr/local/Cellar/opencv/4.3.0/include/opencv4/opencv -I/usr/local/Cellar/opencv/4.3.0/include/opencv4
$ pkg-config --libs opencv4
-L/usr/local/Cellar/opencv/4.3.0/lib -lopencv_gapi -lopencv_stitching -lopencv_alphamat -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d
で、コマンドラインでバッククオートで括って実行してますが、この場合、バッククオートで括った部分の実行結果をコマンドラインに埋め込んでさらに実行します。つまり、
$ c++ -std=c++11 `pkg-config --cflags opencv4` -c -o opencv.o opencv.cpp
$ c++ `pkg-config --libs opencv4` opencv.o -o a.out
は、それぞれ実際には以下のコマンドが実行されることになります。
$ c++ -std=c++11 -I/usr/local/Cellar/opencv/4.3.0/include/opencv4/opencv -I/usr/local/Cellar/opencv/4.3.0/include/opencv4 -c -o opencv.o opencv.cpp
$ c++ -L/usr/local/Cellar/opencv/4.3.0/lib -lopencv_gapi -lopencv_stitching -lopencv_alphamat -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d opencv.o -o a.out
次に Makefile の読み方を解説します。
まず最初の部分は変数定義です。
TARGET は最終的にできるプログラムの名前です。
SRCS はソースコード (.cpp ファイル) で、複数指定できます。(なので変数名が複数型。)
OBJS は SRCS の拡張子 .cpp を .o にしたもので、この場合は opencv.o になります。
なお、TARGET, SRCS, OBJS という名前は習慣的なもので、別の名前でも構いません。
TARGET = a.out
SRCS = opencv.cpp
OBJS = $(SRCS:.cpp=.o)
CXXFLAGS と LDFLAGS は飛ばして、次の部分がルール記述になります。
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) $(OBJS) -o $(TARGET)
Makefile のルールの書き方は次のとおりで、make 作りたいもの と打つと、まず必要なものを作って、それより作りたいものが古ければ、作るためのコマンドを実行します。
作りたいもの: 必要なもの
(タブ) 作るためのコマンド
また、$(変数名) は変数が展開されるので、実際には次のようになります。
(ちなみに、CXX は make の組み込み変数 (C++ コンパイラの意味) で、値は c++ になってます。)
これの意味ですが、a.out を作るには opencv.o が必要で、opencv.o から a.out を作るコマンドが次の行に書いてあるということになります。
a.out: opencv.o
c++ `pkg-config --libs opencv4` opencv.o -o a.out
ところで、opencv.o はどうやって作るかというと、make にはメタルールと言って、ある拡張子のファイルから別の拡張子のファイルを作るためのルールを定義することができます。
例えば、.cpp から .o を作るためのメタルールはこんな感じです。(ここで、$@ は作りたいもの、$< は必要なものです。)
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<
つまり、opencv.cpp から opencv.o を作るためのルールはこうなります。(CPPFLAGS と TARGET_ARCH は空です。)
opencv.o: opencv.cpp
c++ -std=c++11 `pkg-config --cflags opencv4` -c -o opencv.o opencv.cpp
最後に make clean ですが、clean というファイルを作ろうとして、普通そんなファイルはないので、毎回指定したコマンドが実行されます。(間違って clean というファイルを作ってしまうと、make clean しても make: `clean' is up to date. と言われて何もしてくれません。)
clean:
$(RM) $(TARGET) $(OBJS)