TypeCodes

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

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

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

1 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

2 使用方法

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

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

3 附录:Makefile文件源码

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

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

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
##################################################################
#
# 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)]

Comments »