为linux device driver developer准备的Clion配置指南。
Clion 是JetBrains公司最近推出的跨平台C++ IDE,
如果没有听过Clion,那一定听过IntelliJ Idea,如果还没听过,那一定听过Android Studio,他们
其实都是兄弟产品(Android Studio是基于IntelliJ Idea开发的)。
Clion用CMake作为其编译系统(其他的自定义Makefile也支持),利用CMake的配置文件创建编辑器本身
的代码环境,比如子项目,比如预处理宏等,这跟IntelliJ Idea利用Gradle作为编译系统是同样的道理。
废话不多说,现在开始我们的驱动开发环境配置。
代码路径问题
Clion创建CMake工程后,默认把CMakeLists.txt
所在的目录作为工程根目录,然后它就开始分析根目录下的所有C/C++代码,头文件查找路径是很重要的,
当然它会使用编译器(gcc, g++, clang, visual c等)默认的头文件路径,在linux上就是/usr/include
,/usr/local/include
之类的路径(除非你修改了默认路径)。但是我们的驱动代码
都是放到kernel/drivers/
目录下的,不可能复制出来修改然后再复制回去,太low!聪明的你可能
已经想到解决方法了,对,就是符号链接,ln -s
把kernel里你的驱动代码路径链接到项目根目录下,
完美!
还有一种方法,Clion允许修改工程根目录,完全可以直接把kernel目录作为工程根目录,但是如此
巨量的代码,你是想类似Clion吗?!即使可以把用不到的目录(绝大部分都用不到)标记为忽略,
那也太繁杂了!
头文件路径设置
Clion用library的观点来看待头文件,它把头文件看做是library的导出符号集合,然后把这些library
单独组织起来构成External Libraries
视图,所以问题就明确了: 一个头文件路径就看做是一个library,
我们要开发驱动,自然要把kernel里的头文件引进来(其实驱动开发时,kernel源文件不是必须的,
不过有kernel源码引进来,随时查看各个kenrel函数的实现方式还是蛮爽的),/kernel/include
是必须的,然后CPU架构相关的头文件也是必须的,如果/arch/arm/include
,arch/arm64/include
对应到ARM平台架构。
设置方式就是配置CMakeLists.txt文件:1
2
3
4
5
6
7
8include_directories(
# kernel headers
"${KERNEL_ROOT}/include"
"${KERNEL_ROOT}/arch/arm/include"
"${KERNEL_ROOT}/arch/arm64/include"
# kernel source
"${KERNEL_ROOT}/mm"
)
把mm/
目录引进来干嘛?!因为我想看kernel的源码的,include_directories
指令不仅可以引入
头文件,还可以直接把库文件引进来哦,这样我们就可以有选择性的把kernel的代码引进来了,
避免让Clion解析整个kernel的源码。
另外还有一个不完美的地方,Clion默认把系统头文件引入进来,但是系统头文件版本跟我们用的
kernel版本可能不一致,尤其是交叉编译的时候,如我们为android开发驱动,android可能只是用
3.x的kernel,而我们的linux系统kernel可能已经是4.x,或者它还是2.x,这有时会造成困扰,
所以我们还是用kernel编译之后生成的/usr/include
目录吧,该目录位于kernel_obj/usr/include
,
当然前提是你的kernel编译过了,这样可以保证版本统一。然后呢,我们还要把默认的系统头文件
干掉才行啊,这个很简单,因为Clion使用CMake的构建结果构造代码环境,所以我们只需配置
CMake就好了,在CMakeLists.txt里面添加编译器选项来解决这个问题:set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -nostdinc")
用c99选项是因为kernel大量使用c99的feature,而-nostdinc
就是说no standard include files
。
符号解析问题
代码路径问题解决了,头文件引入问题解决了,接下来打开你的C代码,啊呀,WTF,一篇红啊!
这么多符号都解析不出来,Clion你难不成是徒有虚名?!
其实这不能怪Clion,你把哪个IDE弄来都是这样,Eclipse CDT,KDevelop,QTCreator,谁都白扯,
这是代码问题。问题就出在__KERNEL__
这个宏身上,原来kernel为了保护其代码,故意设置了这么一个
宏,只有在编译kernel的时候才会在命令行传递这个宏进去,像libc等C runtime编译时要用到kernel
的部分代码,但是它不会设置__KERNEL__
这个宏,于是被这个宏保护的kernel代码它是看不到的。
自然,我们的Clion没有定义这个宏,那些kernel代码(大部分代码)它也是看不到的,于是parser在
解析头文件时,很多符号是解析不出来的,然后只能红红火火起来了。
怎么解决呢? 没有这个宏,我们手动添加这个宏不就好了,别忘了,Clion使用CMake的构建结果来
构造代码环境,所以我们只需给CMake添加预处理宏即可,还是在CMakeLists.txt里面,add_definitions(-D__KERNEL__=1)
Reload CMake Project之后,发现碍眼的红色提示消失了,但是别高兴的太早,你看下kmalloc
,
这个定义咋是空的呢?WTF!
别急,问题跟__KERNEL__
宏是一样的,原来kernel在编译之前会配置一堆的config,make menuconf
就是用来生成这些config的,kernel/include/generated/autoconfig.h
就是啦,这里面定义了
上千条宏定义,kernel代码根据这里的宏定义而走不同的代码,所以跟__KERNEL__
一样,把这些
宏也一并加进去吧!美中不足的是,没有方法可以直接吧autoconf.h
直接丢给CMake让它解析宏定义,
只能手动add_definitions
,不过好在这些宏比较规律,用正则表达式来查找替换,也花不了几分钟。
Bingo,配置完成。什么代码高亮,爽歪歪的代码补全(折腾了半天还不都是为了你啊),错误提示等等,
Happy coding!
示例
最后来一个配置示例,这是我用来做Android驱动开发的配置。
1 | cmake_minimum_required(VERSION 3.5) |
(over)