makefile常用编译选项

我们习惯创建一个环境变量文件Inc.mk来定义常用的变量

CC = gcc
CXX = g++ -std=c++11
AR ?= ar
ARFLAGS = -scurv
RANLIB ?= ranlib

CFLAGS ?=
CXXFLAGS ?=
INCLUDE ?=
LDFLAGS ?=

CFLAGS   += -Wall -g -fPIC -Wl,-z -Wl,defs -DDEBUG
CXXFLAGS += -Wall -g -fPIC -Wl,-z -Wl,defs -DDEBUG

%.o: %.cpp 
	$(CXX) $(CXXFLAGS) $(INCLUDE) -c $<

%.o: %.c
	$(CC) $(CFLAGS) $(INCLUDE) -c $<

ar命令:

-s 创建归档索引(等同ranlib)

-c 如果必须创建库,请不要发出警告

-u 仅替换比当前存档内容更新的文件

-r 替换现有文件或将新文件插入存档

-v 详细说明

ar -s其实等同于ranlib,由于早期linux系统ar只是单纯打包多个.o文件到.a静态库,而不处理.o的符号表,所以需要ranlib来生成链接所需要的符号信息。现在其实不需要第二步ranlib。

编译选项:

-w 关闭所有警告信息

-Wall 提供有用的警告信息

-Werror 警告信息变成错误,必须处理

-g 产生调试信息,给调试器用,可以用-g3这个级别可以调试宏;如果调试器是gdb,建议使用-ggdb或者-ggdb3

-fPIC 是生成动态库使用的,编译器就输出位置无关目标码,适用于动态连接,即使分支需要大范围转移

-Wl,-z -Wl,defs 链接编辑器生成共享库输出文件时,允许在链接编辑结束时仍存在未定义符号。此缺省行为允许共享库从将其定义为依赖性的动态可执行文件导入符号。-z defs选项强制在存在任何未定义符号的情况下生成致命错误

-DDEBUG 相当于定义了宏DEBUG,代码中可以用#ifdef DEBUG来控制调试输出信息等

现在来看下正文Makefile文件

include ../Inc.mk

DIR_MODULES=crypto \
            net

SRC := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRC))
SO_NAME = libcomm.so
SO_BIN = $(LIB_DIR)/$(SO_NAME)
A_NAME = libcomm.a
A_BIN = $(LIB_DIR)/$(A_NAME)

INCLUDE += -I$(XML_INC) 
LDFLAGS += -L$(LIB_DIR) -ltinyxml2

all : clean $(SO_BIN) $(A_BIN)
	@for dir in $(DIR_MODULES); \
	do \
		make -C $$dir; \
		echo; \
	done

$(SO_BIN) : $(OBJS)
	$(CXX) $(CXXFLAGS) -shared -Wl,-soname,$(SO_NAME) -o $@ $^ $(LDFLAGS)

$(A_BIN) : $(OBJS)
	$(AR) $(ARFLAGS) $@ $?
	$(RANLIB) $@

clean :
	@for dir in $(DIR_MODULES); \
	do \
		make -C $$dir clean; \
		echo; \
	done
	rm -rf $(OBJS) $(SO_BIN) $(A_BIN)

静态库的生成一般是两步:

ar -scurv libcomm.a *.o

ranlib libcomm.a

这是早期linux做法,现在可以省去ranlib这一步

动态库的生成需要用到-shared

-Wl,-soname 是为了提高新老版本库的兼容性,通过soname指定我们所希望的库版本

include ../Inc.mk

SRC := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRC))
BIN = $(BIN_DIR)/server

INCLUDE += -I$(COMM_INC) -I$(XML_INC)
LDFLAGS += -L$(LIB_DIR) -ltinyxml2 -lcomm

all : clean $(BIN)

$(BIN) : $(OBJS)
	$(CXX) $(CXXFLAGS) -Wl,-rpath=$(LIB_DIR) -o $@ $^ $(LDFLAGS)

clean :
	rm -rf $(OBJS) $(BIN)

-Wl,-rpath 是为了指定我们链接的库路径,就不需要再去修改LD_LIBRARY_PATH变量了

这里我们看到每个Makefile文件都include ../Inc.mk

1. 在Inc.mk中,我们定义了固定的几个参数,gcc,g++还有编译选项等,在Makefile中include之后就可以直接使用,但是INCLUDE和LDFLAGS我们并没有固定,而是在Makefile中自定义,因为它们要引用的头文件,库文件都是各取所需。

2. 在Inc.mk中,我们定义了.c生成.o和.cpp生成.o的规则,在Makefile中include之后就可以直接使用了,所以我们在Makefile中只需要写.o生成可执行文件的规则就行了,生成可执行文件需要包含的头文件INCLUDE和需要链接的库LDFLAGS我们自定义,就配合完美了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章