文章目录


现在搞深度学习都在linux平台,经常遇到gcc手动编译的时候。由于linux平台没有通用的IDE,大家都是靠Makefile配置文件进行make。在学习darknet框架的过程中,决定要顺便搞清楚Makefile的写法和参数配置。Makefile完整的教程网上有很多,我暂时也不打算完整学一遍,仅仅把遇到的都搞懂,下次遇到新的东西再学。
以下是我通过网上搜索整理好的darknet的Makefile文件注释,希望能够帮到其他人。如有错误,希望包涵。

1. darknet Makefile注释

# Makefile中变量定义如:标签=内容,后面的变量引用需要$(标签)
GPU=0
CUDNN=0
OPENCV=0
OPENMP=0 # OpenMP是一套支持跨平台共享内存方式的多线程并发的编程API
DEBUG=0

ARCH= -gencode arch=compute_30,code=sm_30 \
      -gencode arch=compute_35,code=sm_35 \
      -gencode arch=compute_50,code=[sm_50,compute_50] \
      -gencode arch=compute_52,code=[sm_52,compute_52]
#      -gencode arch=compute_20,code=[sm_20,sm_21] \ This one is deprecated?

# This is what I use, uncomment if you know your arch and want to specify
# ARCH= -gencode arch=compute_52,code=compute_52

VPATH=./src/:./examples
SLIB=libdarknet.so #待生成的动态链接库
ALIB=libdarknet.a  #待生成的静态链接库
EXEC=darknet #待生成的执行文件名称
OBJDIR=./obj/ #生成目标文件的目录,即当期目录下obj子目录

CC=gcc
CPP=g++
NVCC=nvcc #nvidia编译器
AR=ar 	#ar,Linux系统的一个备份压缩命令,用于创建、修改备存文件(archive)。这里的ar命令是将目标文件打包为静态链接库。
ARFLAGS=rcs #ar命令的参数 -rcs。-r:将文件插入备存文件中 c:建立备存文件 s:若备存文件中包含了对象模式,可利用此参数建立备存文件的符号表
OPTS=-Ofast
#编译选项中指定 -pthread 会附加一个宏定义 -D_REENTRANT,该宏会导致 libc 头文件选择那些thread-safe的实现;
#链接选项中指定 -pthread 则同 -lpthread 一样,只表示链接 POSIX thread 库。由于 libc 用于适应 thread-safe 的宏定义可能变化,
#因此在编译和链接时都使用 -pthread 选项而不是传统的 -lpthread 能够保持向后兼容,并提高命令行的一致性。
LDFLAGS= -lm -pthread
COMMON= -Iinclude/ -Isrc/
#-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
#unknow-pragmas:使用未知的#pragma指令
CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC

ifeq ($(OPENMP), 1) #条件判断
CFLAGS+= -fopenmp
endif

ifeq ($(DEBUG), 1)
OPTS=-O0 -g #-g选项可以产生带有调试信息的目标代码
endif

CFLAGS+=$(OPTS)

ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV #相当于C语言中的#define OPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv` -lstdc++  #pkg-config能够把头文件和库文件的位置指出来,给编译器使用
COMMON+= `pkg-config --cflags opencv`
endif

ifeq ($(GPU), 1)
COMMON+= -DGPU -I/usr/local/cuda/include/
CFLAGS+= -DGPU
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
endif

ifeq ($(CUDNN), 1)
COMMON+= -DCUDNN
CFLAGS+= -DCUDNN
LDFLAGS+= -lcudnn
endif

#OBJ表示需要生成的目标文件
OBJ=gemm.o utils.o cuda.o deconvolutional_layer.o convolutional_layer.o list.o image.o activations.o im2col.o col2im.o blas.o crop_layer.o dropout_layer.o maxpool_layer.o softmax_layer.o data.o matrix.o network.o connected_layer.o cost_layer.o parser.o option_list.o detection_layer.o route_layer.o upsample_layer.o box.o normalization_layer.o avgpool_layer.o layer.o local_layer.o shortcut_layer.o logistic_layer.o activation_layer.o rnn_layer.o gru_layer.o crnn_layer.o demo.o batchnorm_layer.o region_layer.o reorg_layer.o tree.o  lstm_layer.o l2norm_layer.o yolo_layer.o iseg_layer.o image_opencv.o
EXECOBJA=captcha.o lsd.o super.o art.o tag.o cifar.o go.o rnn.o segmenter.o regressor.o classifier.o coco.o yolo.o detector.o nightmare.o instance-segmenter.o darknet.o
ifeq ($(GPU), 1)
LDFLAGS+= -lstdc++
OBJ+=convolutional_kernels.o deconvolutional_kernels.o activation_kernels.o im2col_kernels.o col2im_kernels.o blas_kernels.o crop_layer_kernels.o dropout_layer_kernels.o maxpool_layer_kernels.o avgpool_layer_kernels.o
endif

EXECOBJ = $(addprefix $(OBJDIR), $(EXECOBJA)) #addprefix统一添加前缀
OBJS = $(addprefix $(OBJDIR), $(OBJ))
DEPS = $(wildcard src/*.h) Makefile include/darknet.h #wildcard展开src文件下所有后缀为.h的头文件;

all: obj backup results $(SLIB) $(ALIB) $(EXEC) #主要任务all和其所有依赖
#all: obj  results $(SLIB) $(ALIB) $(EXEC)


$(EXEC): $(EXECOBJ) $(ALIB)
	$(CC) $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(ALIB) #$@自动变量,表示目标名称,这里指$(EXEC),实际为darknet;$^指代所有前置条件,之间以空格分隔

$(ALIB): $(OBJS)
	$(AR) $(ARFLAGS) $@ $^

$(SLIB): $(OBJS)
	$(CC) $(CFLAGS) -shared $^ -o $@ $(LDFLAGS) #-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

$(OBJDIR)%.o: %.cpp $(DEPS)
	$(CPP) $(COMMON) $(CFLAGS) -c $< -o $@ #$<指代第一个前置条件,这里指%.cpp; -c编译、汇编到目标代码,不进行链接

$(OBJDIR)%.o: %.c $(DEPS)
	$(CC) $(COMMON) $(CFLAGS) -c $< -o $@

$(OBJDIR)%.o: %.cu $(DEPS)
	$(NVCC) $(ARCH) $(COMMON) --compiler-options "$(CFLAGS)" -c $< -o $@

obj:
	mkdir -p obj #-p 确保目录名称存在,不存在的就建一个
backup:
	mkdir -p backup
results:
	mkdir -p results

.PHONY: clean

clean:
	rm -rf $(OBJS) $(SLIB) $(ALIB) $(EXEC) $(EXECOBJ) $(OBJDIR)/*

2. reference

https://www.cnblogs.com/fengbeihong/p/3641384.html
http://www.shanghai.ws/gnu/gcc_1.htm
https://www.cnblogs.com/suntp/p/6473751.html

10-07 14:17