004_Makefile的编译
一、向内核中添加驱动步骤
在向内核中添加驱动的时候要完成3 项工作,包括:
1、在Kconfig 中添加新代码对应项目的编译条件
2、将驱动源码添加到对应的目录中
3、在目录Makefile 中文件中增加针对新代码的编译条目
二、编译器路径的设置
1、打开家目录下的.bashrc文件,在其最下面添加如下内容:
export PATH=$PATH:/home/mint/itop/arm-2009q3/bin
使其生效
. .bashrc
2、该目录与交叉编译器的解压放置位置相对应
/home/mint/itop/arm-2009q3/bin
3、打开内核源码的顶层目录的Makefile文件
在195行的位置有如下内容
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= arm
CROSS_COMPILE ?= /home/mint/itop/arm-2009q3/bin/arm-none-linux-gnueabi-
#CROSS_COMPILE ?= /usr/local/arm/4.5.1/bin/arm-none-linux-gnueabi-
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
该交叉编译工具链的位置与上面是一一对应的。
三、使用make zImage编译内核执行过程
在这里以BUZZER的驱动为例。
1、在make zImage命令执行之后,它会首先找到源码顶层目录下的Makefile文件,运行Makefile 文件之后,它会在Makefile 文件中找到编译器的路径,然后系统根据环境变量找到“export PATH=$PATH/home/mint/itop/arm-2009q3/bin”编译器的路径。
2、在driver/char/ 目录下,暂时关注以下三个文件
itop4412_buzzer.c //led 驱动的源码
itop4412_buzzer.o //生成最终zImage 二进制的中间文件
Makefile //make执行时所需要的文件
3、打开该目录下的Makefile文件
obj-$(CONFIG_BUZZER_CTL) += itop4412_buzzer.o
如果想添加类似的字符驱动,就可以在这个目录下添加。
四、Makefile 脚本语法简介
1、强制编译进内核
obj-y += misc.o
2、条件编译
obj-$(CONFIG_BUZZER_CTL) += itop4412_buzzer.o
需要在Kconfig 中定义,在menuconfig中配置之后,编译器运行的时候找到对应的宏变量CONFIG_BUZZER_CTL之后才会编译。
3、Makefile的层层调用
打开driver/下的Makefile文件,在第33行中
obj-y += char/
“加等号”右边有文件变为了文件夹。这里表示强制编译当前目录“/drivers”的下一级目录“/char”。在执行编译命令执行到这一句的时候,就会先跳转到“/char”目录下的“Makefile”文件。
五、Makefile 的测试
目标:通过配置menuconfig 中的SKYFALL,来将内核编译进内核或者不编译进内核。
实现步骤:
(1) 在源码目录下的driver/char目录下编写itop4412_skyfall.c源文件,文件内容如下。最后在/dev下显示的设备节点的名字为skyfall_007。
#include <linux/init.h>
#include <linux/module.h>
/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>#define DRIVER_NAME "skyfall"
#define DEVICE_NAME "skyfall_007"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("SKYFALL");//long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
//驱动实际操作的实现
static long skyfall_ioctl( struct file *file, unsigned int cmd, unsigned long arg){printk("%s,%d\n",__func__,__LINE__);printk("cmd is %d,arg is %d\n",cmd,arg);return 0;
}//int (*release) (struct inode *, struct file *);
//关闭该驱动的实现
static int skyfall_release(struct inode *inode, struct file *file){printk("%s,%d\n",__func__,__LINE__);printk(KERN_EMERG "skyfall release\n");return 0;
}//int (*open) (struct inode *, struct file *);
//打开该驱动的实现
static int skyfall_open(struct inode *inode, struct file *file){printk("%s,%d\n",__func__,__LINE__);printk(KERN_EMERG "skyfall open\n");return 0;
}//定义一个字符设备操作集合
static struct file_operations skyfall_ops = {.owner = THIS_MODULE,.open = skyfall_open,.release = skyfall_release,.unlocked_ioctl = skyfall_ioctl,
};//定义一个杂项设备结构体
static struct miscdevice skyfall_dev = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,//字符设备操作集合,需要提前定义一个,然后取地址.fops = &skyfall_ops,
};static int skyfall_probe(struct platform_device *pdv){printk(KERN_EMERG "initialized\n");printk("%s,%d\n",__func__,__LINE__);//注册杂项设备,需要一个传一个杂项设备的结构体,所以需要提前定义一个,然后取地址misc_register(&skyfall_dev);return 0;
}static int skyfall_remove(struct platform_device *pdv){printk(KERN_EMERG "\tremove\n");//注销杂项设备misc_deregister(&skyfall_dev);return 0;
}static void skyfall_shutdown(struct platform_device *pdv){;
}static int skyfall_suspend(struct platform_device *pdv,pm_message_t pmt){return 0;
}static int skyfall_resume(struct platform_device *pdv){return 0;
}struct platform_driver skyfall_driver = {.probe = skyfall_probe,.remove = skyfall_remove,.shutdown = skyfall_shutdown,.suspend = skyfall_suspend,.resume = skyfall_resume,.driver = {.name = DRIVER_NAME,.owner = THIS_MODULE,}
};static int __init skyfall_init(void)
{int DriverState;//定义驱动状态,判断驱动是否注册成功printk(KERN_EMERG "skyfall driver enter!\n");printk("%s,%d\n",__func__,__LINE__);DriverState = platform_driver_register(&skyfall_driver);/*驱动一旦注册成功,会与设备进行匹配,匹配成功是由platform_match函数进行匹配,驱动调用probe初始化函数*/printk(KERN_EMERG "DriverState = %d\n",DriverState);return 0;
}static void __exit skyfall_exit(void)
{printk(KERN_EMERG "skyfall driver exit!\n");platform_driver_unregister(&skyfall_driver);
}module_init(skyfall_init);
module_exit(skyfall_exit);
以上这些需要配合后面的注册设备与注册驱动相结合。
(2)打开源码目录下的driver/char目录下Makefile文件,添加编译选项
obj-$(CONFIG_SKYFALL_CTL) += itop4412_skyfall.o
(3)打开源码目录下的driver/char目录下Kconfig文件,添加菜单选项
config SKYFALL_CTLbool "Enable SKYFALL config"default yhelpEnable SKYFALL config!
(4)打开menuconfig界面,将Device Drivers —> Character devices—> [] Enable SKYFALL config (NEW) 添加 。
添加完毕后,保存,生成新的.config文件。
(5)查看.config文件
CONFIG_SKYFALL_CTL=y
(6)编译内核 sudo make zImage,查看有没有生成itop4412_skyfall.o中间文件
编译内核
(7)将新生成的内核烧写至开发板中
cp arch/arm/boot/zImage /mnt/share/
(8)在开发板的/dev目录中产生itop4412_skyfall.c 驱动的设备节点skyfall_007。在源码的driver/char目录下,生成了对应的中间文件。
(9)以上是生成skyfall设备节点的步骤。
(10)打开menuconfig界面,将Device Drivers —> Character devices—> [ ] Enable SKYFALL config 去掉 。
保存并退出,生成新的.config文件。
(11)打开.config文件,发现配置成功。
# CONFIG_SKYFALL_CTL is not set
(12)再次编译内核,发现没有中间文件itop4412_skyfall.o生成。
sudo make zImage
(13)将新生成的内核烧写至开发板中
cp arch/arm/boot/zImage /mnt/share/
(14)在开发板的/dev目录中没有产生itop4412_skyfall.c 驱动的设备节点skyfall_007。
(15)至此,整个过程全部完成。
六、内核编译的全部过程
1、红色的线条表示配置文件Kconfig 这一部分,在Kconfig 中要定义针对具体驱动文件的宏变量。然后使用menuconfig 工具生成新的.config文件。
2、黑色的线条表示编译文件Makefile 这一部分,在Makefile 中针对宏变量编译驱动文件。
3、执行make 命令之后,调用.config文件,配合各级目录中的Makefile 文件编译具体的驱动源代码,将源代码编译成.o中间文件。
4、当中间文件全部编译完成之后,编译工具会生成一个非常精炼的zImage二进制文件。
004_Makefile的编译相关推荐
- go build 编译报错 missing go.sum entry for module providing package
go build 编译报错 missing go.sum entry for module providing package 解决方法 // 移除未使用的依赖 go mod tidy 再次编译,就可 ...
- kotlin重写构造方法编译报错:Primary constructor call expected
在kotlin中使用construct关键字定义构造方法,如果类定义时已经有构造方法(类名后带括号),需要添加构造方法时,需要使用以下写法: class User(var name,var age){ ...
- Myeclipse中项目没有代码错误提示,jsp页面无编译迹象?如何解决
在使用Myeclipse开发项目时,发现jsp页面中嵌入的java代码没有编译的迹象,错误的get方法没有报错,没有报错信息我们如何知道我们开发的内容是正确的呢? 接下来就演示一下如何解决
- 初试linux编译(ubuntu+vim)+玩转智能蛇
一.初试linux编译(ubuntu+vim) 步骤: ①下载vmware15+ubuntu桌面版映像 ②安装ubuntu ③下载vim+gcc 在ubuntu终端输入: sudo apt-get i ...
- java调用clang编译的so_写Java这么久,JDK源码编译过没?编译JDK源码踩坑纪实
好奇害死羊 很多小伙伴们做Java开发,天天写Java代码,肯定离不开Java基础环境:JDK,毕竟我们写好的Java代码也是跑在JVM虚拟机上. 一般来说,我们学Java之前,第一步就是安装JDK环 ...
- Go 编译的可执行文件是否有动态库链接?
Go 引用了其他包的话,是将引用的包都编译进去.用 ldd 看几个 Go 编译出来的二进制程序有的没有动态链接库的使用.但是有的又有引用动态链接库,这个是为什么? 回答:Go 默认是开启 CGO_EN ...
- Go 知识点(18)— 条件编译(编译标签、文件后缀)
1. 条件编译 Go 能根据所处环境选择对应的源码进行编译.让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就叫做条件编译. 在 Go 中,也称之为 Build Constraints ...
- RPC 笔记(03)— gRPC 概念、安装、编译、客户端和服务端示例
1. gRPC 概念 gRPC 是 Google 开源的一款高性能的 RPC 框架.GitHub 上介绍如下: gRPC is a modern, open source, high-performa ...
- GCC 同时编译多个 C/C++ 文件
以下这些操作都可以共用一条 gcc 指令: 将多个 C/C++ 源文件加工为汇编文件或者目标文件: 将多个 C/C++ 源文件或者预处理文件加工为汇编文件或者目标文件: 将多个 C/C++ 源文件.预 ...
- GCC 编译 C++ 程序分步骤流程(预处理 gcc -E、编译 gcc -S、汇编 gcc -c 和链接 gcc 以及 gcc -o 选项)
C 或者 C++ 程序从源代码生成可执行程序的过程,需经历 4 个过程,分别是预处理.编译.汇编和链接. 同样,使用 GCC 编译器编译 C 或者 C++ 程序,也必须要经历这 4 个过程.但考虑在实 ...
最新文章
- SpringCloud 教程 | 第二篇: 服务消费者(rest+ribbon)
- bs4之标签树的平行遍历
- 数据结构-二叉树的非递归遍历
- mysql sleep连接过多的完美解决办法
- 【WXS数据类型】Boolean
- GIMP的Path的import和export
- VBScript 程序员参考手册 读书笔记01-07
- 2020,2022年全年详细工作日、周末、节假日数据表sql
- 浅谈国内软件信息化项目项目立项管理办法
- 高中分班考试如何计算机,新高一生如何应对分班考?
- JavaScript swiper
- 蓝绿发布、金丝雀发布、A/B测试
- Arduino追光小车
- 从Hadoop到Spark和Flink,大数据处理框架十年激荡发展史
- Redirect组件的使用
- idea中push代码失败问题解决
- 【地理人工智能交叉】通过整合兴趣点和Word2Vec模型感知城市土地利用的空间分布
- 如何下载通州区卫星地图高清版大图
- java泛型(360°无死角讲解)
- 让低版本的IE浏览器支持HTML5