2019年7月19日星期五(交叉编译工具)
一、工程管理文件makefile。
1. 什么是makefile?
makefile称之为工程管理文件,用于管理整个工程所有.c文件编译规则。
2. makefile是一个工程中是一定要写的吗?
如果在项目源码中,文件不多的时候,一般makefile不用写,因为编译命令比较简单。
如果在项目源码,源文件(.c) 头文件(.h)这些文件比较多,一般会携带一个makefile。
写makefile目的: 为了提高编译效率。
二. 项目工程应该由哪些文件组成?
1. 简单版
源程序文件 main.c -> 包含main函数在内的.c文件。
功能程序文件 fun1.c -> 第1个功能文件 -> 功能性最好以功能来命名,例如: play_music.c
功能程序文件 fun2.c -> 第2个功能文件
...
功能程序文件 funn.c -> 第n个功能文件
头文件: head.h -> 结构体声明,函数声明,宏定义,系统头文件..
库文件:
工程管理文件: makefile -> 里面有一套可以编译整个项目的规则。
2. 复杂版
src/ -> 所有的.c文件
include/ -> 所有的.h文件
lib/ -> 所有的库文件
bin/ -> 编译之后的可执行文件
makefile -> 里面有一套可以编译整个项目的规则。
如果没有makefile,上述例子中,用户应该每次都要输入: "gcc main.c fun1.c fun2.c -o main -I ."
学习书写makefile之后,就可以让makefile帮我们做这件事情了。
三. makefile书写规则?
1. makefile文件的核心:"依赖" 与 "目标"?
"依赖" -> 在编译文件时,才需要写依赖,如果不是编译,则不需要写依赖。一般依赖指的就是.c文件。
"目标" -> 你最终想得到的文件,一般指的是可执行程序
在上述例子中:
main.c fun1.c fun2.c -> 依赖
main -> 目标
2. makefile的书写规则?
有依赖情况下:
========================================================
1)确定好依赖与目标叫什么名字。
2)按照以下格式来写makefile:
目标:依赖(如果有多个依赖,则每一个依赖之间使用空格分开)
<Tab键>编译规则
注意:
1)<Tab键>不等于四个空格,编译规则之所以能识别出来,就是因为这个Tab键
2)在编译规则中如何调用依赖与目标
$^ -> 代表所有的依赖文件 -> 等价于 main.c fun1.c fun2.c
$@ -> 代表目标文件 -> 等价于 main
无依赖情况下:
1)确定目标叫什么名字。
2)按照以下规则来写makefile:
目标:
<Tab键>执行命令
3. 举实例。
1)makefile的helloworld版本1。
target: //目标一定要写,但是依赖不一定。
echo helloworld //规则,执行make命令,就会执行这套规则了。
执行make,结果:
echo helloworld -> 默认将规则命令输出到屏幕中,如果不想看到,则只需要在规则前面加@
helloworld
2)makefile的helloworld版本2。
target: //目标一定要写,但是依赖不一定。
@echo helloworld //规则,执行make命令,就会执行这套规则了。
执行make,结果:
helloworld
练习: 修改code1的代码,写一个makefile,使得执行make时候,可以生成main这个可执行程序。
main:main.c fun1.c fun2.c
gcc $^ -o $@
执行make,结果:
gcc main.c fun1.c fun2.c -o main -> 在当前目录下生成一个main文件。
再次执行make,结果:
make: `main' is up to date. -> 因为makefile检测到所有的依赖文件都没有更新,所以不会重新编译。
-> 只要其中一个依赖文件的修改日期与之前的不一样,都会重新编译。
四、makefile多个目标情况。
例子:
main: -> 当执行make,默认只会执行第一个目标。
xxxx;
main1: -> 当需要执行某个特定的目标时,在make时候,需要指定该目标的名字: make main1
yyyy;
main2:
zzzz;
修改makefile为:
main:main.c fun1.c fun2.c
gcc $^ -o $@
clean:
rm main
五. makefile的变量种类。
1. 自定义变量 -> makefile不需要声明类型,只需要定义名字就可以。变量默认是字符串类型的。
规则:
1)变量名与C语言规则一致。
2)给变量赋值时,等号两边都可以有空格,也可以没有。但是shell编程中变量赋值时,等边两边不能有空格。
3)引用makefile中变量时,需要在变量前面添加$。 $A $(A)
4)因为变量都是默认是字符串类型,所以""可以省略。
例子:
A = Hello 等价于 A = "hello"
B=world
C=$A $(B)
练习2: 修改makefile,将所有的依赖放置到一个变量。
C_SOURCE=main.c fun1.c fun2.c
main:$(C_SOURCE)
gcc $^ -o $@
clean:
rm main
2. 系统预设定变量
有些变量是系统中已经写好的,并且已经赋了初值的,这些变量的值就可以直接使用。
CC: -> 编译器名字,默认系统赋值是cc CC=cc cc等价于gcc
RM: -> 删除命令,默认系统赋值是rm -f RM=rm -f
练习3:把系统预设定变量加入到makefile中。尝试交叉编译与本地编译。
CC=arm-linux-gcc
C_SOURCE=main.c fun1.c fun2.c
main:$(C_SOURCE)
$(CC) $^ -o $@
clean:
rm main
3. 自动化变量 -> 变量的值不是固定的,而是会变化的。
$^ -> 代表当前的所有依赖
$@ -> 代表目标
例子:
main:
$@ -> 代表main
clean:
$@ -> 代表clean
例子:
CC=arm-linux-gcc
C_SOURCE=main.c fun1.c fun2.c
TARGET=main
$(TARGET):$(C_SOURCE)
$(CC) $^ -o $@
clean:
rm $(TARGET)
六. makefile伪指令。
假设makefile有一套规则:
------------------------------
clean:
$(RM) main
------------------------------
当我们执行make clean时,就会执行这套规则,如果当前目录下有一个文件名字叫clean
那么再执行make clean就会提示:make: `clean' is up to date.
解决方案:将clean这个目标添加为伪指令。
添加为伪指令的含义是什么?
就是告诉makefile,这个目标不是一个生成的文件。
在makefile中添加代码:
.PHONY:clean
-----------------------------------------
CC=arm-linux-gcc
C_SOURCE=main.c fun1.c fun2.c
TARGET=main
$(TARGET):$(C_SOURCE)
$(CC) $^ -o $@
.PHONY:clean
clean:
$(RM) $(TARGET)
----------------------------------------
七. makefile函数 -> wildcard
1. makefile中调用函数方式: $(函数名参数1,参数2,参数3.....)
C语言中调用函数方式: 函数名(参数1,参数2,参数3...)
2. wildcard函数作用:在指定的路径下找到相匹配的文件
例子: SRC = $(wildcard *.c) -> 在当前目录下寻找所有的.c结尾的文件,并把结果保存在SRC变量,每个结果之间使用空格分开。
SRC = $(wildcard /*.c) -> 在根目录下寻找所有的.c结尾的文件。
注意:
* -> 代表任意长度的任意字符。
最终得到简单版通用的makefile为:
CC=arm-linux-gcc
C_SOURCE=$(wildcard *.c)
TARGET=main
INCLUDE_PATH=-I .
$(TARGET):$(C_SOURCE)
$(CC) $^ -o $@ $(INCLUDE_PATH)
.PHONY:clean
clean:
$(RM) $(TARGET)
练习4: 将简单版通用的makefile修改为复杂版的!
CC=arm-linux-gcc
C_SOUCRE=$(wildcard ./src/*.c)
TARGET=./bin/main
INCLUDE_PATH=-I ./include
$(TARGET):$(C_SOUCRE)
$(CC) $^ -o $@ $(INCLUDE_PATH)
.PHONY:clean
clean:
$(RM) $(TARGET)
八.嵌入式linux的库文件。
1. 什么是库文件?
库文件在linux下以二进制形式存在,往往我们编译程序时,需要链接这些库。
2. 库文件的格式?
1)静态库 ---> libxxx.a
2)动态库/共享库 ---> libxxx.so
例子: libxxx.so.9.1.0
lib: 库的前缀
xxx: 库的名字
.a/.so: 库的后缀
.9: 库的版本号
.1.0:库的修正号
3. 静态库与动态库的区别?
静态库特点:libxxxx.a -> 去图书馆(libxxxx.a)中把图书(函数接口)拿走
1)程序在编译时,如果是链接静态库,那么就等于把库的内容拿走,就会导致可执行程序的大小非常大。
2)由于是静态库编译,所以在编译程序之后,可执行文件不需要静态库的存在都可以运行。
动态库特点:libxxx.so -> 去图书馆(libxxx.so)看看书(函数接口)而已,看完了,就把书放回图书馆,并没有拿走。
1)程序在编译时,如果是链接动态库,仅仅链接而已,没有拿走库的东西,相对于静态库来讲,会比较小。
2)由于是动态库编译,在执行可执行文件之后,动态库必须存在,可执行文件才能正常运行。
4. 如何制作库文件?
只有包含功能性函数.c文件才能制作成库文件,含有main函数在内的.c文件不能制作为库文件。
1)静态库的制作。 -> 没有架构可言。
1.将工程所有不包含main函数在内的.c文件找到。
2.将这些.c文件全部编译为.o文件。
gcc fun1.c -o fun1.o -c
gcc fun2.c -o fun2.o -c
3.将这些.o文件全部塞进一个.a文件
ar rcs libmy.a fun1.o fun2.o
4.编译程序
gcc main.c -o main -L . -lmy
5.执行
./main 就可以出来结果!
注意:
1)-L . -> 只是告诉系统去当前目录下寻找库文件,但是没有告诉链接哪个。
2)-lmy -> -l(小写字母L)没有空格的,要紧跟库的名字(my),注意不是库文件的名字(libmy.a)
3)制作库与编程程序所使用到的工具链必须一致。
练习5:熟悉交叉编译静态库的制作。
arm-linux-gcc fun1.c -o fun1.o -c
arm-linux-gcc fun2.c -o fun2.o -c
ar rcs libmy.a fun1.o fun2.o
arm-linux-gcc main.c -o main -L . -lmy
结论: 库的架构必须与编译程序时的工具链架构一致,否则就会出错:
库:x86 编译: arm-linux-gcc
/usr/local/arm/bin/../lib/gcc/arm-none-linux-gnueabi/4.5.1/../../../../arm-none-linux-gnueabi/bin/ld: skipping incompatible ./libmy.a when searching for -lmy
/usr/local/arm/bin/../lib/gcc/arm-none-linux-gnueabi/4.5.1/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lmy
库: ARM 编译: gcc
/usr/bin/ld: skipping incompatible ./libmy.a when searching for -lmy
/usr/bin/ld: cannot find -lmy
collect2: ld returned 1 exit status
练习6:把库添加到复杂版的lib目录,修改makefile。
CC=arm-linux-gcc
C_SOUCRE=$(wildcard ./src/*.c)
TARGET=./bin/main
INCLUDE_PATH=-I ./include
LIBRARY_PATH=-L ./lib -lmy
$(TARGET):$(C_SOUCRE)
$(CC) $^ -o $@ $(INCLUDE_PATH) $(LIBRARY_PATH)
.PHONY:clean
clean:
$(RM) $(TARGET)
2)动态库的制作 -> 有架构可言
1. 将工程所有不包含main函数在内的.c文件找到。
2. 将这些.c文件全部编译为.o文件。
gcc fun1.c -o fun1.o -c -fPIC
gcc fun2.c -o fun2.o -c -fPIC
3. 将这些.o文件编译为libxxx.so文件
gcc -shared -fPIC -o libmy2.so fun1.o fun2.o
4. 编译程序
gcc main.c -o main -L . -lmy2
5. 执行
./main
终端提示错误:
./main: error while loading shared libraries: libmy2.so: cannot open shared object file: No such file or directory
//执行main程序时需要加载共享库:libmy2.so时出现了错误: 因为文件不存在所以,不能打开这个文件。
解决方案:
1. 把制作的好的库文件拷贝到/lib中 -> 不推荐
2. 把该库的路径添加到环境变量 LD_LIBRARY_PATH
假设库在/home/gec。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/gec -> 系统就会家目录下找这个"libmy2.so"这个东东!
3. 重新执行代码
./main
练习7:熟悉交叉编译动态库的制作。
练习8:把库添加到复杂版的lib目录,修改makefile。
转载于:https://www.cnblogs.com/zjlbk/p/11215281.html
2019年7月19日星期五(交叉编译工具)相关推荐
- 2019年10月19日星期六
2019年10月19日星期六 师院上课 颗粒归仓 纪老师教会我们学习了东西要及时总结,颗粒归仓的意思就是收获的粮食要放到仓库中(储存),知识也一样,学会以后需要把知识做收集总结起来. 今天我们进行了一 ...
- 2016年8月19日 星期五 --出埃及记 Exodus 16:20
2016年8月19日 星期五 --出埃及记 Exodus 16:20 However, some of them paid no attention to Moses; they kept part ...
- 【图片新闻】2019年6月19日伊朗击落一架美军MQ-4 Triton无人侦察机
伊朗消息人士和五角大楼称,2019年6月19日,伊朗击落了一架MQ-4 Triton侦察机.伊朗声称这架无人机正在伊朗领空飞行,但美国政府否认这一说法. MQ-4 Triton是一种无人驾驶.非致命的 ...
- 2019年6月19日 星期三 今日计划
2019年6月19日 星期三 今日计划 学习XMLHttpRequest对象
- 【蜕变之路】第29天 CAST和CONVERT的区别(2019年3月19日)
Hello,大家好!我是程序员阿飞!今天从北京来了位项目经理,很热情,中午的时候,就带我们出去吃了一顿,很感谢领导.我们主要学习一下SQL中 CAST和CONVERT的区别. 1.作用 两者都是用来获 ...
- 2019年6月14日 星期五(吴翰清web安全)
到底是买苹果笔记本还是thinkpad到今天为止还没有一个合适的定论,暂时先这样吧,暂时先不买吧 安全工程师的核心竞争力不在于他能拥有多少个 0day,掌握多少种安全技术,而是在于他对安全理解的深度, ...
- 2019年6月19日Jerry Wang的SAP SAP Cloud Connector练习
https://webidetesting9070069-i042416trial.dispatcher.hanatrial.ondemand.com/ag3-backend/sap/opu/odat ...
- 2019年8月23日 星期五(韩天峰的swoole)
Swoole:面向生产环境的 PHP 异步网络通信引擎 使 PHP 开发人员可以编写高性能的异步并发 TCP.UDP.Unix Socket.HTTP,WebSocket 服务. Swoole 可以广 ...
- 2019年9月19日好货十元内精选包邮
复制这条信息,$H14ZYNhfI2g$,到[手机淘宝]即可查看 复制这条信息,$LmqTYNhlCUs$,到[手机淘宝]即可查看 复制这条信息,$yHt0YNhIbdT$,到[手机淘宝]即可查看 复 ...
- Win10 收件箱添加QQ邮箱(2019年5月19日)
Emmm弄的时候没截图,就语言描述吧,非常简单. 登录到网页端QQ邮箱.点我登录 登录之后,界面上端的Logo右边有个"设置"(字有点小).点它 邮箱设置下面有一堆标签,点击&qu ...
最新文章
- HttpSession
- mysql执行文件脚本文件_MySQL执行外部sql脚本文件的命令
- java获取文件地址吗_java获取文件所在服务器位置路径
- SpringMVC中JSON处理
- 内部办公网与IDC机房的GRE隧道配置实践
- 使用PHP来简单的创建一个RPC服务
- H3C防火墙——回环流量问题(内网终端通过外网IP访问内部服务器)
- 深度强化学习之近端策略优化(Proximal Policy Optimization)
- 防范勒索软件的七大举措
- C++/MFC 面试题(六、逻辑题)
- 常见前端九十道面试题及答案-韩烨
- http请求报错context deadline exceeded (Client.Timeout exceeded while awaiting headers)
- python:实现9×9二维数组数独算法(附完整源码)
- sqlserver2012 查询远程数据库
- 微信公众平台测试号登录入口地址
- 修复iPhone X 开机卡白苹果导致无法开机的问题
- 新建Maven工程乱七八糟全都失效了
- linux tar xzmf,有人吗??IT大神求助
- 多媒体-百科知识(转百度百科)
- 【问题解决】外部环境分析