IOT设备AI搭建4:MakeFile基础语法

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中去

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值