Makefile使用

来源:互联网 发布:360度全景软件 编辑:程序博客网 时间:2024/06/06 13:30

一、Makefile简介
1、Makefile由三部分组成,目标,依赖项,命令三部分组成。格式如下
目标:依赖性
(tab键)命令

2、编译过程
 2.1各个cpp文件编译成为独立的目标文件(.o文件)(语法检验、函数声明查找等)
 2.2各个目标文件链接成为可执行文件(查找函数定义、外部变量、外部函数等)
 
二、简单Makefile例子
//准备文件main.cpp、test1.cpp、test1.h
//main.cpp文件
include "test1.h"
int main(int arg, char** args)
{
 Print();
 return 0;
}

//test1.cpp
#include "test1.h"
#include <stdio.h>

void Print()
{
 printf("Print() function\n");
}

//test1.h
#ifndef __TEST1_H20130903__
#define __TEST1_H20130903__
void Print();
#endif

//Makefile文件
CXX = g++
#目标文件,用变量表示
OBJS = main.o test1.o
#-g 编译debug版本 -O编译优化 -Wall 编译输出所有警告信息
CFLAGS = -g -O -Wall


all:start

#链接目标文件形成执行文件
start: $(OBJS)
  $(CXX) $(CFLAGS) -o main $(OBJS)

#编译各个文件形成目标文件(.o文件)
test1.o : test1.cpp test1.h
  $(CXX) $(CFLAGS) -c  test1.cpp test1.h  
main.o : main.cpp test1.h
 $(CXX) $(CFLAGS) -c  main.cpp test1.h 
 
二、复杂例子
XX = g++
CFLAGS = -Wall -O -g
TARGET = ./main

#wildcard 获取.c、.cpp文件列表
SOURCES = $(wildcard *.c *.cpp)
#patsubst获取目标文件列表
OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))

$(TARGET) : $(OBJS)
 $(XX) $(OBJS) -o $(TARGET)
 chmod a+x $(TARGET)

#这里有三个比较有用的内部变量。$@扩展成当前规则的目的文件名,$<扩展成依靠列表的第一个依靠文件,$^扩展成整个依靠的列表(除掉重复文件名)
%.o: %.c
 $(CC) $(CFLAGS) -c $< -o $@
 
%.o:%.cpp
 $(XX) $(CFLAGS) -c $< -o $@

#清空目标文件、执行文件
clean:
 rm -rf *.o main
#查看源文件
source:
 @echo $(SOURCES)
#查看目标文件
objs:
 @echo $(OBJS)

三、动态库制作与使用
 例如 假设main.cpp,hello.h,hello.cpp,其中main.cpp调用了hello类中的方法
 
1、生成hello.so

  g++ -shared hello.cpp -o libtest.so
 
2、编译main.cpp,并链接,并指定运行时libhello.so的位置

  g++ main.cpp -ltest -L./ -Wl,-rpath=./ -o main

      特殊说明:-L./  用于说明在编译时,指定动态库的路径  -Wl,-rpath=./ 用于指定执行程序时,指定动态库路径

3、编译多个cpp生成so
  g++ -fPIC -c file1.c
  g++ -fPIC -c file2.c
  g++ -shared libxxx.so file1.o file2.o
 
 4、g++编译参数解析
  -shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
 
  -fpic 使输出的对象模块是按照可重定位地址方式生成的。
 
  -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

  -L.:表示要连接的库在当前目录中

  -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

  LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
 
 5、测试共享库
 命令:  ldd main  输出在命令行上指定的每个程序或共享库需要的共享库。
 
 四、静态库创建及使用
 1、静态库的后缀是.a,它的产生分两步
    Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
    Step 2.ar命令将很多.o转换成.a,成文静态库
 2、编译方法
    # g++ -c test1.cpp -o tes1.o
    # ar cr libtest1.a test1.o
 3、使用静态库
 选项说明: -l用于链接库文件 -L是指明链接时的路径(选项可以和后面的内容连写,如-L./lib),以下两种方式效果相同:
    #g++ -o main main.cpp -L ./lib -l test1   (用-l指出库的名称为test1,g++编译时自动将其解析为libtest1.a)
 #g++ -o main main.cpp -L ./lib libtest1.a  (不用-l选项,直接给出库的名称)
 
五、动态库与静态库名称
  静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称
  动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号
 
  注意,g++会在静态库名前加上前缀lib,然后追加扩展名.a(.so)得到的静态库文件名来查找静态库文件(动态库文件)。
 
 六、make使用的自动变量
 1、 $@规则目标的文件名。如果目标是档案文件的一个成员,$@就是档案文件的名称
 2、 @%当目标是档案文件的一个成员时,$%是该成员的名称。若不是档案文件的一个成员,$%为空
 3、 @<第一个依赖文件的名称
 4、 @?以空格隔开的比目标新的所有依赖文件名。在依靠文件是档案文件的成员时,只是用成员的名称。
 5、 @^以空格隔开的所有依赖文件名。在依赖文件是档案文件的成员时,只使用成员的名称。无论一个依赖文件出现过多次,$^值只包含其名称的一个拷贝。

 例子:
 all:main.cpp test1.cpp
 g++ main.cpp -ltest -L./ -Wl,-rpath=./ -o main
 @echo $@
 @echo $<
 @echo $?
 @echo $^
 
 输出结果如下:
 all
 main.cpp
 main.cpp test1.cpp
 main.cpp test1.cpp
 

原创粉丝点击