1.写在前面
本篇文章讲的是接前面Makefile之编译多个可执行程序中第二个需求,并延伸到对正规工程的编译。
2.工程
我接触的工程有2种情况:
- 所有源文件都放一个目录
- 按模块分放不同的目录
下面按照这两种情况讲解。
3.所有源文件都放一个目录
不建议所有源文件都放一个目录,当工程大时,一个目录下会有很多源文件,建议采用第二种方式,按模块分放不同的目录。
编译这种工程时,比较方便,一个Makefile就可以编译出可执行文件,如下:
CC = g++
CFLAGES = -g -Wall
INCLUDE =
LIBS =
OBJDIR = .
TARGET = obj
SRCS :=$(wildcard *.cpp)
OBJS :=$(patsubst %cpp, %o, $(SRCS))
ES = $(shell if[-d $(OBJDIR)];then echo "h";else echo "no";fi;)
all: $(TARGET) clean
#转换为.o文件
%.o:%.cpp
$(CC) $(CFLAGES) -c $< $(INCLUDE)
#将.o文件链接成可执行文件
$(TARGET):$(OBJS)
$(CC) $(CFLAGES) -o $@ $(OBJS) $(LIBS)
ifeq($(ES),no)
@ echo "Create obj directory";
@ mkdir -p $(OBJDIR)
endif
mv $@ $(OBJDIR)
clean:
rm -rf *.o
4.按模块分放不同的目录
按模块分放不同目录,主要特点就是结构清晰,但是每个模块都需要一个Makefile,最后由一个Makefile编译出可执行程序。
有三种编译方法:
- 每个模块1个Makefile,将模块编译成.o文件,将.o文件拷贝到main函数目录,链接成可执行程序。
- 每个模块1个Makefile,将模块编译成.a文件静态链接库,链接时指定静态链接库路径。
- 每个模块1个Makefile,将模块编译成.so文件动态链接库,链接时指定动态链接库路径,运行时,需将可执行程序和.so文件拷贝至目录。
4.1 模块的Makefile
CC = g++
CFLAGES = -g -Wall
INCLUDE =
LIBS =
OBJDIR = .
TARGET = obj.a
SRCS :=$(wildcard *.cpp)
OBJS :=$(patsubst %cpp, %o, $(SRCS))
ES = $(shell if[-d $(OBJDIR)];then echo "h";else echo "no";fi;) all: $(TARGET) clean
#转换为.o文件
%.o:%.cpp
$(CC) $(CFLAGES) -c $< $(INCLUDE)
ifeq($(ES),no)
@ echo "Create obj directory";
endif
$(TARGET):$(OBJS)
#转换为.a文件
ar -crv $@ $(OBJS)
#转换为.so文件
$(CC) -shared -fPIC -o $@ $(OBJS)
#不转换,则直接使用.o文件
mv $@ $(OBJDIR)
clean: rm -rf *.o
4.2 main模块的makefile
CC = g++
CFLAGES = -g -Wall
#此处要加模块头文件路径
INCLUDE = -I . -I /home/test
#此处要加静态链接库的路径
LIBS = -L -libobj
OBJDIR = .
TARGET = obj
SRCS :=$(wildcard *.cpp)
#如使用.o文件,OBJS后面加上模块.o文件的全路径
OBJS :=$(patsubst %cpp, %o, $(SRCS))
ES = $(shell if[-d $(OBJDIR)];then echo "h";else echo "no";fi;) all: $(TARGET) clean
#将main转换为.o文件
%.o:%.cpp
$(CC) $(CFLAGES) -c $< $(INCLUDE)
ifeq($(ES),no)
@ echo "Create obj directory";
endif
$(TARGET):$(OBJS)
$(CC) $(CFLAGES) -o $@ $(OBJS) $(LIBS)
#不转换,则直接使用.o文件
mv $@ $(OBJDIR)
clean: rm -rf *.o
注:此处未说明动态链接的参数,稍后补充。