makefile学习

makefile学习

1. GCC默认头文件搜索路径

echo | gcc -v -x c -E -

2. 编译过程

四个阶段:预处理,编译,汇编,链接

2.1 预处理阶段

预处理器(cpp) hello.c --> hello.i

展开头文件,将头文件的内容复制到#icnlude 的地方

宏替换

删除注释或将注释变为空行

进行条件编译的逻辑(#ifndef #else #endif)

2.2 编译

编译器(ccl) hello.i --> hello.s (汇编语言)

逐行检查语法错误

2.3 汇编阶段

汇编器(as) hello.s --> hello.o 机器语言(二进制代码)

用文本编辑器打开hello.o文件,将是乱码

2.4 链接阶段

连接器(ld) hello.o printf.o —> hello(可执行程序)

将多个编译好的目标文件(.o文件)以及库文件链接在一起,形成一个可执行程序。

3. C语言的编译

3.1 c语言相关后缀

.a 静态库

.c 源文件

.h 头文件

.i 预处理文件

.o 目标文件

.s 汇编文件

.so 动态库,共享库,运行时库

// hello.c
#include <stdio.h>

int main(int argc,char* argv[])
{
        printf("hello world\n");

        return 0;
}

3.2 预处理阶段(hello.c --> hello.i)

gcc -E hello.c 		// 不会生成 .i 文件
gcc -E hello.c -o hello.i		// 生成 hello.i文件
  • -E 选项告诉编译器只进行预处理操作
  • -o 选项把预处理的结果输出到指定文件

3.3 编译阶段(hello.i --> hello.s)

gcc -S hello.i 
gcc -S hello.i -o hello.s
// 也可以直接编译 hello.c 文件
  • -S 选项告诉编译器,进行预处理和编译生成汇编语言操作

3.4 汇编阶段(hello.s --> hello.o)

gcc -c hello.s 	// 也可以直接编译 hello.c 文件, gcc -c hello.cls
gcc -c hello.s -o hello.o
gcc -c hello1.c hello2.c hello3.c   // 编译多个.c文件

3.5 链接阶段(hello.o --> hello)

gcc hello.o 	// 生成了 a.out文件
gcc hello.o -o hello

3.6 执行程序

./hello

3.8 一步执行

gcc hello.c -o helloworld
./helloworld

4. C语言 .a 静态库的编译与链接

//TODO: add.c

int add(int a,int b)
{
        return a+b;
}
//TODO: minus.c

int minus(int a,int b)
{
        return a-b;
}
//TODO: main.c

#include <stdio.h>

int add(int a,int b);
int minus(int a,int b);

int main(int argc,char* argv[])
{
        int a=10;
        int b=5;
        int c;
        printf("a+b=%d\n",add(a,b));
        printf("a-b=%d\n",minus(a,b));


        return 0;
}

4.1 编译成 .o 文件

gcc -c [.c] -o [自定义文件名]
gcc -c [.c] [.c] ...   // 编译多个文件
gcc -c add.c minus.c   // 生成 add.o  minus.o

4.2 编译静态库

ar -r [lib自定义库名.a] [.o] [.o] ...   // 静态库名一般以lib开头
ar -r liboperation.a add.o minus.o   // 生成 liboperation.a 静态库

4.3 链接成可执行文件

gcc [.c] [.a] -o [自定义输出文件名]
gcc [.c] -o [自定义输出文件名] -l[库名] -L[库所在路径]
gcc main.c liboperation.a -o exec    // 链接目标文件和库文件,生成了可执行程序 exec
gcc main.o add.o minus.o -o exec1  	// 链接目标文件,生成了可执行程序 exec1

5. C语言 .so 动态库的编译与链接

5.1 编译二进制.o文件

gcc -c -fpic [.c/.cpp] [.c/.cpp] ...
 gcc -c -fpic add.c minus.c   // 生成了 add.o  minus.o

5.2 编译动态库文件

gcc -shared [.o] [.o] ... -o [lib自定义库名.so]
gcc -shared add.o minus.o -o liboperation.so
# 直接生成 .so
gcc -fpic -shared [.c] [.c] [...] -o lib[库名].so

libname.so.x.y.z

lib --> 固定代表共享库

name --> 共享库名称

so --> 固定后缀

x --> 主版本号

y --> 次版本号

z --> 发行版本号

5.3 链接动态库生成可执行程序

gcc [.c/.cpp] -o [自定义可执行文件名] -l[库名] -L[库路径] -Wl, -rpath=[库路径]
gcc main.c -o main -loperation -L/home/book/Desktop/cprogram/Shared_Library 
// 库名是 operation,不是 liboperation

5.4 出现的问题(动态库没有加载到内存中)

./main

./main: error while loading shared libraries: liboperation.so: cannot open shared object file: No such file or directory

加载动态库失败了:liboperation ,不能打开动态库文件。

静态库:GCC进行链接时,会把静态库中的代码打包到可执行程序中

动态库:运行时才加载的库,GCC进行链接时,动态库的代码不会被打包到可执行程序中

使用命令 ldd xxx检查动态库的依赖关系

由于动态库没有被加载到内存中,导致./main制运行失败

解决动态库加载失败问题
(1)临时修改
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/cprogram/Shared_Library
(2)当前用户永久修改
# 修改当前用户的环境变量文件 (~/.bashrc) (永久设置,针对当前用户)
vim ~/.bashrc
# 在文件末尾添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/cprogram/Shared_Library
# 让环境变量立即有效
source ~/.bashrc
(3)所有用户永久修改
# 修改 /etc/profile ,即修改系统环境变量(永久设置,针对所有用户)
sudo vim /etc/profile
# 在文件末尾添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/cprogram/Shared_Library
# 让环境变量立即生效
source /etc/profile

6. C++的编译

.a 静态库文件

.c/.c++/.cc/.cp/.cpp/.cxx 源文件

.h 头文件

.ii 预处理文件

.o 目标文件

.s 汇编代码

.so 动态库文件

c++编译时将c的gcc换为g++

7. Makefile基本格式,规则,伪目标

7.1 基本格式

targets: prerequisties				# targets依赖于prerequisties
[tab键]command
  • target : 目标文件,可以是Object file,也可以是执行文件,还可以是一个标签(Label)。

  • prerequisties :要生成那个targets所需要的文件或目标。

  • command : 是make需要执行的命令

    dubug:
    	@echo hello		
    # @ 将命令隐藏起来。 make debug 时不会显示echo hello,只会显示hello7.2
    

7.2 Makefile规则

  • make 会在当前目录下找到一个名字叫 Makefilemakefile 的文件
  • 如果找到,它会找文件中第一个目标文件(target),并把这个文件作为最终的目标文件。
  • 如果target文件不存在,或是target文件依赖的.o文件(prerequities)的文件修改时间要比target这个文件要新,就会执行后面所定义的命令command 来生成target文件
  • 如果target依赖的.o文件(prerequities)也存在,make会在当前文件中找到target为.o文件的依赖性,如果找到,再根据哪个规则生成.o文件

7.3 伪目标

”伪目标“不是一个文件,只是一个标签。我们要显示地指明这个”目标“才能让其生效。

”伪目标“的取名不能和文件名重名,否则就不会执行这个命令

为了避免和文件重名的这种情况,可以使用一个特殊的标记 .PHONY来显示地指明一个目标是”伪目标“,向make说明,不管是否有这个同名的文件,这个目标就是”伪目标“。

.PHONY: clean

只要有这个声明,不管是否有"clean"文件,要运行"clean"这个目标,只有"make clean"这个命令。

8. Makefile变量的定义,使用

变量在声明时需要赋初值。使用时,需要在变量名前加 $ 符号,并用小括号 () 把变量括起来。

8.1 变量的定义

cpp := src/main.cpp
obj := objs/main.o

8.2 变量的引用

  • 可以用 (){}
cpp := ./main.cpp
obj := objs/main.o

${obj} :${cpp}
		@g++ -c ${cpp} -o ${obj}
complie: ${obj}

debug: 
		@echo ${cpp}
		@echo ${obj}
		
.PHONY: complie debug

8.3 预定义变量

  • $@ : 目标(target)的完整名称。
  • $< :第一个依赖文件(prerequities)的名称
  • $^ : 所有依赖文件(prerequities),以空格分开,不包含重复的依赖文件
cpp := ./main.cpp
obj := objs/main.o

${obj}:$(cpp)
        @g++ -c $< -o $@
# g++ -c main.cpp -o objs/main.o

complie: ${obj}

clean:
        @rm -r objs

debug:
        @echo $(cpp)
        @echo $(obj)


.PHONY: clean complie debug

9. Makefile 几种等号,续行符

9.1 =(相当于赋给地址或指针)

  • 简单的赋值运算
  • 用于将右边的值分配给左边的变量
  • 如果在后面的语句中重新定义了该变量,则使用新的值
HOST_ARCH = aarch64
TARGET = ${HOST_ARCH}


HOST_ARCH = amd64

debug:
        @echo ${TARGET}
        @echo ${HOST_ARCH}

.PHONY: debug
# TARGET = amd64

9.2 :=(相当于直接赋值)

  • 立即赋值运算符
  • 用于在定义变量时立即求值
  • 该值在定义后不再更改
  • 即使在后面的语句中重新定义了该变量
HOST_ARCH := aarch64
TARGET := ${HOST_ARCH}


HOST_ARCH := amd64

debug:
        @echo ${TARGET}
        @echo ${HOST_ARCH}

.PHONY: debug
# TARGET = aarch64

9.3 ?=

  • 默认赋值运算符
  • 如果变量已经定义,则不进行任何操作
  • 如果变量没有定义,则求值并分配
#HOST = aaarch64
HOST ?= amd64

debug:
        echo ${HOST}

.PHONY: debug

9.4 累加 +=

include_paths := src

CXXFLAGS := -m64 -fPIC -g -0o -std=c++11 -w -fopenmp

CXXFLAGS += ${include_paths}
debug:
        @echo ${CXXFLAGS}


.PHONY: debug

9.5 续行符 \

LDLIBS := cudart opencv_core \
          gomp nvinfer protobuf cudnn pthread \
          cublas nvcaffe_parser nvinfer_plugin 

9.6 通配符 * 与 %

  • ***** : shell命令中的通配符,表示匹配任意字符串,可以用在目录名或文件名
  • % : make语法中的通配符,表示匹配任意字符串,并将匹配的字符串作为变量使用

10. Makefile的常用函数

函数调用,很像变量的使用,用 “$” 来标识,语法:

  • $(fn arguments)  或 ${fn arguments}
    # fn 函数名
    # arguments 函数参数,参数间以逗号 "," 分隔,函数名与参数之间用”空格“分隔
    

10.1 shell

$(shell <command> <arguments>)
  • 名称:shell 命令函数 ——shell
  • 功能:调用 shell 命令 command
  • 返回:函数返回 shell 命令 command 的执行结果
# shell 指令 ,在c++program目录下找到所有的.cpp文件
cpp_c++program := ${shell find ../c++program/ -name "*.cp

debug:
        @echo ${cpp_c++program}

.PHONY: debug

# shell指令 ,获取计算机架构
HOST_ARCH := $(shell uname -m)

10.2 subst , patsubst

10.2.1 subst
$(subst <from>,<to>,<text>)
  • 名称: 字符串替换函数
  • 功能:把字符串 中的字符串替换为
  • 返回:函数返回被替换过后的字符串
cpp_src := ${shell find ../c++program/ -name "*.cpp" }
cpp_obj := ${subst ../c++program/,../c++program/objs/,${cpp_src}}
cpp_obj := ${subst .cpp,.o,${cpp_obj}}
10.2.2 patsubst
$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换
  • 功能:通配符**%**,表示任意长度的字符串,从text中取出pattren,替换为 replacement
src := ${shell find ../c++program/ -name "*.cpp"}
obj := ${patsubst ../c++program/%.cpp,../c++program/objs/%.o,${src}}

10.3 foreach

$(foreach <var>,<list>,<text>)
  • 名称:循环函数
  • 功能:把字符串中的元素(路径)逐一取出来赋值给var,执行 包含的表达式
  • 返回: 所返回的每个字符串所组成的整个字符串(以空格分隔)
include_path := /usr/include \
                /usr/incude/opencv2/core

include_path := $(foreach item,${include_path},-I${item})

debug:
        @echo ${include_path}


.PHONY: debug

​ 在Makefile中,‘-I’ 后面跟一个路径,用于告诉编译器在那些目录中查找头文件。在这个代码中,** i t e m ∗ ∗ 代表在 f o r e a c h 循环中的每个路径, ∗ ∗ − I {item}** 代表在foreach循环中的每个路径,**-I item代表在foreach循环中的每个路径,I{item}**实际为每个路径加上-I的前缀,这样编译器在编译时就会将这些路径作为头文件的搜索路径。

m10.3.1 foreach 同等效果:
include_path := /usr/include \
                /usr/incude/opencv2/core

I_flag := $(include_path:%=-I%)
# % 是用通配符符号,用于匹配include_path中的每个元素
# =-I% 是替换的格式,表示将每个匹配到的元素前加上 '-I' 前缀

10.4 dir

$(dir <names...>)
  • 名称:取目录的函数
  • 功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠”/“之前的部分。如果没有反斜杠,就返回 “./
  • 返回:返回文件名序列的目录部分
cpp_src := $(shell find . -name "*.cpp")
cpp_obj := $(patsubst ./%.cpp,./objs/%.o,${cpp_src})

./objs/%.o : ./%.cpp
        @mkdir -p $(dir $@)
        @g++ -c $^ -o $@


complie: ${cpp_obj}

debug:
        @echo ${cpp_src}
        @echo ${cpp_obj}

.PHONY: debug complie

​ 在Makefile规则中,%是Make语法中的通配符,而*是Shell中的通配符。在Makefile规则中,必须使用%来表示通配符,表示对目标文件和依赖文件的模式匹配。

10.5 notdir

$(notdir <names...>)
  • 名称:提取文件名的函数
  • 功能:从一个文件路径中提取文件名(去除了路径部分)
  • 返回:返回文件名
ibs := ${notdir ${shell find /usr/lib -name "lib*"}}
#libs := ${notdir ${libs}}

debug:
	@echo ${libs}

.PHONY: debug

10.6 filter

$(filter pattern..., text)
  • 功能:filter函数会遍历text中的每个元素,然后根据pattern进行模式匹配。如果元素与任意一个pattern匹配,则该元素会被包含在结果列表中,否则会被忽略。(从一个列表中筛选出符合指定模式的元素)
  • 返回:返回一个新的列表
  • pattern : 是一个模式,可以包含通配符
  • text : 是一个以空格或Tab字符分隔的列表
libs := ${notdir ${shell find /usr/lib -name "lib*"}}

a_lib := ${filter %.a,${libs}}
so_lib := ${filter %.so,${libs}}

debug:
	@echo ${so_lib}

.PHONY: debug

10.7 basename

${basename <names...>}
  • 功能:从一个文件路径中提取文件名的基本部分(删除路径名和扩展名部分),
  • 返回:返回文件名的基本部分
  • name : 一个或多个文件路径(可以是变量、通配符表达式等)
# 删掉了 后缀名
libs := ${notdir ${shell find /usr/lib -name "lib*"}}

a_lib := ${basename ${filter %.a,${libs}}}
so_lib := ${basename ${filter %.so,${libs}}}

debug:
	@echo ${a_lib}

.PHONY: debug
# 删除lib前缀,用subst函数,用 空白 替换掉lib
libs := ${notdir ${shell find /usr/lib -name "lib*"}}

a_lib := ${subst lib,,${basename ${filter %.a,${libs}}}}
so_lib := ${subst lib,,${basename ${filter %.so,${libs}}}}

debug:
	@echo ${a_lib}

.PHONY: debug

10.8 filter-out

  • 剔除不想要得字符串
obj := objs/add.o objs/minus.o objs/main.o
cpp_objs := ${filter-out objs/main.o,${obj}}

11.makefile编译过程

11.1 编译带头文件的程序

test0803/
├── include
│ ├── add.hpp
│ └── Minus.hpp
├── makefile
├── obj
│ ├── add.o
│ ├── main.o
│ └── Miuns.o
├── src
│ ├── add.cpp
│ ├── main.cpp
│ └── Miuns.cpp
└── workspace
└── exec

// add.hpp
#ifndef __ADD__
#define __ADD__

int add(int a,int b);

#endif
// Minus.hpp
#ifndef __MINUS__
#define __MINUS__


int Minus(int a,int b);

#endif
// add.cpp
#include "add.hpp"

int add(int a,int b)
{
        return a+b;
}
// Minus.cpp
#include "Minus.hpp"

int Minus(int a,int b)
{
        return a-b;
}
//main.cpp
#include "add.hpp"
#include "Minus.hpp"
#include <iostream>
using namespace std;


int main(void)
{
        int a=10;
        int b=5;
        int c = add(a,b);
        cout<<"a+b="<<c<<endl;
        c = Minus(a,b);
        cout<<"a-b="<<c<<endl;

        return 0;
}
# makefile
cpp_srcs := ${shell find src -name "*.cpp"}
cpp_objs := ${patsubst src/%.cpp,obj/%.o,${cpp_srcs}}

include_paths := /home/book/Desktop/test0803/include

I_flags := ${include_paths:%=-I%}
# I_flag := ${foreach var,${include_paths},-I${var}}

compile_options := -m64 -O3 -w ${I_flags}

obj/%.o : src/%.cpp
        @mkdir -p $(dir $@)
        @g++ -c $^ -o $@ ${compile_options}

#链接
workspace/exec : ${cpp_objs}
        @mkdir -p ${dir $@}
        @g++ $^ -o $@


run : workspace/exec
        @./$<


clean:
        @rm -rf workspace/exec obj/%.o


debug:
        @echo ${cpp_srcs}
        @echo ${cpp_objs}
        @echo ${I_flags}
        @echo ${compile_options}


.PHONY: debug run clean

11.2 c/c++编译选项

11.2.1 编译选项

-m64 : 指定为64位应用程序

-std= :指定编译标准,eg: -std=c++11 , -std=c++14

-g :包含调试信息

-w :不显示警告信息

-o :优化等级,通常使用:-O3

-I : 加在头文件路径前 (大写的i),-Iincldue(include为头文件目录),指定头文件的搜索路径

fpic :(position-Independent Code),没有绝对地址,全部使用相对地址,代码可以被加载到内存的任意位置,且可以正确的执行。生成与位置无关的代码。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

11.2.2 链接选项

-l :加在库名前面

-L : 加在库路径前面

-Wl,<选项> : 将逗号分隔的<选项>传递给链接器

-rpath : 运行的时候,去找的目录。运行的时候,要找 .so文件,会从这个选项里指定的地方寻找

11.3 预处理(main.cpp --> main.i)

// main.cpp
#include <iostream>
using namespace std;


int main(void)
{
        cout<<"Hello world\n";

        return 0;

}
cpp_srcs := ${shell find . -name "*.cpp"}
cpp_objs := ${patsubst %.cpp,%.i,${cpp_srcs}}

%.i : %.cpp
        @g++ -E $^ -o $@


compile : ${cpp_objs}


debug:
        @echo ${cpp_objs}

.PHONY: debug compile

11.4 编译(main.i --> main.s)

cpp_srcs := ${shell find . -name "*.cpp"}
# find 命令在当前目录及其子目录查找 '.cpp'文件,但它返回的是相对路径,包含了当前目录的信息,返回的是 ./main.cpp
cpp_objs := ${patsubst ./%.cpp,obj/%.s,${cpp_srcs}}
cpp := ${shell find . -name "*.cpp" -printf "%P\n"}
# find命令的 -printf "%p\n" 选项来获取文件的相对路径,返回的是不包含当前目录信息的'.cpp'文件路径, 即 main.cpp
obj/%.s : %.cpp
        @mkdir -p ${dir $@}
        @g++ -S $^ -o $@


compile: ${cpp_objs}


debug:
        @echo ${cpp_objs}
        @echo ${cpp_srcs}
        @echo ${cpp}
.PHONY: compile

11.5 汇编(main.s–>main.o)

cpp_srcs := ${shell find . -name '*.cpp'}
cpp_objs := ${patsubst ./%.cpp,obj/%.o,${cpp_srcs}}


obj/%.o : %.cpp
        @mkdir -p ${dir $@}
        @g++ -c $^ -o $@

compile : ${cpp_objs}


debug :
        @echo ${cpp_objs}


.PHONY: compile debug

11.6 链接(生成可执行程序)

cpp_srcs := ${shell find . -name '*.cpp'}
cpp_objs := ${patsubst ./%.cpp,obj/%.o,${cpp_srcs}}

obj/%.o : %.cpp
        @mkdir -p ${dir $@}
        @g++ -c $^ -o $@


workspace/exec : ${cpp_objs}
        @mkdir -p ${dir $@}
        @g++ $^ -o $@

run : workspace/exec
        @./$<

debug :
        @echo ${cpp_objs}

clean:
        @rm -rf ./workspace ./obj

.PHONY: debug run clean

12. 静态库编译

StaticLibrary/
├── include
│ ├── add.hpp
│ └── Minus.hpp
├── lib
│ └── libxxx.a
├── makefile
├── obj
│ ├── add.o
│ ├── main.o
│ └── Miuns.o
├── src
│ ├── add.cpp
│ ├── main.cpp
│ └── Miuns.cpp
└── workspace

12.1 编译过程

12.1.1 源文件[.c/.cpp] --> Object文件[.o]
g++ -c [.c/.cpp] [.c/.cpp] ... -o [.o] [.o] ... -I[.h/.hpp] -g
12.1.2 Object文件[.o] --> 静态库文件[libname.a]
ar -r [libname.a [.o] [.o] ...
12.1.3 main文件[.c/.cpp] --> Object文件[.o]
g++ -c main.cpp -o mian.o -I[.h/.hpp]
12.1.4 链接main的Object文件与静态库文件[libname.a]
g++ main.o -o [可执行文件] -l[name] -L[静态库路径]
# name为静态库名字

12.2 makefile

lib_srcs := ${filter-out src/main.cpp , ${shell find src -name "*.cpp"}}
lib_objs := ${patsubst src/%.cpp,obj/%.o,${lib_srcs}}

include_path := /home/book/Desktop/StaticLibrary/include

library_paths := /home/book/Desktop/StaticLibrary/lib

linking_libs := xxx

I_flag := ${foreach var,${include_path},-I${var}}

l_options := ${linking_libs:%=-l%}
L_options := ${library_paths:%=-L%}


compile_flags := -g -O3 -m64 ${I_flag} -std=c++11
linking_flags := ${l_options} ${L_options}

#-------编译静态库---------

obj/%.o : src/%.cpp
        @mkdir -p ${dir $@}
        @g++ -c $^ -o $@ ${compile_flags}


lib/libxxx.a : ${lib_objs}
        @mkdir -p ${dir $@}
        @ar -r $@ ${lib_objs}
        
static_lib : lib/libxxx.a

#---------链接静态库------
obj/main.o : src/main.cpp
        @g++ -c $< -o $@ ${compile_flags}


workspace/exec : obj/main.o
        @mkdir -p ${dir $@}
        @g++ $< -o $@ ${linking_flags}

run: workspace/exec
        @./$^
debug :
        @echo ${lib_objs}
        @echo ${lib_srcs}

clean:
        rm -rf obj lib


.PHONY : debug static_lib run

13. 动态库编译

13.1 编译过程

13.1.1 源文件[.c/.cpp] --> Object文件[.o]
g++ -c [.c/.cpp] [.c/.cpp]... -o [.o] [.o]... -I[.h/.hpp] -g -fpic
13.1.2 Object文件[.o] --> 动态库文件[lib库名.so]
g++ -shared [.o] [.o]... -o [lib库名.so]
13.1.3 main文件[.c/.cpp] --> Object文件[.o]
g++ -c [main.c/.cpp] -o main.o -I[.h/.hpp] -g
13.1.4 链接动态库文件
g++ main.o -o [可执行程序] -l[库名] -L[库路径] -Wl,-rpath=[库路径]

13.2 makefile

13.2.1 更标准的makefile
cpp_srcs := ${shell find src -name '*.cpp'}
cpp_objs := ${patsubst src/%.cpp,obj/%.o,${cpp_srcs}}

so_objs := ${filter-out obj/main.o,${cpp_objs}}

include_paths :=/home/book/Desktop/SharedLibrary/include

library_paths :=/home/book/Desktop/SharedLibrary/lib

linking_libs := xxx

I_options := ${include_paths:%=-I%}
l_options := ${linking_libs:%=-l%}
L_options := ${library_paths:%=-L%}
r_options := ${library_paths:%=-Wl,-rpath=%}


compile_options := -g -m64 -O3 -w -fpic ${I_options}
linking_options := ${l_options} ${L_options} ${r_options}


#--------编译cpp文件-----

obj/%.o : src/%.cpp
        @mkdir -p ${dir $@}
        @g++ -c $^ -o $@ ${compile_options}


compile : ${cpp_objs}


#----------编译动态库-------

lib/libxxx.so : ${so_objs} 
        @mkdir -p ${dir $@}
        @g++ -shared $^ -o $@

dynamic : lib/libxxx.so


#-------链接动态库------

workspace/exec : obj/main.o compile dynamic
        @mkdir -p ${dir $@}
        @g++ $< -o $@ ${linking_options}


run : workspace/exec
        @./$<


debug :
        @echo ${so_objs}


clean :
        @rm -rf lib obj  workspace

.PHONY: debug compile dynamic clean run

13.2.2 不太标准的makefile
lib_srcs :=${filter-out src/main.cpp,${shell find src -name '*.cpp'}}

lib_objs := ${patsubst src/%.cpp,obj/%.o,${lib_srcs}}

include_paths :=/home/book/Desktop/SharedLibrary/include

library_paths := /home/book/Desktop/SharedLibrary/lib

linking_libs := xxx

I_options :=${include_paths:%=-I%}

l_options :=${linking_libs:%=-l%}
L_options :=${library_paths:%=-L%}
r_options :=${library_paths:%=-Wl,-rpath=%}

compile_flags := -m64 -g -O3 ${I_options} -fpic
linking_flags := ${l_options} ${L_options} ${r_options}

#----------编译动态库----------

obj/%.o : src/%.cpp
        @mkdir -p ${dir $@}
        @g++ -c $^ -o $@ ${compile_flags}



lib/libxxx.so : ${lib_objs}
        @mkdir -p ${dir $@}
        @g++ -shared $^ -o $@


shared_lib :lib/libxxx.so

#----------链接动态库-------
obj/main.o : src/main.cpp
        @g++ -c $< -o $@ ${compile_flags}


workspace/exec : obj/main.o
        @mkdir -p ${dir $@}
        @g++ $< -o $@ ${linking_flags}

run: workspace/exec
# @LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${library_paths}
        @./$<


debug:
        @echo ${lib_objs}


clean:
        @rm -rf obj workspace lib


.PHONY: clean debug run shared_lib
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值