美文网首页神经网络
IOT设备AI搭建4:MakeFile基础语法

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

作者: 古风子 | 来源:发表于2020-04-16 21:47 被阅读0次

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

    相关文章

      网友评论

        本文标题:IOT设备AI搭建4:MakeFile基础语法

        本文链接:https://www.haomeiwen.com/subject/mvdjvhtx.html