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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容