之前学的Makefile 不用的话经常会忘掉以写规则,记录下一些常用的功能的随笔,方便查找。
先来看一个Makefile文件,通过 foreach 和 patsubst 方法和
^、$< 变量来构建遍历的编译
CROSS =
CC = $(CROSS)gcc
CXX = $(CROSS)g++
DEBUG = -g
CFLAGS = $(DEBUG) -Wall -c -fPIC
MV = mv -f
RM = rm -rf
LN = ln -sf
TARGET = libhello.so
TOP_PATH = $(shell pwd)
INC_PATH = $(TOP_PATH)/include
SRC_PATH = $(TOP_PATH)
SRC_PATH += $(TOP_PATH)/src
MOD_PATH = $(TOP_PATH)/modules
MOD_LIB_PATH = $(MOD_PATH)/lib
MOD_INC_PATH = $(MOD_PATH)/include
DIRS = $(shell find $(SRC_PATH) -maxdepth 3 -type d)
FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))
##########################################################
# modules
##########################################################
modules =
MODULES_PATH = $(foreach m, $(modules), $(MOD_PATH)/$(m))
##########################################################
# srcs
##########################################################
SRCS_CPP += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))
SRCS_CC += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))
SRCS_C += $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))
##########################################################
# objs
##########################################################
OBJS_CPP = $(patsubst %.cpp, %.o, $(SRCS_CPP))
OBJS_CC = $(patsubst %.cc, %.o, $(SRCS_CC))
OBJS_C = $(patsubst %.c, %.o, $(SRCS_C))
##########################################################
# paths
##########################################################
INC_PATH += -I$(MOD_INC_PATH)
INC_PATH += -I$(MOD_PATH)
LIB_PATH += -L$(TOP_PATH)/lib
LIB_PATH += -L$(MOD_LIB_PATH)
##########################################################
# libs
##########################################################
##########################################################
# building
##########################################################
all:$(TARGET)
$(TARGET) : $(OBJS_CPP) $(OBJS_CC) $(OBJS_C)
@ for i in $(MODULES_PATH); \
do \
make -C $$i; \
done
@ $(CXX) $^ -o $@ $(LIB_PATH) $(LIBS)
@ echo Create $(TARGET) ok...
$(OBJS_CPP):%.o : %.cpp
$(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)
$(OBJS_CC):%.o : %.cc
$(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)
$(OBJS_C):%.o : %.c
$(CXX) $(CFLAGS) $< -o $@ $(INC_PATH)
$(OBJS_C):%.o : %.c
$(CC) $(CFLAGS) $< -o $@ $(INC_PATH)
.PHONY : clean
clean:
@ $(RM) $(TARGET) $(OBJS_C)
一些常见参数说明
-c
编译文件,但是没有链接,产生的结果就是目标文件(Object file)
-o
产生输出文件,不管是可执行的二进制文件,目标文件,汇编文件还是预处理文件。如果 -o 没有指明,默认的可执行文件为 a.out;目标文件为 .o;汇编文件为 .s;预处理文件为 .i
-O
在程序编译,链接的过程中,对源代码进行优化,导致的结果就是产生的二进制文件的执行效率会提高,但是编译链接的过程会变慢
-O2
更 -O 相比执行更好的优化,一般选这个
-Wall
产生详细的警告,出错信息,建议开启
-shared
生成动态库文件
# 指定编译时查找共享库的路径 -l 添加共享库名称,-L添加共享库路径。
DLIBS := -lmdroid -lrt
LDFLAGS = -L./lib/linux-arm/
# 指定运行时的库文件路径
RPATH = -Wl,-rpath=./lib/linux-arm/
生成位置无关的代码参数
-fpic
Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. Such code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system). If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000\. The x86 has no such limit.)
Position-independent code requires special support, and therefore works only on certain machines. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent.
When this flag is set, the macros __pic__ and __PIC__ are defined to 1.
-fPIC
If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on AArch64, m68k, PowerPC and SPARC.
Position-independent code requires special support, and therefore works only on certain machines.
When this flag is set, the macros __pic__ and __PIC__ are defined to 2.
-fpie
-fPIE
These options are similar to -fpic and -fPIC, but the generated position-independent code can be only linked into executables. Usually these options are used to compile code that will be linked using the -pie GCC option.
我们先看三段C++程序:
一、line1的源码
line1.h
#ifndef _LINE_1_H #define _LINE_1_H
void line1_print(const char *strMsg);
#endif
line1.cpp
#include "line1.h"
#include
void line1_print(const char *strMsg)
{
printf("This is line1 print %s.\r\n",strMsg);
}
二、line2的源码
line2.h
#ifndef _LINE_2_H #define _LINE_2_H
void line2_print(const char *strMsg);
#endif
line2.cpp
#include "line2.h"
#include
void line2_print(const char *strMsg)
{
printf("This is line2 print %s.\r\n",strMsg);
}
三、main的源码
main.cpp
#include "line1.h"
#include "line2.h"
int main(int argc,char **argv)
{
line1_print("hello runfarther");
line2_print("hello runfarther");
return 0;
}
对上面的代码,在不用Makefile时,我们可以直接用命令行来编译,得到我们的可执行程序main.out:
g++ -c main.c
g++ -c line1.c
g++ -c line2.c
g++ -o main.out main.o line1.o line2.o
为了编译工作更加方便,我们通常会编写Makefile来完成编译,我们先看一个用于编译和链接上面代码的例子:
main.out:main.o line1.o line2.o
g++ -o main.out main.o line1.o line2.o
main.o:main.c line1.h line2.h
g++ -c main.c
line1.o:line1.c line1.h
g++ -c line1.c
line2.o:line2.c line2.h
g++ -c line2.c
从例子可以看出,Makefile一般的格式是:
target:components rule
第一行表示的是依赖关系,第二行是规则,特别要注意,rule这行必须是TAB键开头。
比如说我们上面的那个Makefile文件的前面二行:
main.out:main.o line1.o line2.o
g++ -o main.out main.o line1.o line2.o
表示我们的目标(target)main.out的依赖对象(components)是main.o line1.o line2.o,当依赖的对象在被修改的话,就要去执行规则一行所指定的命令g++ -o main.out main.o line1.o line2.o。注意规则这行是以一个TAB键开头。 接下来我来介绍下Makefile中的四个有用的特殊符号意义和使用,他们分别是@、
^、$<
一、@
这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果,例如Makefile中的内容为:
DIR_OBJ=./obj
CMD_MKOBJDIR=if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi
mkobjdir:
@${CMD_MKOBJDIR}
命令行执行如下:
make mkobjdir
此时不会显示在命令行不会显示出 if [ -d
{DIR_OBJ}; fi
二、
^、$<
这三个分别表示:
$@ --代表目标文件(target)
$^ --代表所有的依赖文件(components)
$< --代表第一个依赖文件(components中最左边的那个)。
好了,知道了他们的意义后,如果使用上面三个变量,那么简化的Makefile文件为:
main.out:main.o line1.o line2.o
g++ -o $@ $^
main.o:main.c line1.h line2.h
g++ -c $<
line1.o:line1.c line1.h
g++ -c $<
line2.o:line2.c line2.h
g++ -c $<