微软的Visual Studio确实是个很方便使用的IDE,但真正部署在很多设备上,尤其是工程设备的时候,还是很依赖于Linux的。
最近做了一些预研的项目,一开始考虑了半天到底用什么平台来做出效果最快,就先选了Windows10 + VisualStudio2019来做。VisualStudio的观察变量窗口和debug确实是界面非常友好,我也很快就按照思路做出了一个demo,但最后还是被产品经理要求转到Linux去开发,因为对接的研发人员用的目标设备都是Linux的主机。
由于我也是头一次开发比较大的程序,明显的200行根本搞不定,算法步骤多,且变量多,就不敢像之前一样搞一个.cpp文件然后一个main函数干到底,还是老老实实分了模块,放进了好几个.cpp和.h里面去写,然后用了#include"***.h"的方式。
这种联合编写的方式在VisualStudio里面就是直接放在一个Project下面就自动解决了链接的问题,但如果用在Linux的g++,还是需要使用makefile的。于是,我就再次把学习makefile的事情推上了日程。
在包括CSDN在内的一些博客网站上看了一些介绍的博文,普遍都是面向C语言的,而且博客的格式混乱,介绍的内容也不去全面,于是我也没再尝试找这类教程,而是直接找过去用过的成功范例来模仿了。(StackOverflow也是个好东西,但远水确实解不了近渴,读英文的时间还是有消耗的。)
这里废话不多说,先上一段代码看一下。(由于CSDN没有支持makefile的格式,因此这段代码没有显示出不同颜色的高亮区分)中间加了一些我的注释,可能有些错误在里面,欢迎大家指正。
此代码主要用于一个使用了OpenCV视觉库的应用程序。程序的".cpp"和".h"文件直接来自于VisualStudio复制粘贴。下面的makefile中虽然没有显式提及用到的".cpp"和".h"文件的名称,但已经将当前目录下的这些文件都进行了处理(包括main.cpp,没有同名的.h文件。包括个别的无需配合同名.cpp文件的即用式.h文件,都进行了处理。可见wildcard还是很强大的,适用于文件较多的工程。)
TARGET = MonocularDistance #生成的可执行文件名称
OPENCV_LIB_PATH = -L /usr/local #OpenCV库文件路径
OPENCV_INC_PATH = -I /usr/local/include #OpenCV包含文件路径,注意是大写的i
OUTDIR = OutputDirectory/ #输出可执行文件路径,在当前目录下生成文件夹
CC=g++ #选择g++作为编译器
INCLUDE = -I $(OPENCV_INC_PATH)$ #添加包含文件,注意是大写的i
CFLAGS=-Wall -g -O2 -std=c++11 -Wno-unknown-pragmas #编译过程中的可选项,具体的可以自行百度其含义
#OpenCV库文件。注意格式中使用了"-l"(小写L)连接库文件的名称。文件数量较多时,使用"\"进行换行
OPENCV_LIBS = -lopencv_core \
-lopencv_imgcodecs \
-lopencv_highgui \
-lopencv_videoio \
-lopencv_imgproc
#将OpenCV库文件放入库中
LIBS= $(OPENCV_LIBS)
#定义remove功能
RM = rm -f
SRCS = $(wildcard *.cpp) #源文件,来自于当前目录下所有的".cpp"文件,"wildcard"表示通配符,意为所有的
OBJS = $(SRCS:%.cpp=%.o) #目标文件,采用与源文件相同的名称,以".o"结尾
DEPS = $(OBJS:%.o=%.d) #依赖关系文件,这个目前我还没太搞清楚,先抄下来了。“不知为不知”
.PHONY: all #用于欺骗make
all: ${TARGET}
#根据以上给定的生成可执行文件、目标文件、编译器、编译选项、库文件进行编译,并创建输出文件夹,且将可执行文件复制到该文件夹
${TARGET}: ${OBJS}
${CC} ${LDFLAGS} $^ -o $@ $(LIBS)
-mkdir -p $(OUTDIR)
-cp $(TARGET) $(OUTDIR)
#目标文件来自于源文件的编译
%.o: %.cpp ${SRCS}
${CC} ${INCLUDE} ${LDFLAGS} -o $@ $< -c ${CFLAGS}
#依赖项来自于源文件
${DEPS}: %.cpp
${CC} ${CLAGS} ${INCLUDE} -MM $< >$@
#包含目标文件名称所对应的依赖项
-include $(OBJS:.o=.d)
#可通过clean语句清除编译过程中产生的可执行文件、目标文件和依赖项
.PHONY: clean
clean:
-${RM} ${TARGET} ${OBJS} ${DEPS}
以下是不带注释的洁净版,可作为后续参考或直接复制粘贴使用。
TARGET = MonocularDistance
OPENCV_LIB_PATH = -L /usr/local
OPENCV_INC_PATH = -I /usr/local/include
OUTDIR = OutputDirectory/
CC=g++
INCLUDE = -I $(OPENCV_INC_PATH)$
CFLAGS=-Wall -g -O2 -std=c++11 -Wno-unknown-pragmas
OPENCV_LIBS = -lopencv_core \
-lopencv_imgcodecs \
-lopencv_highgui \
-lopencv_videoio \
-lopencv_imgproc
LIBS= $(OPENCV_LIBS)
RM = rm -f
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:%.cpp=%.o)
DEPS = $(OBJS:%.o=%.d)
.PHONY: all
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} ${LDFLAGS} $^ -o $@ $(LIBS)
-mkdir -p $(OUTDIR)
-cp $(TARGET) $(OUTDIR)
%.o: %.cpp ${SRCS}
${CC} ${INCLUDE} ${LDFLAGS} -o $@ $< -c ${CFLAGS}
${DEPS}: %.cpp
${CC} ${CLAGS} ${INCLUDE} -MM $< >$@
-include $(OBJS:.o=.d)
.PHONY: clean
clean:
-${RM} ${TARGET} ${OBJS} ${DEPS}