1. 值的赋予和覆盖
make会将整个Makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
例如你在Makefile文件总为TARGET赋值了
TARGET := $(HOST_OS)
TARGET_ARCH := $(HOST_ARCH)
当运行make时, TARGET=rpi会将Makefile的值覆盖,最总TARGET的值为rpi
make -f tensorflow/lite/tools/make/Makefile TARGET=rpi TARGET_ARCH=armv7l
2. MakeFile中打印变量的值
$(error $(TARGET)) 或者 $(warning $(TARGET));TARGET为Makefile中的变量
3. 扩展通配符
在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...)
如下代码,将会在tensorflow/lite目录获取所有符合通配规则的.c和.cc文件
CORE_CC_ALL_SRCS := \
$(wildcard tensorflow/lite/*.cc) \
$(wildcard tensorflow/lite/*.c) \
$(wildcard tensorflow/lite/c/*.c) \
$(wildcard tensorflow/lite/core/*.cc) \
$(wildcard tensorflow/lite/core/api/*.cc) \
$(wildcard tensorflow/lite/experimental/resource/*.cc) \
$(wildcard tensorflow/lite/experimental/ruy/*.cc)
4. patsubst :替换通配符
obj=$(patsubst %.c,%.o,$(dir) )
@echo $(obj)
a.o b.o sa.o sb.o
在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
5. 编译链接
cc就是编译命令,默认是gcc,
-o 表示编译并链接 所有依赖文件
-c 表示只编译不链接
-g 表示带调试信息
6.批量编译
all: test1 test2 test3
%:%.cpp
g++ $< -o $@
clean:
rm -f test1 test2 test3
结果(如下用make命令也可以):
taoge@localhost Desktop> make clean
rm -f test1 test2 test3
taoge@localhost Desktop> make all
g++ test1.cpp -o test1
g++ test2.cpp -o test2
g++ test3.cpp -o test3
7.静态链接,编译
7.1 创建工具类头文件和c文件
jutils.h
#ifndef UTIL_FILE
int add(int,int);
#define UTIL_FILE
#endif
jutils.c
#include "jutils.h"
#include <stdio.h>
int add(int a,int b)
{
int result = 0;
printf("a+b: = %d\n",a+b);
result = a+b;
return result;
}
7.2 预处理,处理各种宏定义,条件编译等
gcc -E jutils.c -o jutils.i
通过cat查看下jutils.i的结果
# 1 "jutils.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "jutils.c"
# 1 "jutils.h" 1
int add(int,int);
# 2 "jutils.c" 2
# 1 "/usr/include/stdio.h" 1 3 4
太多了,不完全列出来了。主要是将引用的h头文件,在此文件进行展开
7.3 编译阶段,将c源码处理为汇编代码
gcc -S jutils.i -o jutils.s
或者
gcc -S jutils.i -o jutils.c
处理后的结果为:
add:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl $0, -4(%rbp)
movl -20(%rbp), %edx
movl -24(%rbp), %eax
addl %edx, %eax
movl %eax, %esi
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
movl -20(%rbp), %edx
movl -24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
7.4 汇编阶断
汇编阶断是将汇编代码处理为二进制代码。
gcc -c jutils.s -o jutils.o
处理完成后生成o文件
~/study/helloworld$ ls
jutils.c jutils.h jutils.i jutils.o jutils.s
7.5 生成静态库文件
选择合适的交叉工具,通过ar生成静态文件
ar crv libjutils.a jutils.o
得到静态库文件libjutils.a;由静态库文件生成的可执行文件,不依赖与其他文件,与动态库文件相对应
上述命令中 crv 是 ar的命令选项:
c 如果需要生成新的库文件,不要警告
r 代替库中现有的文件或者插入新的文件
v 输出详细信息
通过ar t命令,可以查看静态库文件包含的o文件列表
~/study/helloworld$ ar t libjutils.a
jutils.o
注:我们要生成的库的文件名必须形如 libxxx.a ,这样我们在链接这个库时,就可以用 -lxxx;
反过来讲,当我们告诉编译器 -lxxx时,编译器就会在指定的目录中搜索 libxxx.a 或是 libxxx.so
通过gcc -c main.c生成main.o文件
通过ar rcs main.a test.o生成静态库文件
在程序中使用静态库,生成可执行文件
gcc -o main main.c -L. -ltest
7.6 测试静态库
创建测试程序
main.c
#include "jutils.h"
#include <stdio.h>
int add(int a,int b)
{
int result = 0;
printf("a+b: = %d\n",a+b);
result = a+b;
return result;
}
编译main.c
gcc main.c -L. -ljutils -o main
运行main;这个可执行文件,你可以copy到其他目录,单独运行,不会依赖于libjutis.a
~/study/helloworld$ ./main
a+b: = 7
7.7 通过Makefile流程化处理
以上过程就是一个程序的正常变化流程,上述流程可以用一个Makefile表示
Makefile
.PHONY: build run
build: libjutils.a
libjutils.a: jutils.o
ar crv $@ jutils.o
jutils.o: jutils.c
gcc -c jutils.c -o jutils.o
run: main
main: main.c
gcc main.c -L. -ljutils -o main
Makefile文件,编写完成后,make build生成libjutils.a静态文件;make run生成可执行文件
make build
gcc -c jutils.c -o jutils.o
ar crv libjutils.a jutils.o
a - jutils.o
(base) jiadongfeng@jiadongfeng:~/study/helloworld$ ls
jutils.c jutils.h jutils.o libjutils.a main.c Makefile
可以看到,执行命令时,先运行被依赖的项
gcc -c jutils.c -o jutils.o
ar crv libjutils.a jutils.o
a - jutils.o
运行make run生成可执行main文件
make run
gcc main.c -L. -ljutils -o main
~/study/helloworld$ ls
... main ...
运行可执行文件:
~/study/helloworld$ ./main
a+b: = 7
8 动态链接编译
还是以jutils.h,jutils.c(库文件)和main.c测试代码为例
8.1 生成动态链接库
~/study/helloworld$ gcc -fpic -shared jutils.c -o libjutils.so
~/study/helloworld$ ls
jutils.c jutils.h libjutils.so main.c Makefile
8.2 调用动态库生成可执行文件
~/study/helloworld$ gcc -o main main.c -L. ./libjutils.so
~/study/helloworld$ ls
jutils.c jutils.h libjutils.so main main.c Makefile
8.3 执行
~/study/helloworld$./main
a+b: = 7
这个可执行文件是不能方法其他目录的,因为依赖so
~/study$ ./main
./main: error while loading shared libraries: ./libjutils.so: cannot open shared object file: No such file or directory
之所以报这个错,是因为我们生成可执行文件的时候,指定的滤镜是 ././libjutils.so;我们需要修改下编译方式
方法1:
通过LD_LIBRARY_PATH指定动态库搜索路径
//编译
/study/helloworld$ LD_LIBRARY_PATH=$(pwd)
~/study/helloworld$ gcc -o main main.c -L. libjutils.so
~/study/helloworld$ ./main
a+b: = 7
//copy到其他目录执行
~/study/helloworld$ cp ./main ../
~/study/helloworld$ cd ..
~/study$ ./main
a+b: = 7
方法2
在配置文件/etc/ld.so.conf中指定动态库搜索路径
(base) jiadongfeng@jiadongfeng/etc$ cat ld.so.conf
include /etc/ld.so.conf.d/*.conf
(base) jiadongfeng@jiadongfeng:/etc$ cd ld.so.conf.d
(base) jiadongfeng@jiadongfeng:/etc/ld.so.conf.d$ ls
fakeroot-x86_64-linux-gnu.conf libc.conf x86_64-linux-gnu.conf
(base) jiadongfeng@jiadongfeng:/etc/ld.so.conf.d$ cat *
/usr/lib/x86_64-linux-gnu/libfakeroot
# libc default configuration
/usr/local/lib
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
(base) jiadongfeng@jiadongfeng:/etc/ld.so.conf.d$
如上所示,可以将你的so库放到linux默认的目录/usr/local/lib中去
网友评论