C/C++工程管理:makefile模板

C/C++工程,代码文件一旦多起来,需要考虑怎样有效的组织管理它们。多数情况下可以用CMake构建,少数时候例如嵌入式linux平台,用cmake也是完全没有问题的,但总是有工程师喜欢坚持用makefile,我不知道和u-boot使用makefile有没有关系,但如果坚持要用makefile,我认为要考虑如下2点:

  1. .o/.a/.so等,生成的各种二进制文件,不要放在.c/.cpp源码同级目录,而是放在独立的构建目录,并且目录应该自动创建。
  2. 分别指定C_SRCSCXX_SRCS很麻烦,应当支持让makefile自行过滤出来。

查找makefile的教程,关键字"万能通用makefile“,以及B站上排名第一的视频,大都在讲如何编一个可执行文件目标,很少有提及静态库动态库目标的;如果makefile解决的问题仅仅是可执行文件的构建,那么完全没必要用makefile,g++ *.cpp一把梭岂不是很好?

此外,有些人不知道Address Sanitizer这一内存问题排查利器的存在,它是可以在makefile中配置的。

针对以上问题,本人用一个实际项目fibercv的代码予以实践:fibercv的代码会构建静态库(libfibercv.a)、动态库(libfibercv.so)和可执行文件(demo),并且生成目录为obj目录。

C/C++代码的目录结构:

(base) home% tree
.
├── CMakeLists.txt
├── demo
│   └── main.cpp
├── deps
│   ├── glad
│   │   ├── glad.c
│   │   └── glad.h
│   ├── KHR
│   │   └── khrplatform.h
│   └── stb
│       ├── stb_image.h
│       └── stb_image_write.h
├── fibercv
│   ├── fc_log.c
│   ├── fc_log.h
│   ├── fibercv.h
│   ├── image.cpp
│   ├── image.h
│   ├── improc_private.cpp
│   ├── improc_private.h
│   ├── imshow.cpp
│   └── imshow.h
├── makefile
├── mingren.jpg
├── readme.md

对应的万能通用makefile如下:

#CC := clang
#CXX := clang++
#CXXFLAGS = -Ideps/ -I./
#LDFLAGS = -lglfw
#SRCS = fibercv/image.cpp fibercv/imshow.cpp fibercv/improc_private.cpp fibercv/fc_log.c deps/glad/glad.c demo/main.cpp
#all:
#	clang++ $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o demo


BUILD_DIR=obj

SRCS := fibercv/image.cpp fibercv/imshow.cpp fibercv/improc_private.cpp fibercv/fc_log.c deps/glad/glad.c
C_SRCS = $(filter %.c,$(SRCS))
CXX_SRCS = $(filter %.cpp,$(SRCS))

C_OBJS := $(patsubst %.c,$(BUILD_DIR)/%.o,$(C_SRCS))
CXX_OBJS := $(patsubst %.cpp,$(BUILD_DIR)/%.o,$(CXX_SRCS))

CC = clang
CXX = clang++
AR = ar crs

ASAN_FLAGS :=-g -fno-omit-frame-pointer -fsanitize=address

INCLUDE = -I./deps
CFLAGS += -fPIC $(ASAN_FLAGS) $(INCLUDE)
CXXFLAGS += -fPIC $(ASAN_FLAGS) $(INCLUDE)
SHARE = -fPIC -shared
SO_LDFLAGS += -lglfw

FIBERCV_LIB:=$(BUILD_DIR)/libfibercv.a
FIBERCV_SO:=$(BUILD_DIR)/libfibercv.so
DEMO=$(BUILD_DIR)/demo

all: $(FIBERCV_LIB) $(DEMO)
#all: $(FIBERCV_SO) $(DEMO)

info:
	@echo "C_SRCS:" $(C_SRCS)
	@echo "CXX_SRCS:" $(CXX_SRCS)
	@echo "C_OBJS:" $(C_OBJS)
	@echo "CXX_OBJS:" $(CXX_OBJS)

#-----------------------
# fibercv static library
#-----------------------
$(FIBERCV_LIB): $(CXX_OBJS) $(C_OBJS)
	$(AR) $@ $^

$(BUILD_DIR)/%.o: %.cpp
	mkdir -p $(@D)
	$(CXX) $(CXXFLAGS) -c $^ -o $@

$(BUILD_DIR)/%.o: %.c
	mkdir -p $(@D)
	$(CC) $(CFLAGS) -c $^ -o $@

#-----------------------
# fibercv shared library
#-----------------------
$(FIBERCV_SO): $(CXX_OBJS) $(C_OBJS)
	$(CXX) $(SHARE) $^ $(SO_LDFLAGS) -o $@

#-----------------------
# demo executable
#-----------------------
DEMO_SRCS := demo/main.cpp
DEMO_CXXFLAGS := -I./
export PKG_CONFIG_PATH=/home/zz/soft/glfw3/lib/pkgconfig:$PKG_CONFIG_PATH
DEMO_LDFLAGS := -lfibercv -Lobj/ `pkg-config --libs glfw3` -ldl -lpthread
$(DEMO): $(DEMO_SRCS)
	$(CXX) $(DEMO_CXXFLAGS) $^ $(DEMO_LDFLAGS) -o $@

.PHONY:
clean:
	rm -f $(C_OBJS)
	rm -f $(CXX_OBJS)
	rm -f $(FIBERCV_LIB)
	rm -f $(FIBERCV_SO)
	rm -f $(DEMO)

一些坑

  1. make sort 不符合预期
sort:
	cmake --build ${BUILD_DIR} --target sort
	./sort

看起来 sort 是 make 的保留字, make sort 执行时候不会执行 ./sort. 两种解决方法:

  • 把 target 改为别的名字
  • 添加 .PHONY 说明
.PHONY : sort

sort:
	cmake --build ${BUILD_DIR} --target sort
	./sort

参考

posted @ 2020-08-30 18:18  ChrisZZ  阅读(683)  评论(0编辑  收藏  举报