由于个人需要想做海思的C++和C混编,好像不认真学一学makefile不行了
hi3559 C/C++混编
3559给的SDK的makefile是嵌套的,想用官方的SDK的话,如果对makefile 不熟悉,就只能用官方给的Makefile,在上面修改,如果你很厉害,能看得懂,层层嵌套也得花个一天半天的整理一个自己用着舒服的Makefile模板,这里先说直接在他的sample下改,如果之后有时间我再做一个自用版本的makefile
上来先说解决方案
我是在2.0.3.0的版本上面改的,但是根据个人经验,不同版本的SDK的sample嵌套差距不大
- 在"/Hi3559AV100_SDK_V2.0.3.0/mpp/sample/"路径下,把vio copy一份出来,细节不说了,这里主要是要改他的Makefile,.c文件、.cpp文件可以删了自己写
- 修改"/Hi3559AV100_SDK_V2.0.3.0/mpp/sample/vio_2"路径下的Makefile,增加如下几行
CFLAGS += -I$(PWD)
SRCPPS := $(wildcard *.cpp)
TARGETCPP := $(SRCPPS:%.cpp=%)
- 按照他的嵌套,修改"Hi3559AV100_SDK_V2.0.3.0/mpp/Makefile.linux.param",找到[export CC:=$(CROSS)gcc]这句话,在后面加上一句,加完了之后大概是下面这样
export CC:=$(CROSS)gcc
export AR:=$(CROSS)ar
export CXX:=$(CROSS)g++
- 最后按照他的嵌套规则,修改"Hi3559AV100_SDK_V2.0.3.0/mpp/sample/linux.mak"在前面修改和增加下面几行
OBJS := $(SRCS:%.c=%.o)
OBJCPPS := $(SRCPPS:%.cpp=%.o)
.PHONY : clean all
all: $(TARGETCPP)
# all: $(TARGET)
CXXFLAGS :=$(CFLAGS)
$(TARGETCPP):$(OBJS) $(OBJCPPS) $(COMM_OBJ)
$(CXX) $(CFLAGS) $(LIBS_LD_CFLAGS) -lpthread -lm -o $@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -Wl,--end-group
# $(TARGET): $(COMM_OBJ) $(OBJS)
# $(CC) $(CFLAGS) $(LIBS_LD_CFLAGS) -lpthread -lm -o $@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -Wl,--end-group
clean:
@rm -f $(TARGET)
@rm -f $(OBJS)
@rm -f $(COMM_OBJ)
@rm -f $(TARGETCPP)
@rm -f $(OBJCPPS)
5.如果正常编译纯c目标,应该把all: $(TARGETCPP) 注释,把4中的注释打开,防止日后我自己看不懂,在这里多说一嘴
另外如果要用NNIE
增加下面一句
MPI_LIBS += $(REL_LIB)/libnnie.a
另外如果要用opencv
增加下面两句
CFLAGS += -I$(PWD) -I/home/xxx/Hisi3559A_Yolov5-master/third_party/opencv4/include/opencv4 -lopencv_highgui -lopencv_features2d -lopencv_flann -lopencv_calib3d -lopencv_objdetect -lopencv_imgcodecs -lopencv_imgproc -lopencv_videoio -lopencv_core -fpermissive
LIBS_LD_CFLAGS += -L/home/xxx/Hisi3559A_Yolov5-master/third_party/opencv4/lib
其中
home/xxx/Hisi3559A_Yolov5-master/third_party/opencv4/include/opencv4:opencv的包含文件
/home/xxx/Hisi3559A_Yolov5-master/third_party/opencv4/lib:opencv4编译出来的.so文件的位置
-lopencv_highgui -lopencv_features2d -lopencv_flann -lopencv_calib3d -lopencv_objdetect -lopencv_imgcodecs -lopencv_imgproc -lopencv_videoio -lopencv_core:你可能用到的opencv的动态链接库
后面说一下原理
想看原理点个关注吧,最近想冲数据,而且确实弄了好几天
原理
也不是特别好解释,我也了解的不太深,就通俗易懂的说说我的理解
海思的makefile 是层层嵌套的,你看vio的makefile,上来就先载入了参数,最后又载入了一个mak
include ../Makefile.param
include $(PWD)/../$(OSTYPE).mak
然后我们再看Hi3559AV100_SDK_V2.0.3.0/mpp/sample/Makefile.param
这个参数文档里面入了给一堆编译参数赋值之外最醒目亮眼的就是下面这句
ifeq ($(PARAM_FILE), )
PARAM_FILE:=../../Makefile.param
include $(PARAM_FILE)
endif
他在判空PARAM_FILE,如果这个变量是空,那么给他赋值并include,可能和.h文件的#ifndf是一个意思,怕重复调用,然后他有嵌套出来了一个关联文件Hi3559AV100_SDK_V2.0.3.0/mpp/Makefile.param
这个文件除了指定一堆编译指令,路径,环境之外,我们主要就是找嵌套。也就是这两句
include $(PARAM_DIR)/cfg.mak
include $(MPP_PATH)/Makefile.$(OSTYPE).param
这两句
之后如果有什么参数想改,也是要来这些地方ctrl+F的
其中Hi3559AV100_SDK_V2.0.3.0/mpp/cfg.mak,暂时没什么卵用,我们主要看Hi3559AV100_SDK_V2.0.3.0/mpp/Makefile.linux.param,因为我的目标平台是linux
在这个文件里面能找到$(CC),相关的赋值,这个东西是export CC:=$(CROSS)gcc,然后捋着我们来时的路可以发现,这句话相当于CC:=aarch64-himix100-linux-gcc
然后全局手工遍历CXX,我没找到,就给他加了一句export CXX:=$(CROSS)g++
能这么干的前提是你在命令行里输入aarch64-himix100-linux-g++这个指令是不报错的
至此,他载入参数这条线结束了,然后我们看include $(PWD)/../$(OSTYPE).mak,这个mak文件
直接全贴上来,逐句解析,下面的应该很贴近原始文件了
# target source
OBJS := $(SRCS:%.c=%.o) # [1]目标文件从SRCS正则生成,SRCS中含有.c的字符串去掉.c 加一个.o,空格分开,生成OBJS目标文件
.PHONY : clean all# [2]指定两个伪目标,clean、all
# 其中all 的目标是生成target ,target是在vio下的makefile指定的,我这里是.c文件去了.c,也有可能是一个指定名字
all: $(TARGET)
# [3]TARGET的依赖有COMM_OBJ,OBJS,在这两个玩意都生成了之后再执行本语句包含的下面那一行指令
$(TARGET): $(COMM_OBJ) $(OBJS)
# [5]在隐式生成.o文件之后,调用下面的语句,下面这条语句的大多数相信你已经能猜出来是什么了,麻烦的是这两个玩意$@ $^
# $@ : 规则的目标所定义的文件名
# $^ : 规则中的第一个文件名
# 经过个人发现,这个target如果有多个的话,是会遍历完所有的生成目标项的,也就是$^位置,每次填充一个target
# 至于这个东西,$@ ,应该是$(COMM_OBJ) $(OBJS)中的所有.o文件,空格隔开
$(CC) $(CFLAGS) $(LIBS_LD_CFLAGS) -lpthread -lm -o $@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -Wl,--end-group
# [6] 原始文件的这句话前面应该有个@ ,放在指令前面的@是用于说明本条语句不输出的,为了方便观察他的语句执行效果,我给去了,也没加回来。
# [4]这里说一下$(COMM_OBJ) $(OBJS)这俩玩意是怎么生成的,makefile有隐式生成规则
# 就是你的目标文件如果没有说是怎么来的,他就自动在你的文件夹下给你找同名文件编译,编译的指令,如果是C,就$(CC)编译,编译指令是$(CFLAGS),链接的库在$(LIBS_LD_CFLAGS),C++的话就是$(CXX)编译$(CXXFLAGS)
# 也就是说,这里列举了两个目标文件,这两个目标文件都采用默认的语句自动生成,生成结果是对应的.o文件
clean:
@rm -f $(TARGET)
@rm -f $(OBJS)
@rm -f $(COMM_OBJ)
cleanstream:
@rm -f *.h264
@rm -f *.h265
@rm -f *.jpg
@rm -f *.mjp
@rm -f *.mp4