code:block怎么生成linuxwindows makefilee

博客访问: 8780
博文数量: 8
博客积分: 0
博客等级: 民兵
技术积分: 112
注册时间:
认证徽章:
潜心静气。。慢慢出成果
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
最近一直在搞Makefile文件的编辑,一直想通过自己的心得体会与广大网友分享。Linux学习者只有参与的大多人当中去,才能体会到乐趣。同时慢慢培养自己的学习linux的兴趣爱好。与广大网上爱好者互动。
Linux的GNU计划:
Linux下构建自己的开源软件使用的是linux下自己带的强大的工具。Autoconf& libtoolize 和automake .这是开源软件必须的基本工具。
如果使用了autoconf和automake,除了编译应用程序,用户并不需要有这些工具。使用这些工具的目的是创建能在用户环境使用的、可移植的shell脚本和Makefile文件。
Autoconf实际上是一个工具集,其中包含aclocal、autoheader和autoconf等可执行文件。这些工具生成一个可移植的shell脚本—configure,configure和软件包一起发布给用户。
它探查编译系统,生成 Makefile文件和一个特殊的头文件config.h。由configure生成的文件能适应用户系统的特定环境。
configure脚本从一个称为 Makefile.in的模板文件生成每个Makefile文件。
而Makefile.in 有Makefile.am 生成。
Configure.in 有开发者自己手动修改。
Makefile.am 是由开发者自己手写。
Libtool软件包是第三个重要的GNU工具,它的作用是确定共享库在特定平台上的特性。因为共享库在不同平台上可能会有所不同。
上述是自动生成Makefile的概括。以后再细讲。
手动书写Makefile:
手动书写顾名思义就是自己跳过configure.Scan& configure.in
configure Makefile.am Makefile.in 的生成过程。直接书写Makefile 这种方式只能用于相对简单的源代码。如有几个,几十个或者上百个源文件时,自己编写Makefile往往是可行的,但是如果我们所编写的源文件有几千,几万,几十万甚至更多时,显然手动书写Makefile不是个明智之举。
我们在手动书写Makefile时(此心得面向是略微看过Makefile的编写规则。如果没看过,可以参考这个文章“大家一起写Makefile”里面有蛮详细的介绍)一个简单的makefile的书写。
我们只需要把握编译选项,链接选项目标依赖文件等
给大家分享下自己的自己对编译和链接的领悟(勿拍砖)编译就是将检测各种源文件的语法是否正确。我们称之为是从.cà到.o的过程。这个过程中只是检测语法错误。而链接过程我称之为从.oà.a或者.la 然后从.a(la)到可执行文件的过程。其中有心的各位会发现.a或者.la是一个很大的文件。笔者以为这只是个中间连接文件。就是把所有的函数。调用子函数。以及嵌套调用的函数在中间文件里铺开的过程。
现在以笔者最近的一个例子作为分析进入到Makefile文件的编写中;
CROSSCOMPILE :=arm-linux-
CC :=$(CROSSCOMPILE)gcc
LD :=$(CROSSCOMPILE)ld
LDFLAGS := -lm
CLFAGS := -Wall -02 -c -g
CFLAGS += -I $(PWD)
OBJS :=bitstream.o\
&&&&&&&& && mmask.o\
&&&&&&&& && mqrspec.o\
&&&&&&&& && qren.o\
&&&&&&&& && qrencode.o\
&&&&&&&& && qrinput.o\
&&&&&&&& && qrspec.o\
&&&&&&&& && rscode.o\
&&&&&&&& && split.o
.PHONY:%.o
&&&&&&&& $(CC)& $(CFLAGS) $< -o $@
all:$(OBJS)
&&&&&&&& $(CC)& $(LDFLAGS) -o qrencode $^
.PHONY:clean
&&&&&&&& rm
-rf $(OBJS) qrencode
很明显这是个属于极其简单的Makefile文件。有初学者会认为。很多我拿到的代码里已经有了Makefile 我干嘛还有学习Makefile编写呢?我觉得对于只想移植。不想开发的朋友来说或许足够了。但是对于我们要往深水区来游的小同志来说。显然Makefile的编写和shellscript 的编写。很明显是我们的必修课。这是我们对大工程把握水平的体现。
结束废话:开始分析Makefile的写法:
首先进come到我们面前的是CROSSCOMPILE :=arm-linux
CROSSCOMPILE :=这是个变量定义而且是一个可以传递到底层Makefile文件的定义变量。而且必须是传递到底层。然而一旦传递的底层。它必然是个环境变量。所以可以选择export linux下的命令来全局化。所以Makefile中变量的定义是如果需要引入到环境变量中请选择全程大写。如果仅是这个Makefile中使用。不会用到子目录Makefile中,请选择小写。当然即使大写我们也需要配合export后才可传递到底层Makefile
按照进程的思想,当前Makefile层是一个进程,调用下一层Makefile的过程就是开启一个新的进程。调用下一个进程使用include + Makefile文件
第二个符号:= 这是个环境变量的定义。
= 表示定义一个新的变量。:=表示是如果前边定义过了则选择是覆盖之前的定义。+=表示追加。?=则是表示如果询问定义,既是如果前边定义了,这里不在定义。
而arm-linux-gcc这里所说的是arm下交叉编译工具而gcc则是linux下的编译工具
当然如果选择的是C++ 则是g++ 和arm-linux-g++ 这里采用C语言。毕竟编译和链接过程跟C++ 类似。
上述二位是非常敬畏的了编译器。因为linux下它的出现解决了编译工具的问题。
而编译对应的是链接。链接分别对应的是arm-linux-ld 和ld 当然不同的交叉编译版本不同。可能略有差别。只有交叉编译的概念。如有误解请问伟大的度娘或者强大的360
CC以及LD这里定义的是编译器和链接器这里采用可以方便修改的做法。用的是变量替代。
往下走时是我们的参数传递。我们知道在linux命令行下使用gcc 或者arm-linux-gcc时我们也会有参数传入,这里就是我们所说的参数传递。参数传递的意思则是
-lm则是告诉编译器如果数学库找不到请到/libs下找。我们是需要数学库的
数学函数位于libm.so库文件中(这些库文件通常位于/lib目录下),-lm选项告诉编译器,我们程序中用到的数学函数要到这个库文件里找
一般参数很多我们这里只介绍必须的。很多是缺省的。就是了解有这回事。未必一定要用的
-c 告诉编译器你编译的对象是.c
-o 告诉编译器编译无错后输出文件格式为.o
-static告诉编译器不用动态库,只是使用静态库(动态库和静态库的去一个是.so一个是.a)这个编译后会产生很大的文件。一般不使用
与之对应的这是只是使用动态库–share 这一般是我们的选择。
还有就是-S生成汇编文件
-E生成预处理文件
-wall 启动警告检测
-02 是编译器的级别一共 00 01 02 03 四个编译器级别。-00表示没有优化,-01为缺省值,-03优化级别最高
-g 为在编译的时候,产生条是信息
-I指定头文件目录
$(PWD) 表示执行linux下命令 pwd 一个生成当前位置的变量。并替代了。
其余的参数如果有需要的可以自己查看拉。毕竟编译器是个很强大的。
参数的废话结束了那么我们进入到我们的目标定义
目标定义的一个显著符号则是:
如ALL: $(OBJS) 这里说明我们这就是编译的总目标
Makefile文件里可以定义编译一个目标,也可以定义编译多个目标(设计伪定义)
就是下面使用的关键字.PHONY
Makefile文件中总是默认第一个定义的目标作为总体的生成目标。使用上诉关键字后编译器就是知道了这里不是,只是一个伪目标。
通常配合着clean distclean 来使用。那就是后边的删除
rm –rf $(OBJS) qrencode
这里指的是删除所有生成的目标文件
rm是linux下一个命令。不在叙述。
下边进入到奇怪的字符的解释:
$ 是一个用了很多遍的字符是一个具有替代功能的字符
如$(OBJS)就是替代我们定义的所有的变量。
还有就是$@ 是在编译过程中的所生成的目标文件
$<是我们所依赖的文件
$(CFLAGS) $< -o $@
上述的语句就是 CC替代arm-linux-gcc CGLAGS 用来替代我们的参数传递
$<表示依赖所有的.C 文件–c的参数传递在CFLAGS&& -o目的是生成.o 文件
所以S@则是目标文件
“%”的意思是匹配零或若干字符
就是自动匹配这里的o和c 文件
$(LDFLAGS) -o qrencode $^
这句话的解释则是编译生成qrencode的可执行文件。
$^的意思则是自动依赖所有的文件
所以看者不知道是否明白了一个手写Makefile的语法写的过程?
其实就是把我们平时写的arm-linux-gcc –c mian.c –o mian.o
原理类似。
至于Makefile中的自动查询的方式:
我们知道上述是一个隐式的Makefile的编写方式。
Makefile中* 为通配符这个玩过Linux肯定知道。还有就是换行符\
特别声明下如果在命令下加入@ 表示该条命令只是执行但不输出该条命令。
输出执行命令结果。
显式的编写方式往往看者很明白。但是很繁琐。
隐式的写法就是使用了自动匹配和静态编写的方式写成了上诉的Makefile
当然复杂的makefile还会有linux的shell命令的使用
还有就是我们的字符命令这里的简单书写个人感觉暂时用不着。
还有就是简单命令的使用
VPATH 用于声明代码的路径
%.c& file1
路径声明优先搜索file 和file1
Makefile下每条命令下执行正确了都会返回0 错误返回非0 然后检测退出。
Make –t =touch 更新目标文件时间但不进行新的编译。
Make –q =question 如果目标不在。打印输出。目标在,不显示
Make –f=file指定编译文件
这里感觉使用的就是这么几个。
至于字符函数的处理。笔者的功力真的没有那么深。暂时手动写Makefile过程中未使用过。
自动生成Makefile的过程为:
1.& 执行autoscane& 生成configure.scan
2.& 然后手动修改configure.scan为configure.in 有的平台直接为configure.ac
3.& 修改configure.in 里面的内容。怎么修改。下文讲,这给给看客一个大致全过程。
4.& 执行autoheader生成文件configure.h.in(现在一般改为configure.ac)。configure.in里有宏AC_CONFIG_HEADER()时用
5.& 运行libtoolize生成一些libtool 的文件这些文件跟平台适应性有关系。
6.& 运行autoconf 执行过程中会生成configure 文件
7.& 手动写makefile.am 写的过程下文详细介绍
8.& 执行automake –a 将makefile.am 生成Makefile.in 同时生成选项可以补齐文件config.guess,config.sub,install-sh,missing,depcomp
9.& 然后执行./configure 后边会有缺省的参数比如
生成文件生成config.status,config.h,makefile
对于符合GNU的源码通常目录下包含那些文件又有哪些组成?
必须有一个README主要是介绍源码包的详细信息。
一个INSTALLIN文件介绍安装包的使用方法和安装方式
一个configure文件主要配合Makefile.in 生成Makefile文件。
一个CONPYING 包含版本信息
一个CHANGELOG 包含软件的变化过程。
通常我们做顶层目录可以包含任何的信息,然后才是做底层的目录。分别设置其配置文件
我们用linux-2.26.32来分析:
顶层目录:
这里我们就可以看到一个大型工程里顶层目录的基本文件:
README CONPYING 等当然很多文件是我们后期执行make zImage时生成的。
但是我们通过这里见识到了源码的分类存放和基本的配置文件。
Arch架构下存放各种的关于架构的信息如:
当然linux系统下的跟我们这里讲的还是有差别的。Linux下不可能手动书写makefile 而是采用makemenuconfig 或者make Xconfig 来配置不同的执行对应着不同的脚本文件
如make menuconfig 对应着是Kconfig 最后会被选择后进入到.configure 然后配合顶层makefile使用。
而我们这里说的是应用软件的编写。
所以做GNU的文件源码我们一定要会源码分类放,同时学会修改configure.in
和手动编写Makefile.am
下文将着重介绍Makefile.am 编写和configure.in 修改
例如我们随便建立三个文件
一个是main.c
一个是hello目录下main.c
int main(int argc,int *argv)
&&& int num[100];
&&& int val=0;
&&& int val2=0;
printf("argv[1]===%d \n",argv[0]);
printf("argv[2]===%d \n",argv[2]);
val=add(argv[1],argv[2]);
val2=lsl(argv[1],argv[2]);
printf("val=%d \n",val);
printf("val2=%d \n",val2);
我们在add目录下建立add.c
int add(int i,int j)
int num=i+j;
printf("here is add.c:\n");
在 hello 下建立lsl
int lsl(int i,int j)
int val=i*j;
printf("here is lsl\n");
我们执行完autoscan后生成 configure.scan 和autoscan.log
其实configure.scan就是configure.in的模板
于是我们的configure.scan内容就是
# -*- Autoconf -*-
# Process this file with autoconf to
produce a configure script.
AC_PREREQ([2.63])
AC_INIT([FULL-PACKAGE-NAME],[VERSION],[BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for header files.
# Checks for typedefs, structures, and
compiler characteristics.
# Checks for library functions.
而我们手动修改成configure.in后为
#&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&-*- Autoconf -*-
# Process this file with autoconf to
produce a configure script.
AC_PREREQ(2.61)
AC_INIT(hello, 1.0, [])
AM_INIT_AUTOMAKE(hello, 1.0)
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and
compiler characteristics.
# Checks for library functions.
AC_OUTPUT(Makefile add/Makefile
lsl/Makefile)
通过对比我们发现其实我们只是更改了部分文件。
AC_PREREQ(2.61)
指的是我们使用的内核版本号
当然这里的输入接口AC_INIT(hello, 1.0, [])
分别指的是输入接口,源码包,源码包版本号,缺省
AM_INIT_AUTOMAKE(hello, 1.0) 这句话指的是我们要使用automake 所传入的宏定义。
里面参数顾名思义也是源码包和版本号。
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADER([config.h])
这两句话一个指的是需要检查的目下下的文件,一个是config.h文件
如果confi.h文件不在,我们需要手动输入很多参数,如下:
Gcc-DPACKAGE_NAME=\"hellobb\"-DPACKAGE_TARNAME=\"hellobb\"-DPACKAGE-VERSION=\"1.0\"
-DPACKAGE_STRING=\"hellobb\ 1.0\" -DPACKAGE_BUGREPORT=\"\"
-DPACKAGE=\"hellobb\" -DVERSION=\"1.0\" -DSTDC_HEADERS=1
_DHAVE_SYS_TYPES_H=1 -DHAVE_UNISTDLIB_H=1 -DHAVE_STING_H=1 -DHAVE_MEMORY_H=1
-dHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1
-DHAVE_DLFCN_H=1 -DLT_OBJDIR=\"./libs/\" -I. -g -O2 -MT main.o -MD
-MP -MF .deps/main.Tpo -c -o main.c
所以离开了config.h 是何等的麻烦。还有就是我们使用的
AC_PROG_CC
AC_PROG_LIBTOOL
一个指定的是CC 所替代的编译工具,工具的指定可以在configure处指定,也可是make 处指定
下一行这是指定使用LIBTOOL编译成库
最后的输出接口则是
AC_OUTPUT(Makefile add/Makefile lsl/Makefile)
指定生成的makefile文件
以上是简单地更改过程。
然后是makefile.am 书写过程
AUTOMAKE_OPTIONS = foreign
SUBDIRS = add lsl
bin_PROGRAMS = main
main_SOURCES = main.c
main_LDADD = add/libadd.la lsl/liblsl.la
一个简单地makefile.am 顶层的书写
而各个底层也需要有自己的makefile.am
lib_LTLIBRARIES = liblsl.la
liblsl_la_SOURCES = lsl.c
书写完成后,进过上述几步后你会发现我们看到GNU的文件基本都有了
然后就可以放心的执行make make install 等
如果想制作一个基于arm 平台的我们只需要在./configure 处加上交叉编译选项即可:
那么我们所需要更改的是
--host =arm-linux
指定软件运行的系统平台.如果没有指定,将会运行`config.guess'来检测
-build=BUILD
指定软件包安装的系统平台.如果没有指定,默认值将是'--host'选项的值.
 --host=HOST
指定软件运行的系统平台.如果没有指定,将会运行`config.guess'来检测.
-srcdir=DIR
这个选项对安装没有作用.他会告诉'configure'源码的位置.一般来说不用指定此选项,因为'configure'脚本一般和源码文件在同一个目录下.
--program-prefix=PREFIX
指定将被加到所安装程序的名字上的前缀.例如,使用'--program-prefix=g'来configure一个名为'tar'的程序将会使安装的程序被命名为'gtar'.当和其他的安装选项一起使用时,这个选项只有当他被`Makefile.in'文件使用时才会工作.
有时候你可能不想让你的软件包与系统已有的软件包交互.例如,你可能不想让你的新编译器使用GNU ld.通过使用这个选项可以做到这一点:
$ ./configure --without-gnu-ld&
阅读(1915) | 评论(0) | 转发(2) |
上一篇:没有了
相关热门文章
给主人留下些什么吧!~~
请登录后评论。& 相关文章 &
利用cbmakegen导出Code::blocks的Makefile
首先到官网下载cbmakegen 官网地址:链接地址 也可通过我的百度网盘下载 【windows版本】地址:链接地址 【linux版本】地址:链接地址 【Windows】 解压cbMakefileGen-bin-0.3.12.5-Win32 得到cbMakefileGen.cbplugin 打开Code::Blocks界面的Plugins-&Manage Plugins 添加cbMakefileGen.cbplugin 然后在Project菜单中会出现Generate Makefile选项,即可导出Makefile 在工程目录中会出现Makefile.gen
X3 C++ PluginFramework 今天发布了新版本1.0.9,距离上个版本正好三个月,主要完善内容有: 1、移植到 Linux,加入 Makefile 文件,能够基本运行起来; 2、对内核文件进行局部完善,替换ConfigXml插件,移动整理工程文件,满足Win32、Linux、VC++、CodeBlocks、Makefile 的移植编译要求。
目前 X3 C++ PluginFramework 可在下列环境编译: 1、Windows: VC++ 6.0/
1. 安装g++
yum install gcc-c++ 2 安装codeblocks
yum install codeblocks 3 安装xterm yum install xterm
1. 利用Makefile 2. 在VS中配置 3. 利用VisualDDK插件
。需要用dragon的jtag。 住:Debug其实不是很推荐使用,虽然比较高效,建议利用串口的信息输入输出(以后会介绍),这是因为在进入系统的嵌入后,常规的debug经常会无法使用。 实际的命令会是 [plain]
view plain copy avarice -g -j usb --erase --program --filemain.hex :4242
不过如果makefile里已经写好的话直接输入sudo make debug就可以了 下面为命令的结果 现在属于等待GDB,可视化
Linux下CodeBlocks的交叉编…
原文地址:Linux下CodeBlocks的交叉编译 作者:samzhen 作者: Sam (甄峰) sam_
Sam一直是Makefile流,这些天需要移植一些游戏引擎模块。这些模块在其它嵌入式平台上是使用CodeBlocks编译的,Sam不想再去写Makefile。所以只好学习使用CodeBlocks交叉编译了。
与Makefile相同,CodeBlocks也需要提供交叉编译器,并指定include,library目录。过程如下:
0. 打开多个
codeblocks 汉化
首先找 在ubuntu软件中心里搜索codeblocks,点击安装
然后他就会自动帮你全部弄好了
然后就是在 CodeBlocks的所有目录。打开终端,运行命令 locate codeblocks 复制代码 等一片一片的刷过去之后发现,因为终端显示局限性,很多没有显示出来,只好修改命令: locate codeblocks &codeblocks 复制代码 把结果输出到一个名为codeblocks的文件中,然后打开文件来看。输出结果很多,下面我只列举出有用的几条: /etc
【CodeBlocks 非官方翻译】相关资源[首个预览版(zh_CN)已发布]
一、翻译参考资源 1.
CodeBlocks 12.11 full 2.
zh_CN for 10.05 3.
zh_CN offcial 二、项目发布资源 1. CodeBlocks 12.11 unoffcial v 0.1 @ 首个预览版(zh_CN) 翻译率:11.06% 使用方法:
将下载的 .mo 文件放到 ...\CodeBlocks\share\CodeBlocks\locale\zh_CN\ 目录中,并在 Setting--Environment--View 中勾选
然后重新启动 Code::Blocks 即可。
codeblocks使用
,对应的文档就会出现通过快捷键F1。… 1.10.8 集成外部工具
通过菜单[Tools-&Configuration Tools–&Add],把外部工具集成到CodeBlocks开发环境中。这些外部的工具允许以参数的形式访问CodeBlocks的内建 (Built-in)变量(如当前项目所在的文件夹${PROJECT_DIR})。利用这个功能,我们给CodeBlocks添加一个菜单项:打开当前 项目所在的文件夹。请看图: 链接地址 (译者注:这是一个非常实用的功能。利用这个功能,我在我
CodeBlocks中文版使用手册
集成外部工具
通过菜单[Tools-&Configuration Tools–&Add],把外部工具集成到CodeBlocks开发环境中。这些外部的工具允许以参数的形式访问CodeBlocks的内建 (Built-in)变量(如当前项目所在的文件夹${PROJECT_DIR})。利用这个功能,我们给CodeBlocks添加一个菜单项:打开当前项目所在的文件夹。请看图: 链接地址 (译者注:这是一个非常实用的功能。利用这个功能,我在我的CodeBlocks中,添加了三个我最常用的菜单项:使用
Tools–&Add],把外部工具集成到CodeBlocks开发环境中。这些外部的工具允许以参数的形式访问CodeBlocks的内建(Built-in)变量(如当前项目所在的文件夹${PROJECT_DIR})。利用这个功能,我们给CodeBlocks添加一个菜单项:打开当前项目所在的文件夹。请看图: (译者注:这是一个非常实用的功能。利用这个功能,我在我的CodeBlocks中,添加了三个我最常用的菜单项:使用Notepad++打开当前文件;打开当前项目所在的文件夹;以Dos窗口打开当前文件夹
的30%以上。 (2)WndTabs:用于显示打开过的源文件,并将源程序用Tab页面来管理,VC 6.0必装工具。 3. 程序编辑器:notepad++,editplus。UltraEdit文本编辑器,Source Insight,codeblocks,自己钟情于notepad++和codeblocks,代码高亮做的蛮好 4. 内存泄露检查:BoundsChecker 6.5 和Vld ,小提示:虽然他们很好用,但是不用的时候最好关闭他们,以防引入其他问题 5. 代码格式化和导出html
工具。 (3)VC6LineNumberAddin :VC6.0显示行号插件
3. 程序查看和编辑:notepad++,editplus。UltraEdit文本编辑器,Source Insight,codeblocks,自己钟情于notepad++和codeblocks,代码高亮做的蛮好
4. 内存泄露检查:BoundsChecker 6.5 和Vld ,小提示:虽然他们很好用,但是不用的时候最好关闭他们,以防引入其他问题 5. 代码格式化和导出html:code2html 和http
/ 2. Windows下利用GNU编译的工具集:MinGW ("Minimalistic GNU for Windows")。该工具集可以在windows下编译linux下开源软件,并生成.dll,.exe等windows本地可执行文件。相对 CygWin等重量级环境,MinGW是比较轻量级和适用的。MinGW支持C,C++,Fortran77等的编译。MinGW包含了轻量级的可自由使 用和分发的windows平台相关的头文件和库以及GNU工具集,不必依赖于第三方C语言头。 MinGW使用了
CodeBlocks中文汉化Code::Blocks 10.05 中文版
http://jianhai1229./blog/static// 实现中文界面
实现中文界面,包括两个步骤。最主要的是安装其中文简体语方包。然后是安装今日提示英中双语版文件。前一文件由本站提供改进,后一文件由本站在原英文版上自行提供。 如果您正在使用CodeBlocks,请确保先退出该程序。 5.1 安装中文语言包 首先,请在 X:\CodeBlocks\share\CodeBlocks\ 建立一个子文件夹:locale
Codeblocks安装
Codeblocks是个很不错的C/C++编译器,专一啊!而且很小! 安装Codeblocks前需要安装 wxGTK,可以从这里下载: http://www.wxwidgets.org/downloads 其次就是下载Codeblocks源码包,地址: http://www.codeblocks.org/downloads 先装GTK,解压缩: # tar -zxvf wxGTK-2.8.9.tar.gz 接着进入解压出来的目录: # cd wxGTK-2.8.9 # ./configure
Oracle备份之导入导出
导出: 导入:
codeblocks-libs-10.05-1.el5.i386.rpm 2、安装中文包
地址就不放了,在csdn上搜索codeblocks 10.05 汉化 就能找到。
mkdir/usr/share/codeblocks/locale/
mv ./zh_*/usr/share/codeblocks/locale/
在codeblocks的主菜单 Settings--&Environment--&view 选上
还是啰嗦下,先利用codeblocks将jsoncpp的vs工程直接打开,然后直接编译即可得到想要的.a文件,即静态链接库,然后自己在usr/local下面建立自己的目录将其中的头文件和库文件放入,当然mv命令即可! 然后我们将codeblocks中的编译选项中加入头文件和库文件即可编译!这个和时下流行的cocos2d-x的客户端进行通信非常方便,很容易利用http协议构建自己的c++服务器。详细的http服务可以参考boost 的asio中http3构建服务器。 sss
matlab mex 应用接口程序,codeblocks IDE,使用gcc编译器
,ncols,mxREAL); x=mxGetPr(prhs[0]); y=mxGetPr(plhs[0]); timestwo(y,x); }
当然你也可以自己写Makefile文件,相关设置参考codeblocks手册。次方法应该也适用于DEV++
& 2012 - 2016 &
&All Rights Reserved. &
/*爱悠闲图+*/
var cpro_id = "u1888441";
/*爱悠闲底部960*75*/
var cpro_id = "u1888128";linux(41)
/amanlikethis/p/3675486.html?utm_source=tuicool&utm_medium=referral
     
1、本文的意义
  众多的资料(《嵌入式Linux应用开发完全手册》、Documentation/kbuild/makefiles.txt)已经向我们展示了一个初级Linux用户者应该懂得的知识--怎样添加需要编译的文件、添加编译的规则、多个源文件构成一个目标文件的情况等。
  但是,一种“找到真相”的冲动迫使我想了解Linux内核编译的整个过程是怎样的。为此,查了很多资料,发现《深度探索Linux操作系统:系统构建和原理解析》一文的第三章对该问题有很详细的论述。
  经过一番分析,也有自己的想法,写于此。本文主要讨论的是Linux内核编译的整个过程,以此为基础,再来讨论诸如Linux内核Makefile的特点、构成元素等其他的问题。
  对于分析Linux Makefile的整个编译过程,笔者认为需要对Makefile有一定的基础。如果之前没接触过Makefile的,不建议看本文。另外,对于那些只需要初级认识的Linux用户也无需对此付出过多精力,可以直接飘过。
2、Linux内核Makefile文件组成
Linux内核Makefile文件组成
顶层 Makefile
它是所有Makefile文件的核心,从总体上控制着内核的编译、连接
arch/$(ARCH)/Makefile
对应体系结构的Makefile,它用来决定哪些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定&#26684;式的内核映像
scripts/Makefile.*
Makefile公用的通用规则、脚本等
子目录kbuild Makefiles
各级子目录的Makefile相对简单,被上一层Makefile.build调用来编译当前目录的文件。
顶层.config
配置文件,配置内核时生成。所有的Makefile文件(包括顶层目录和各级子目录)都是根据.config来决定使用哪些文件的
&scripts/Makefile.*中有公用的通用规则,展示如下:
scripts/Makefile.*文件组成
Makefile.build
被顶层Makefile所调用,与各级子目录的Makefile合起来构成一个完整的Makefile文件,定义.lib、built-in.o以及目标文件.o的生成规则。这个Makefile文件生成了子目录的.lib、built-in.o以及目标文件.o
Makefile.clean
被顶层Makefile所调用,用来删除目标文件等
Makefile.lib
被Makefile.build所调用,主要是对一些变量的处理,比如说在obj-y前边加上obj目录
Kbuild.include
被Makefile.build所调用,定义了一些函数,如if_changed、if_changed_rule、echo-cmd
  Linux内核Makefile体系核心的Makefile文件就两个:顶层Makefile、scripts/Makefile.build。
  子目录中的Makefile、kbuild不是Makefile文件(完整的Makefile文件),只能算作是Makefile的包含文件。
  顶层Makefile文件负责将各个目录生成的*.built-in.o、lib.a等文件连接到一起。而scripts/Makefile.build 包含子目录中的Makefile文件来生成这些*.built-in.o、lib.a、*.o等文件。
二、Linux内核Makefile的“make解析”过程
  本文的实验源码是对“linux-2.6.30.4”进行移植后的运行在TQ2440开发板上的源码包。
1 顶层Makefile阶段
1、从总目标uImage说起
  内核配置完成后,在顶层目录中执行“#make uImage”便开始编译内核。但是,uImage却不是在顶层Makefile中定义,而是在arch/$(ARCH)/Makefile中定义。
顶层Makefile Line 452: include $(srctree)/arch/$(SRCARCH)/Makefile
  其中srctree为源码绝对路径,以我的环境为例,它的&#20540;等于/workspace/linux-2.6.30.4;而SRCARCH := $(ARCH),即该变量等于架构名称,我们以arm为例进行说明。&
arch/arm/Makefile Line 230: zImage Image xipImage bootpImage uImage: vmlinux
  可见uImage依赖于vmlinux,要先生成vmlinux,然后执行下边这条指令完成编译。
arch/arm/Makefile Line 231: $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
&1& Q的定义:选择静态编译与否(是否打印编译信息)
顶层Makefile Line 290:ifeq ($(KBUILD_VERBOSE),1)
quiet=quiet_
&2& MAKE: 系统环境变量,&#20540;为make
&3& build: &#20540;为“-f scripts/Makefile.build obj=”实际上就是调用子Makefile--scripts/Makefile.build,然后传递参数目标文件夹。
Kbuild.include Line 141:# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# $(Q)$(MAKE) $(build)=dir
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
Kbuild.include被顶层Makefile所包含
顶层Makefile Line 312:
# We need some generic definitions (do not try to remake the file).
$(srctree)/scripts/Kbuild.include: ;
include $(srctree)/scripts/Kbuild.include
2、vmlinux的生成
顶层Makefile Line 845: # vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
ifdef CONFIG_SAMPLES
$(Q)$(MAKE) $(build)=samples
ifdef CONFIG_BUILD_DOCSRC
$(Q)$(MAKE) $(build)=Documentation
$(call vmlinux-modpost)
$(call if_changed_rule,vmlinux__)
$(Q)rm -f .old_version
  vmlinux的依赖是“$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE”,要想生成vmlinux必须要先把这些原材料准备好。
&1& vmlinux-lds
  在编译之前要把连接脚本先生成,最后的连接阶段会用的着。
顶层Makefile Line 699: vmlinux-lds
:= arch/$(SRCARCH)/kernel/vmlinux.lds
&2& vmlinux-init
顶层Makefile Line 696: vmlinux-init := $(head-y) $(init-y)
& ①head-y
arch/arm/Makefile Line 100: head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
顶层Makefile Line 477:
顶层Makefile Line 661:
:= $(patsubst %/, %/built-in.o, $(init-y))
  init-y最终等于init/built-in.o
&3&vmlinux-main
顶层Makefile Line 697:
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
arch/arm/Makefile Line 196:
core-y &#43;= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
arch/arm/Makefile Line 197:
core-y &#43;= $(machdirs) $(platdirs)
顶层Makefile Line 481:
顶层Makefile Line 650:
&#43;= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
顶层Makefile Line 662:
:= $(patsubst %/, %/built-in.o, $(core-y))
  core-y最终等于
core-y := usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o \
crypto/built-in.o block/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o
arch/arm/Makefile Line 204:
:= arch/arm/lib/ $(libs-y)
顶层Makefile Line 480:
顶层Makefile Line 665:
:= $(patsubst %/, %/lib.a, $(libs-y))
顶层Makefile Line 666:
:= $(patsubst %/, %/built-in.o, $(libs-y))
顶层Makefile Line 667:
:= $(libs-y1) $(libs-y2)
  libs-y最终等于arch/arm/lib/lib.a &lib/lib.a &arch/arm/lib/built-in.o &lib/built-in.o
③drivers-y
顶层Makefile Line 478:
:= drivers/ sound/ firmware/
顶层Makefile Line 663:
:= $(patsubst %/, %/built-in.o, $(drivers-y))
  drivers-y&#20540;最终等于rivers/built-in.o sound/built-in.o firmware/built-in.o
顶层Makefile Line 479:
顶层Makefile Line 664:
:= $(patsubst %/, %/built-in.o, $(net-y))
  net-y最终等于net/built-in.o
&4& vmlinux.o
  目前还未分析
&5& kallsyms.o
  目前还未分析
  它的目的是强迫重建vmlinux(无论上边的原材料是否已经构建,无论上边的原材料是否比已经生成的目标新,都要重建),这种用法在Linux Makefile体系中经常见到。
PHONY &#43;= FORCE
# Declare the contents of the .PHONY variable as phony.
We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY: $(PHONY)
  可以看到FORCE为一个伪目标,所以无论如何都要重建vmlinux。
&&7& 通过编译查看最终的依赖文件
root@daneiqi:/workspace/linux-EmbedSky# make uImage V=1
arm-linux-ld -EL
-p --no-undefined -X --build-id -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o
arch/arm/kernel/init_task.o
init/built-in.o --start-group
usr/built-in.o
arch/arm/kernel/built-in.o
arch/arm/mm/built-in.o
arch/arm/common/built-in.o
arch/arm/mach-s3c2410/built-in.o
arch/arm/mach-s3c2400/built-in.o
arch/arm/mach-s3c2412/built-in.o
arch/arm/mach-s3c2440/built-in.o
arch/arm/mach-s3c2442/built-in.o
arch/arm/mach-s3c2443/built-in.o
arch/arm/plat-s3c24xx/built-in.o
arch/arm/plat-s3c/built-in.o
kernel/built-in.o
mm/built-in.o
fs/built-in.o
ipc/built-in.o
security/built-in.o
crypto/built-in.o
block/built-in.o
arch/arm/lib/lib.a
arch/arm/lib/built-in.o
lib/built-in.o
drivers/built-in.o
sound/built-in.o
firmware/built-in.o
net/built-in.o --end-group .tmp_kallsyms2.o
  命令中的参数V=1的含义是“顶层Makefile&Line 36: # Use 'make V=1' to see the full commands”。
3、vmlinux-lds、vmlinux-init、vmlinux-main的生成
&1& &vmlinux-dirs
顶层Makefile Line 871:
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
  vmlinux的主要构成文件vmlinux-init、vmlinux-main、vmlinux-lds的依赖是vmlinux-dirs。
顶层Makefile Line 652:vmlinux-dirs
:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
  filter首先过滤掉不是文件夹的(带“/”的就是文件夹),然后patsubst将所有的文件夹后边的“/”去掉。笔者在顶层Makefile中添加一个伪目标Debug,使它打印vmlinux-dirs,然后在终端上执行命令&make Debug&得到vmlinux-dirs的&#20540;为:
init usr arch/x86/kernel arch/x86/mm arch/x86/crypto arch/x86/vdso kernel mm fs ipc security crypto block drivers sound firmware net lib arch/x86/lib
  可见vmlinux-dirs都是源码包本来存在的文件夹,怎么通过这些文件夹的名字来生成它们目录下的*.built-in.o、lib.a呢?
&2& vmlinux-dirs对应的命令
顶层Makefile Line 879: PHONY &#43;= $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
  vmlinux-dir所代表的目录都是伪目标,这样即使这些文件夹是存在的,也要执行它们对应的命令。
① prepare
 在正式开始编译之前,要先将准备工作做好,检查输出目录是否与源码目录分开、如果分开了要创建这样的目录,还要生成include/config/kernel.release、include/linux/version.h include/linux/utsrelease.h 等文件。
以下代码都是摘自顶层MakefileLine 955:
PHONY &#43;= prepare archprepare prepare0 prepare1 prepare2 prepare3
# prepare3 is used to check if we are building in a separate output directory,
prepare3: include/config/kernel.release
# prepare2 creates a makefile if using a separate output directory
prepare2: prepare3 outputmakefile
prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \
archprepare: prepare1 scripts_basic
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
$(Q)$(MAKE) $(build)=. missing-syscalls
prepare: prepare0
  准备工作还包括scripts,这些脚本用来决定编译时的选项,例如include/config/auto.conf。
以下内容摘自顶层MakefileLine 384:
# Basic helpers built in scripts/
PHONY &#43;= scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
PHONY &#43;= scripts
scripts: scripts_basic include/config/auto.conf
③$(Q)$(MAKE) $(build)=$@
&  编译命令是至关重要的一句话,这句话就是来调用通用子Makefile文件--scripts/Makefile.build。$@会依次被vmlinux-dirs中的文件夹代替,从而依次执行命令&make -f scripts/Makefile.build obj=$@&
编译该目录中的文件以生成*.built-in.o、lib.a等文件。
  我们以$@为drivers为例进行以下内容的说明,下边这条命令最终的结果是生成drivers/built-in.o。
make -f scripts/Makefile.build obj=drivers
2 scripts/Makefile.build的第一次调用阶段 &
  转战到scripts/Makefile.build,obj=drivers被带到该文件,首先看一下这个文件都包含了哪些文件
1、Makefile.build的包含文件
以下内容皆来自于scripts/Makefile.build
-include include/config/auto.conf
include scripts/Kbuild.include
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
include scripts/Makefile.lib
# Do not include host rules unless needed
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
  包含文件有依据.config生成的配置文件include/config/auto.conf、include scripts/Kbuild.include、
$(kbuild-file)(也就是子目录的Makefile或者kbuild)、include scripts/Makefile.lib、include scripts/Makefile.host(只在一定情况下才被包含进入)。
  这里着重讲一下kbuild-file&#20540;的变化过程,kbuild-dir的等式中有filter函数,它的目的是将不是以“/”开头的目录滤除,显然我们的src=drivers,所以就被滤除掉,这个函数的&#20540;为空。
scripts/Makefile.build Line 5: src := $(obj)
  $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))的结果最终等于$(srctree)/$(src),也就是给src添加绝对路径。所以kbuild-dir&#20540;等于/workspace/linux-2.6.30.4/drivers。  kbuild-file右边的等式,首先查看在kbuild-dir目录中是否有Kbuild存在,如果有就等于这个文件,否则使用这个目录中的Makefile文件。kbuild-file最终等于/workspace/linux-2.6.30.4/drivers/Makefile。
2、scripts/Makefile.build的总目标
scripts/Makefile.build Line 7:
PHONY := __build
scripts/Makefile.build Line 93:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
&&1& KBUILD_BUILTIN
  在终端以#Make uImage执行Make时,KBUILD_BUILTIN := 1。
顶层Makefile Line 241:KBUILD_BUILTIN := 1
If we have only &make modules&, don't compile built-in objects.
When we're building modules with modversions, we need to consider
the built-in objects during the descend as well, in order to
make sure the checksums are up to date before we record them.
ifeq ($(MAKECMDGOALS),modules)
KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
顶层Makefile Line 264: export KBUILD_MODULES KBUILD_BUILTIN
&&2&&builtin-target
scripts/Makefile.build Line 85:&
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
  builtin-target&#20540;为drivers/built-in.o
&&3&&lib-target
scripts/Makefile.build Line 81:&
ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
lib-target := $(obj)/lib.a
  lib-target的&#20540;为drivers/lib.a
&4& $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))
  初步认识时定义编译的模块
&&5& subdir-ym
subdir-ym的定义
scripts/Makefile.lib Line 38:
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
&#43;= $(__subdir-y)
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
&#43;= $(__subdir-m)
scripts/Makefile.lib Line 47: subdir-ym := $(sort $(subdir-y) $(subdir-m))
scripts/Makefile.lib Line 89: subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
 __subdir-y和__subdir-m首先将obj-y、obj-m中的非文件夹滤除,然后通过patsubst函数将最后的“/”去除。注意到drivers/Makefile中的obj-y、obj-m通通都是文件夹。我们以obj-y = net/为例进行以下内容的说明,所以__subdir-y=net。
  subdir-ym就是在__subdir-y和__subdir-m前边添加obj的前缀,所以最终等于drivers/net。
3、drivers/built-in.o的生成
&  scripts/Makefile.build的总目标__build中的一个目标是&builtin-target,而它的&#20540;为drivers/built-in.o,现在就来看看它是怎样生成的。
scripts/Makefile.build Line 288:
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
&1&&drivers/built-in.o的依赖
  drivers/built-in.o依赖于obj-y(子目标),然后通过调用一个if_changed函数,将这些子目标连接起来,生成drivers/built-in.o。通过命令打印查看连接命令如下:
arm-linux-ld -EL
-r -o drivers/built-in.o drivers/gpio/built-in.o drivers/video/built-in.o
drivers/char/built-in.o drivers/gpu/built-in.o drivers/serial/built-in.o drivers/base/built-in.o
drivers/block/built-in.o drivers/misc/built-in.o drivers/mfd/built-in.o drivers/macintosh/built-in.o
drivers/scsi/built-in.o drivers/net/built-in.o drivers/ieee1394/built-in.o drivers/cdrom/built-in.o
drivers/auxdisplay/built-in.o drivers/mtd/built-in.o drivers/usb/built-in.o drivers/usb/gadget/built-in.o
drivers/input/built-in.o drivers/rtc/built-in.o drivers/i2c/built-in.o drivers/media/built-in.o
drivers/watchdog/built-in.o drivers/lguest/built-in.o drivers/idle/built-in.o drivers/mmc/built-in.o
drivers/firmware/built-in.o drivers/crypto/built-in.o drivers/hid/built-in.o drivers/platform/built-in.o
  看下边的代码,原来drivers/Makefile中的obj-y是一群目录,通过第一行代码后就给这些目录后边加上了built-in.o,再经过第二行代码,给它们冠以前缀。我们以obj-y=net/为例说明,经过第一行代码obj-y=net/built-in.o,经过第二行代码obj-y=drivers/net/built-in.o
scripts/Makefile.lib Line 42:obj-y
:= $(patsubst %/, %/built-in.o, $(obj-y))
scripts/Makefile.lib
Line 78: obj-y
:= $(addprefix $(obj)/,$(obj-y))
&2& if_changed函数
  通过if_changed函数,完成了把这些子目录中的目标连接生成dirvers/built-in.o。&
Kbuild.include Line 192:
if_changed = $(if $(strip $(any-prereq) $(arg-check)),
$(echo-cmd) $(cmd_$(1));
echo 'cmd_$@ := $(make-cmd)' & $(dot-target).cmd)
  既然是函数,就会传递参数。相对于C语言来说形参就是(1),而传递实参的方法就是(1),而传递实参的方法就是(call
if_changed,link_o_target),其中call是调用函数命令,if_changed是调用函数名,后边的link_o_target就是实参。
①$(if $(strip $(any-prereq) $(arg-check))any-prereq检查是否有依赖比目标新,或者依赖还没有创建;arg-check检查编译目标的命令相对上次是否发生变化。如果两者中只要有一个发生改变,if_changed的&#20540;就等于
$(echo-cmd) $(cmd_$(1));
echo 'cmd_$@ := $(make-cmd)' & $(dot-target).cmd
   否则,if_changed的&#20540;为空,也就是说$(call if_changed,link_o_target)将什么也不执行,因为没必要执行。
②set -e 是说下边的命令如果出错了就直接返回,不再继续执行
③echo-cmd
Kbuild.include Line 156:
echo-cmd = $(if $($(quiet)cmd_$(1)),\
$(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
  echo-cmd就是打印出调用的命令。if&(((quiet)cmd_(1))是判断命令(1))是判断命令(quiet)cmd_(1)或者cmd_(1)或者cmd_(1)是否定义,也就是quiet_cmd_link_o_target或者cmd_link_o_target是否定义。如果有定义,echo-cmd就会将这个命令打印出来,也就是打印。
④$(cmd_$(1))
  对于&$(call if_changed,link_o_target),该命令就是cmd_link_o_target。
scripst/Makefile.build Line 283:
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs $@)
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) ,这个就是连接命令。总结:  if_changed函数的核心功能就是判断是否需要更新目标,如果需要就执行表达式$(cmd_$(1))展开后的&#20540;来完成重建目标。
4、drivers/net/built-in.o
&  drivers/built-in.o的依赖如何生成呢,比如说drivers/net/built-in.o,还记得subdir-ym吗?subdir-ym记录了当前目录里边要参与编译连接的子文件夹。在 “2 scripts/Makefile.build阶段 &2、scripts/Makefile.build的总目标&&5&&$(subdir-ym)”中,我们假定subdir-ym=drivers/net。
Makefile.build Line 356:&PHONY &#43;= $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
  $(Q)$(MAKE) $(build)=$@就是再一次调用scripts/Makefile.build,并传递参数drivers/net,这和生成drivers/built-in.o没什么差别。&
3 scripts/Makefile.build的再一次调用阶段
  再次转战到scripts/Makefile.build,obj=drivers/net被带到该文件。
1、Makefile.build的包含文件
  其包含文件与第一次调用阶段没什么大的区别,最为重要的区别就是包含子目录Makefile的改变,这次包含的文件是/workspace/linux-2.6.30.4/drivers/net/Makefile。&
2、scripts/Makefile.build的总目标
  总目标中的builtin-target&#20540;为drivers/net/built-in.o
3、drivers/net/built-in.o的生成
scripts/Makefile.build Line 288:
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
  由于子目录的Makefile变成了/workspace/linux-2.6.30.4/drivers/net/Makefile,所以obj-y对应的发生了变化。通过执行编译查看这个连接过程。
arm-linux-ld -EL
-r -o drivers/net/built-in.o drivers/net/mii.o drivers/net/Space.o
drivers/net/loopback.o drivers/net/dm9000.o drivers/net/arm/built-in.o drivers/net/e1000/built-in.o
&1&&drivers/net/built-in.o的依赖
  从drivers/net/Makefile中摘出两个典型的obj-y组成部分如下所示:
drivers/net/Makefile Line 5:
obj-$(CONFIG_E1000) &#43;= e1000/
drivers/net/Makefile Line 230: obj-$(CONFIG_DM9000) &#43;= dm9000.o
  drivers/net/built-in.o的依赖包含了文件夹,并且包含了直接由C文件生成的目标文件.o。
scripts/Makefile.lib Line 42:
:= $(patsubst %/, %/built-in.o, $(obj-y))
scripts/Makefile.lib
:= $(addprefix $(obj)/,$(obj-y))
  第一行代码让obj-y如果是文件夹,就添加built-in.o,如果是普通的目标文件*.o,什么也不操作;第二行代码冠以目录obj。所以obj-y最终等于drivers/net/e1000/built-in.o、drivers/net/dm9000.o。
  我们越来越接近最终的目标了--分析到最底层的C文件生成目标文件。
&2& if_changed函数
  drivers/net/built-in.o也是一个由众多的文件组成的库文件,所以也是通过调用if_changed函数完成连接。
4、drivers/net/dm9000.o
scripts/Makefile.build Line 226:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
scripts/Makefile.build Line 263:
$(obj)/%.o: $(src)/%.S FORCE
$(call if_changed_dep,as_o_S)
$(obj)/%.o: $(src)/%.c FORCE是编译C程序,$(obj)/%.o: $(src)/%.S FORCE是编译汇编程序
&1&&drivers/net/dm9000.o的依赖
  drivers/net/dm9000.o的依赖是对应的$(src)/%.c,也就是drivers/net/dm9000.c。
&2&cmd函数
scripts/Kbuild Line 160:
cmd = @$(echo-cmd) $(cmd_$(1))
  此函数还未做深入分析。
&2&if_changed_rule函数
scripts/Kbuild Line 205:
# Usage: $(call if_changed_rule,foo)
# Will check if $(cmd_foo) or any of the prerequisites changed,
# and if so will execute $(rule_foo).
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),
$(rule_$(1)))
  $(call if_changed_rule,cc_o_c),从而会调用函数if_changed_rule,接着会执行命令$(rule_$(1))),也就是rule_cc_o_c。
scripts/Makefile.build Line 215:
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc)
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c);
$(cmd_modversions)
$(cmd_record_mcount)
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' &
$(dot-target).
rm -f $(depfile);
mv -f $(dot-target).tmp $(dot-target).cmd
  其中$(cmd_cc_o_c)命令的定义是
scripts/Makefile.build Line 179: cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $&
5、drivers/net/e1000/built-in.o的生成
  subdir-ym肯定包含有文件夹drivers/net/e1000,于是继续再一次调用scripts/Makefile.build来完成drivers/net/e1000/built-in.o的生成。&
Makefile.build Line 356:
PHONY &#43;= $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
&三、Linux内核整体编译过程
  经过解析过程的分析,编译过程就是解析过程的相反操作。
1、生成准备文件
①控制C程序的头文件
  include/linux/version.h include/linux/utsrelease.h、include/linux/autoconf.h
②控制编译连接的文件
  arch/arm/kernel/vmlinux.lds、include/config/auto.conf等文件。
2、 由C程序源码和汇编语言源码生成目标文件(*.o)
3、将目标文件连接成*.built-in.o、*/lib.a等文件
4、将紧接着顶层目录的子目录中的*.built-in.o以及部分重要的*.o文件连接生成vmlinux
5、根据arch/arm/Makefile的规则生成zImage、uImage等
四、Linux内核编译构成元素
1、Makefile的目标
&1& 总目标
  总目标实际上是在arch/arm/Makefile中定义了,比方说zImage、uImage,顶层Makefile紧接着定义了这些终极目标直接的依赖目标vmlinux。
&2& 各级子目标
  各级子目标是在scripts/Makefile.build中的__build中定义的,例如传递参数obj=drivers后的目标是drivers/built-in.o。
  这些目标的依赖其实又成为了新的目标,例如drivers/net/built-in.o、drivers/net/dm9000.o。
2、Makefile的依赖
&1& 总目标的依赖
  vmlinux-lds &vmlinux-init vmlinux-main vmlinux.o kallsyms.o
&2& 各级子目标的依赖
  各级子目标的依赖是由子目录中的Makefile(实际是scripts/Makefile.build的包含文件)和scripts/Makefile.lib共同完成确定的。
  子目录中的Makefile负责选材,而scripts/Makefile.lib负责加工。
3、Makefile的规则
&1& 总目标的连接规则
  总目标vmlinux的连接规则就是在顶层Makefile中定义的,至于zImage、uImage则是在arch/arm/Makefile中定义的。
&2&子目标的编译连接规则
  主要是在scripts/Makefile.build、scripts/Kbuild.include中定义的,其中scripts/Kbuild.include定义了许多诸如if_changed的函数。
4、Makefile的编译连接选项
  本文并没有讨论。
五、Linux内核Makefile特点
1、两个Makefile
 顶层Makefile文件负责将各个目录生成的*.built-in.o、lib.a等文件连接到一起生成vmlinux。而scripts/Makefile.build 包含子目录中的Makefile文件以及scripts/中的众多脚本来生成这些*.built-in.o、lib.a、*.o等文件。
  通过“make -f scripts/Makefile.build obj=”的方法完成了顶层Makefile到scripts/Makefile.build的调用生成*/built-in.o,以及scripts/Makefile.build的自调用生成更低一级子目录的*/built-in.o。
2、编译的目录始终是顶层目录
  “make -C”命令会先切换工作目录,然后执行该目录中的Makefile,u-boot就是采用这种方法。而linux则是利用“make -f”的方法,所以编译的目录始终是顶层目录。
3、通用规则
  Linux内核Makefile的通用子Makefile是scripts/Makefile.build,而通用的其他规则则是scripts中的其他文件。
参考资料:《深度探索Linux操作系统:系统构建和原理解析》
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:13620次
排名:千里之外
转载:151篇
(6)(6)(45)(16)(11)(32)(37)

我要回帖

更多关于 跟我一起写makefile 的文章

 

随机推荐