Linux C/C++工程中可生成ELF、动/静态库文件的通用Makefile

最近写了一个*nix环境下的Makefile文件,支持编译C/C++,同时能够通过参数配置生成ELF目标文件、动态链接库(.so)和静态链接库(.a)文件。

Linux C/C++工程中可生成ELF、动/静态库文件的通用Makefile

一、Makefile文件配置说明

首先,根据生成的目标文件类型(ELF可执行文件,动态链接库文件或静态链接库文件),配置GEN_LIBSGEN_DYN_LIBEXCUTE_BINSTATIC_LIBSDYNAMIC_LIBS等变量。

其次,如果生成的目标文件依赖其它库文件,那么只要将LD_LIB_DIR设置成该动态库所在的目录,LD_LIBS设置成要链接的动态库文件名即可。更建议的做法是在当前C/C++工程的配置文件中设置LIBPATH参数为动态库所在的目录,这样就不用在设置变量LD_LIB_DIR的值了,例如:

export LIBPATH=/usr/lib64/:${LIBPATH}:/home/typecodes/lib

最后需要说明的是,变量$(PROJECT_DIR)表示当前C/C++工程的根路径,可以直接将本Makefile文件中的命令# PROJECT_DIR := /home/typecodes前面的#号去掉,然后设置成自己的工程根目录即可。同样,更建议在工程的配置文件中配置,例如:

export PROJECT_DIR=/home/typecodes

二、使用方法

在配置好Makefile文件中的变量对应的值后,直接将该文件放置在需要编译的C/C++工程目录下面,然后执行make或者make all就可以了。伪目标clean对应的命令make clean能够清除上次执行make命令产生的影响;伪目标help对应的命令make help能够在界面上输出Makefile文件中的重要变量的值,方便调试。

执行完make命令后,在当前目录下会生成.o目标文件以及.d依赖文件,ELF可执行文件放在工程的bin目录下,动/静态库文件放在工程的lib目录下。

Linux C/C++工程中可生成ELF、动/静态库文件的通用Makefile

三、附录:Makefile文件源码

已将下面的Makefile源文件托管到两个仓库中:

1、GitHub: https://github.com/vfhky/General_Makefile

2、Coding: https://coding.net/u/vfhky/p/General_Makefile/git

Makefile
##################################################################
#
# FILENAME   :	Makefile
# DESCRIPT	 :	A general makefile to generate an ELF or a
# 					dynamic or a static library for C/C++ project.
# AUTHOR	 : 	vfhky  2015.08.07
# URI 		 :	https://typecodes.com/cseries/cppgeneralmakefile.html
#
##################################################################

.PHONY: all clean help
all: 

# Some important on-off settings. You can not be too careful about them.
DEBUG       	:= y
# Flag of generate a dynamic lib or a static lib: y means yes. If the target is a excutable file, it should be blank!
GEN_LIBS    	:= y
# Flag of generate a dynamic lib: y means yes. It should be blank unless you want to generate a dynamic lib!
GEN_DYN_LIB		:= y
# The name of target bin file.Please let it be blank unless the target is a excutable file. 
EXCUTE_BIN		:= 
# Name of the static lib. It should be blank unless the target is a static lib, then the GEN_LIBS is y and GEN_DYN_LIB is blank.
# STATIC_LIBS		:= libsrcpbl.a
# Name of the dynamic lib. It should be blank unless the target is a dynamic lib, then the GEN_LIBS is y and GEN_DYN_LIB is y.
DYNAMIC_LIBS 	:= libsrcpbl.so

# Environment settings. The value of PROJECT_DIR shoule be set in the *nix system as the the absolute dir path of your project.
# PROJECT_DIR	:= /home/typecodes
#CURDIR    		:= $(PROJECT_DIR)/src/pbl
CURDIR     		:= $(shell pwd)
PRG_BIN_DIR		:= $(PROJECT_DIR)/bin
PRG_LIB_DIR		:= $(PROJECT_DIR)/lib
PRG_INC_DIR		:= $(PROJECT_DIR)/include

# Cross compile tools defined. You needn't modify these vars below generally.
AS    	:= as
LD    	:= ld
CC    	:= gcc
CXX   	:= g++
CPP   	:= $(CC) -E
AR      := ar rcs
NM      := nm
STRIP   := strip
RANLIB 	:= ranlib
STD_OPT	:= -std=c99 -D_GNU_SOURCE 
CC    	+= $(STD_OPT)
CXX    	+= $(STD_OPT)

# *nix system tools defined. You needn't modify these vars below generally.
CP		:= cp
SED		:= sed
FIND	:= find
MKDIR 	:= mkdir -p
XARGS	:= xargs
MV    	:= mv
RM    	:= rm -rf


# Get .c, .cpp source files by searching from current directory.
CUR_SRC_DIR	= $(shell ls -AxR $(CURDIR)|grep ":"|tr -d ':')
CUR_SRC 	:= $(foreach subdir,$(CUR_SRC_DIR),$(wildcard $(subdir)/*.c $(subdir)/*.cpp))
#CUR_SRC 	:= $(shell find . -name "*.c" -o -name "*.cpp"|sed -e 's,./,,')
CUR_C   	:= $(filter %.c, $(CUR_SRC))
CUR_CPP 	:= $(filter %.cpp, $(CUR_SRC))

# Get the include files, object files, dependent files by searching from PRG_INC_DIR.
CUR_INC_DIR = $(shell ls -AxR $(PRG_INC_DIR)|grep ":"|tr -d ':')
CUR_INC 	:= $(foreach subdir,$(CUR_INC_DIR),$(subdir)/*.h)
SRC_H   	:= $(filter %.h, $(CUR_INC))
#CUR_OBJ	:= $(addprefix $(PRG_BIN_DIR)/,$(strip $(CUR_CPP:.cpp=.o) $(CUR_C:.c=.o)))
#CUR_OBJ	:= $(addprefix $(PRG_BIN_DIR)/,$(notdir $(CUR_CPP:.cpp=.o) $(CUR_C:.c=.o)))
CUR_OBJ		:= $(strip $(CUR_CPP:.cpp=.o) $(CUR_C:.c=.o))
#CUR_DEP	:= $(addprefix $(PRG_BIN_DIR)/,$(notdir $(CUR_CPP:.cpp=.d) $(CUR_C:.c=.d)))
CUR_DEP		:= $(strip $(CUR_CPP:.cpp=.d) $(CUR_C:.c=.d))

# Create directory in the header files, bin and library directory.
$(foreach dirname,$(sort $(PRG_INC_DIR) $(PRG_BIN_DIR) $(PRG_LIB_DIR)),\
  $(shell $(MKDIR) $(dirname)))

# Complie and link variables. LD_LIBS means the dynamic or static library needed for the object file.
CFLAGS     	:= $(if $(DEBUG),-g -Wall, -O2 -Wall)
CFLAGS     	+= $(if $(GEN_DYN_LIB), $(addprefix -fPIC -I ,$(sort $(dir $(SRC_H)))), $(addprefix -I ,$(sort $(dir $(SRC_H)))))
CXXFLAGS   	= $(CFLAGS)
LDFLAGS    	:= 
LD_LIB_DIR 	:= #-L $(PRG_LIB_DIR)
LD_LIBS	   	:= #-lsrcpbl -lmysqlclient
XLD_FLG	   	:= -Xlinker "-(" $(LDFLAGS) -Xlinker "-)"

# Add vpath.
vpath %.h $(sort $(dir $(SRC_H)))
vpath %.c $(sort $(dir $(CUR_C)))
vpath %.cpp $(sort $(dir $(CUR_CPP)))

# Generate depend files.
ifneq "$(MAKECMDGOALS)" "clean"
sinclude $(CUR_DEP)
endif

# Gen_depend(depend-file,source-file,object-file,cc). This command-package is used to generate a depend file with a postfix of .d.
define gen_depend
  @set -e;                                      \
  $(RM) $1;                                     \
  $4 $(CFLAGS) -MM $2 |                         \
  $(SED) 's,\($(notdir $3)\): ,$3: ,' > $1.tmp; \
  $(SED) -e 's/#.*//'                           \
         -e 's/^[^:]*: *//'                     \
         -e 's/ *\\$$//'                        \
         -e '/^$$/ d'                           \
         -e 's/$$/ :/' < $1.tmp >> $1.tmp;      \
  $(MV) $1.tmp $1;
endef

# Rules to generate objects file(.o) from .c or .cpp files.
$(CURDIR)/%.o: %.c
	@$(call gen_depend,$(patsubst %.o,%.d,$@),$<,$@,$(CC))
	$(CC) $(CFLAGS) -o $@ -c $<

$(CURDIR)/%.o: %.cpp
	@$(call gen_depend,$(patsubst %.o,%.d,$@),$<,$@,$(CXX))
	$(CXX) $(CXXFLAGS) -o $@ -c $<

# Gen_excbin(target,CUR_OBJ,cc). This command-package is used to generate a excutable file.
define gen_excbin
  ULT_BIN += $(PRG_BIN_DIR)/$1
  $(PRG_BIN_DIR)/$1: $2
	$3 $(LDFLAGS) $$^ $(LD_LIB_DIR) $(LD_LIBS) $(XLD_FLG) -o $$@
endef

# Gen_libs(libs,CUR_OBJ,cc). This command-package is used to generate a dynamic lib or a static lib.
define gen_libs
  ULT_LIBS += $(PRG_LIB_DIR)/$1
  $(PRG_LIB_DIR)/$1: $2
	$3 $(if $(GEN_DYN_LIB),-shared $$^ $(CXXFLAGS) $(LD_LIB_DIR) $(LD_LIBS) $(XLD_FLG) -o $$@,$$@ $$^)
endef

# Call gen_excbin to generate a excutale file.
$(foreach bin,$(EXCUTE_BIN),$(eval $(call gen_excbin,$(bin),$(CUR_OBJ),$(CXX))))

# Call gen_libs to generate a dynamic lib.
$(foreach lib,$(DYNAMIC_LIBS),$(eval $(call gen_libs,$(lib),$(CUR_OBJ),$(CXX))))

# Call gen_libs to generate a static lib.
$(foreach lib,$(STATIC_LIBS),$(eval $(call gen_libs,$(lib),$(CUR_OBJ),$(AR))))


all: $(ULT_BIN) $(ULT_LIBS)


clean: 
	-$(FIND) $(CURDIR) -name "*.o" -o -name "*.d" | $(XARGS) $(RM)
	-$(RM) $(ULT_BIN)
	-$(RM) $(ULT_LIBS)


help:
	@echo PROJECT_DIR=[$(PROJECT_DIR)]
	@echo CURDIR=[$(CURDIR)]
	@echo PRG_BIN_DIR=[$(PRG_BIN_DIR)]
	@echo PRG_LIB_DIR=[$(PRG_LIB_DIR)]
	@echo PRG_INC_DIR=[$(PRG_INC_DIR)]
	@echo CUR_SRC_DIR=[$(CUR_SRC_DIR)]
	@echo CUR_SRC=[$(CUR_SRC)]
	@echo CUR_C=[$(CUR_C)]
	@echo CUR_CPP=[$(CUR_CPP)]
	@echo CUR_OBJ=[$(CUR_OBJ)]
	@echo CUR_DEP=[$(CUR_DEP)]
	@echo STD_OPT=[$(STD_OPT)]
	@echo CFLAGS=[$(CFLAGS)]
	@echo STATIC_LIBS=[$(STATIC_LIBS)]
	@echo DYNAMIC_LIBS=[$(DYNAMIC_LIBS)]

评论

评论加载中…