arm linux系统开发工具

2016-08-23 21:30:29 LG1259156776 阅读数 2230

Linux及Arm-Linux程序开发笔记(零基础入门篇) 

作者:一点一滴的Beer http://beer.cnblogs.com/

本文地址:http://www.cnblogs.com/beer/archive/2011/05/05/2037449.html

目录

一、Arm-Linux程序开发平台简要介绍... 3

1.1程序开发所需系统及开发语言... 3

1.2系统平台搭建方式... 4

二、Linux开发平台搭建... 5

2.1安装虚拟工作站... 5

2.2安装Linux虚拟机... 5

2.3虚拟机的一些基本配置... 7

2.3.1建立共享目录... 8

2.3.2调整桌面分辨率... 9

2.4安装软件... 11

三、Fedora-linux系统... 11

3.1控制终端的基本操作命令... 12

3.2编程工具简介... 12

3.2.1 Fedora-Eclipse CDT. 13

3.2.2 Qt库及Qt界面设计软件... 14

四、使用Eclipse CDT开发Linux程序... 15

4.1建立控制台程序... 15

4.2建立Linux窗口程序... 16

五、使用Eclipse开发Arm-linux程序... 19

5.1 Arm-linux硬件平台... 19

5.2开发控制台程序... 20

5.2.1使用Eclipse CDT编写代码... 20

5.2.2建立交叉编译环境... 20

5.2.3编译并运行程序... 22

5.3一些常用的软件介绍... 23

5.4开发arm-linux窗口程序... 24

5.4.1建立Qt交叉编译环境... 25

5.4.2编译生成可执行窗体程序... 26

六、高级Linux程序设计... 28

6.1多文件控制台项目... 29

6.2多文件Qt项目... 29

6.2.1使用Qt Designer设置界面... 29

6.2.2多文件Qt开发时的一些经典错误... 31

6.3关于makefile. 32

七、学习资料... 32

 

 

前言:本文记录了自己从一个完全不懂Linux的人如何一步步学会Linux程序开发的过程。当然也希望本文能够达到它的目的,让那些和我一样没有任何基础的人也能快速入门Linux程序开发。

一、Arm-Linux程序开发平台简要介绍

    Arm-Linux程序的开发并不像我们以前接触的Windows程序开发那样,关于平台的搭建就繁琐很多,所以在正式进入程序开发之前先对这种开发模式进行简要介绍,让一个即使没有任何Linux开发经验的程序员也能够看懂后面的内容。

1.1程序开发所需系统及开发语言

    开发arm-linux程序至少需要三种系统:

    Windows系统 
    主要用来文件传送和一些简单的文本文件编辑。这个系统其实并非必需,只是因为目前PC机上最流行的系统仍然是Windows系统,我们的很多关于PC的文件和数据的操作习惯都是在Windows系统上养成的,已经对其形成了严重的依赖,所以Windows系统扮演着的“辅助开发系统”的角色。

    PC-Linux系统。 
    在此系统上安装arm-Linux交叉编译器后,就可以对代码文本文件进行编译,生成可在arm-Linux系统中运行可执行程序。此系统被称为“Linux宿主机”,我们对Linux程序的开发工作(包括代码编写、调试和编译生成可执行文件)基本上就是在此系统上进行的。

    Arm-Linux系统。 
    Arm-Linux程序运行的平台。此系统的硬件载体是一块小型的嵌入式arm板,我们在Linux宿主机上开发好程序并编译生成arm-linux可执行程序后,将可执行程序文件传送到嵌入式arm板中,然后就可以在arm板上直接运行此程序了。

三种系统的职能和联系如下图:

image

“三系统”职能和关联图

  关于每个系统的职能及操作还有文件如何传送交流都在后面详细介绍。

  关于开发语言,因为目前购买的Arm-Linux嵌入式板提供的编译库都是C/C++的,所以一般选择C/C++进行程序设计。

1.2系统平台搭建方式

  关于“三系统”的搭建方式,有两种方法:三台分立的单系统机器组合或者一台双系统PC机和一台单系统Arm板机器。但是不管采用哪种组合方式,各种系统的职能都是一样的,而且都是通过FTP、Telnet或者SSH等网络协议进行文件传输交流。

  “三机器”组合模式。将三个系统分别安装在三台机器上并将三台机器组建局域网。

  “两机器”组合模式。在PC机上利用虚拟工作站可以同时运行两个系统,虚拟机上的Linux系统基本可以完成所有的实体PC-Linux机器的所有任务,当然也能够组建局域网。

clip_image004

“三机器”组合模式图

clip_image006

“两机器”组合模式图

  如果开发人员对机器性能要求比较高,那么建议采用“三机器”组合模式。因为“两机器”组合模式要求一台机器运行双系统,每个系统都需要分配一定的硬件资源,可能会对每个系统运行的流畅程序都造成影响。

  如果开发人员只进行一些简单的程序开发,则建议采用“两机器”组合模式。这样可以节省硬件设备的投资,而且开发环境的搭建、开发的流程等等都会简单一些。而且下面的内容都是基于这种“两机器”组合的开发模式。

二、Linux开发平台搭建

2.1安装虚拟工作站

  目前比较流行的虚拟工作站比较多,推荐使用VM-ware WorkStation。建立虚拟工作站的目的就是为了使一台机器同时运行多个不同类型的系统,方便开发人员进行跨平台开发应用程序。

  (关于VMware,可以到网上搜索到详细介绍和使用方法,在此不再赘述)

2.2安装Linux虚拟机

  安装虚拟机的过程和安装实体机一样,唯一的区别是,虚拟机安装是从VMware中打开并安装的。先准备Linux安装文件,一般可以到网上下载到Linux的iso安装文件,然后从VMware中安装此系统。

  (关于虚拟机安装,在网上可以搜索到详细的步骤,在此不再赘述)

  几点建议:

  1.安装Fedora-10并选择完全安装,即把所以的包和选项都勾上。这样在安装完毕后,系统就自带了很多开发工具和相关的库,避免自己去重新进行烦琐的基本开发平台搭建。

  2.在VMware中为虚拟系统配置硬件资源。建议分配硬盘空间16G,内存1G以上。因为今后主要的Linux程序开发工作是在虚拟机上进行了,所以为了保证虚拟机流畅运行,需要分配比较丰富的硬件资源。

  在第一次从ISO文件中安装完毕虚拟机后,在安装目录下面会生成一系列的文件,将这些文件进行备份后,在其它机器上安装虚拟机的时候就花几个小时去从ISO中安装了,将这个目录下的文件复制到相应的目录下面(在第一次从ISO中安装的时候设定的目录相同),然后只需要从VMware中打开此目录下的文件就行了。

执行VMware Workstation中的【View】--【Home】,调出Home视图,然后打开虚拟工作站系统文件。

clip_image008

  打开后,就可以看到一个虚拟机的硬件资源配置了。这些参数有一部分是在只能在初次使用iso安装的时候配置的,比如硬盘大小。另外一些参数比如内存大小、共享目录等等可以在后期随时人工更改的。

详细设置内容,到网上可以找到很多相关内容,在此不再赘述

clip_image010

  两种方法的区别就是WinXp的安装盘和Ghost盘的区别吧。

  安装完毕Fedora后,就可以从虚拟工作站中启动Fedora Linux系统了。系统桌面如下:

clip_image012

2.3虚拟机的一些基本配置

  在第一次安装完毕虚拟机后开启虚拟机,默认的分辨率是800*600,同时没有全能共享目录。为了获得比较好的操作界面,同时方便文件共享和转移,需要进行一些基本的配置。

2.3.1建立共享目录

  在同一个硬件PC机上运行的两个系统。Windows实体系统用来做一般的用途,比如联网,处理文档等等;Fedora Linux虚拟系统则用来开发Linux程序并进行编译生成可执行文件。

  先需要安装vmware tools

  在VMware上面,选择菜单【VM】--【Install VM tools】,然后在Linux虚拟机上会生成目录/media,同时里面产生一个rpm文件。

  然后打开控制终端并su登录超级用户:

cd /media

rpm –ivh VMwareTools-7.8.5-156735.i386.rpm

cd /usr/bin

然后在/usr/bin下面看到wmware-config-tools.pl

再在Teminal中输入wmware-config-tools.pl

    然后一路回车下去。然后今后就可以建立共享目录。

  (详细过程也可以在网上搜索相关内容

clip_image014

    共享目录的好处是可以将这些文件在Windows系统中提取出来,然后可以通过我们熟悉的windows系统进行网络传输和一些其它命令操作。这个设置在后面程序开发的时候会提到其使用方法。

    在VMware中建立共享目录,执行菜单命令【VM】--【Settings…】

clip_image016

  然后在Linux虚拟机文件系统中可以找到对应的共享目录:/mnt/hgfs/xplinux

clip_image018

  建立共享目录可以方便虚拟机和实体机进行文件交流。例如,我们可以将在Linux机器上编译生成好执行文件放置到共享目录中,然后可以通过Windows机器提取出来并通过网络传送到arm-linux嵌入式板上。

2.3.2调整桌面分辨率

    在VMware工作站中调整虚拟机桌面分辨率。一般默认是800*600,而且现在的显示器,一般是1024*768甚至更高,以我目前使用的电脑显示器为例,分辨率是1440*900。需要将虚拟机桌面分辨率进行适当调整,然后全屏,那么就可以获得比较友好的操作界面。

    在VMware中启动虚拟机,虚拟机启动后的登录界面如下:

clip_image020

 

 

    然后登录系统,设置分辨率,系统菜单:

    【System】--【Preferences】--【Hardware】--【Screen Resolution】

clip_image022

clip_image024

    设置好分辨率后,就可以在获得全屏状态的Linux操作界面了。

clip_image026

2.3.2其它设置

    比如设置桌面背景,系统字体,还有资源管理器的模式等等,这些可以自己去实地操作并进行熟悉。

2.4安装软件

    虽然Fedora已经自带了一些必要的软件,如Open Office办公软件,gedit记事本软件,Firefox网页浏览器等等。但是既然是操作系统,我们也可以安装一些我们需要的软件。比如中文输入法(如:小企鹅输入法),聊天工具(如QQ)等等。

    注意:在Terminal终端中安装程序的时候需要启用su超级用户权限。

三、Fedora-linux系统

    Fedora-linux虚拟机安装完毕并进行基本设置后,就可以开始了程序开发环节了。在正式开始程序开发时,还需要对Linux的一些基本编程工具进行简要介绍,当然如果已经有此基础的,可以直接略过这一章。

3.1控制终端的基本操作命令

    执行系统菜单命令【Applications】--【System Tools】--【Terminal】,打开Terminal终端:

clip_image028

    熟悉Windows系统的DOS操作界面的人肯定也会对此操作终端也不会陌生。通过在Terminal中输入命令,用户可以很方便地完成Linux下的一系列操作,在正式进入自主程序设计之前,用户有必要对下面一些最基本命令进行熟悉(其它的命令在项目需要的时候再到网上查找相关资料)。

文件操作命令

文件/文件夹的创建、修改、复制、删除、移动等等。(如rm/mv/vi/cat等等)

网络设置命令

个性IP、开启FTP、开启Telnet、开启SSH等等。(如ifconfig/telnetd等等)

用户管理命令

系统用户的添加、删除、密码修改等等。(如,addusr/passwd等等)

文件编译命令

这个涉及到编译环境的建立,将在后面正式进入到自主程序设计时进行详细介绍。

    虽然目前Fedora为用户提供了比较良好的操作界面,但是Linux最初是从命令行的操作系统发展起来的,很多强大的功能都是需要依靠Terminal控制终端来实现的,所以作为开发人员有必要先对这些基本命令进行熟悉并熟练操作。

3.2编程工具简介

    如果在安装Fedora的时候,选择的是完全安装,系统会自带很多开发工具。其中Fedora -Eclipse CDT和Qt库及相关设计器Qt Designer是我们今后开发的主要工具。

当然,如果用户没有选择安全安装,则可以到网上下载到各类开发工具的安装文件,并自己进行安装。

3.2.1 Fedora-Eclipse CDT

    在Fedora中执行系统菜单【Application】--【Programming】--【Eclipse】

clip_image030

    然后就可以看到Fedora Eclipse的启动画面

clip_image032

    然后就是下面就是Eclispe的IDE环境了,有过Windows下的Java编程经验的人来说,这个界面是再熟悉不过了,完全可以直接过渡到Linux下的C/C++程序开发上来,这样就极大地减少了程序员的学习周期。

clip_image034

    Eclipse的好处,第一就是开源,第二就是免费,第三就跨平台。

    因为开源,所以可扩展性很强,Eclipse实际上就是一个万能的程序开发环境,只需要在设置中对相关语言的库进行引用并连接相应的编译器,就可以对基于任何语言的程序进行开发;因为免费,所以省去了注册软件等等琐事。因为跨平台,所以当用户进行跨平台程序设计的时候,可以极大减少学习周期。

    Eclispe在Windows平台下一般都是作为Java的开发环境,用来开发Java桌面应用程序和Jsp网页应用程序甚至目前比较流行的Android手机终端软件。在Linux下面对C/C++的库编译器进行了连接后,则成为Linux下的C/C++开发环境,在Linux下安装JDK后则可以进行Linux下的Java程序设计,如果给Linux系统安装tomcat网页服务器,则可以进行Linux下的网页应用程序开发,如果给Linux安装mysql数据库服务,则可以进行数据库连接操作等等(因为目前我们的目标主要是arm-linux窗口程序开发,所以主要对C/C++进行研究)。

3.2.2 Qt库及Qt界面设计软件

    如果只是编写C/C++控制台软件,则只需要Eclipse CDT就完全可以解决。但是如果要进行窗体化编程,就需要引用一些开源的界面库。例如目前比较流行的Qt库。

    Qt是诺基亚开发的一个跨平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的,很容易扩展,并且允许真正地组件编程。基本上,Qt 同 X Window 上的 Motif,Openwin,GTK 等图形界 面库和 Windows 平台上的 MFC,OWL,VCL,ATL 是同类型的东西,但Qt具有优良的跨平台特性、面向对象 、丰富的API、大量的开发文档等优点。

    在Eclipse中对项目Build选项进行设置,对Qt库进行连接,然后就可以进行Linux下的Qt程序进行开发了。

    因为Eclipse没有提供可视化的窗体程序设计器,所以需要借助第三方工具,QtDesigner可以很好的解决Qt的UI设计问题并编译生成对应的*.h和*.cpp文件(具体的操作步骤将在下面的内容中详细介绍)。

clip_image036

    所谓“工欲善其事,必先利其器”,前面花了大量篇幅来介绍,都是为了“磨刀”,现在开始进入“砍柴”环节。下面将以Eclipse CDT作为开发环境来介绍Linux和arm-linux程序开发的一般方法。

四、使用Eclipse CDT开发Linux程序

4.1建立控制台程序

    用Eclipse CDT建立基于C++的“Hello World”控制台程序。

    打开Eclipse开发环境。执行【File】--【New】--【C++ Project】

clip_image038

    然后进入到C++ Project向导,有C++的Hello World模板

clip_image040

    点击Finish,然后Eclispe就会建立一个基于C++的HelloWorld项目,运行程序后,能够在控制台中输出“Hello World”:

clip_image042

    说明:如果是开发控制台程序,则不需要进行任何其它设计,只需要直接编写C++代码即可,不用对编译库和编译器进行设置,Eclipse已经为我们自动完成了这些内容。

4.2建立Linux窗口程序

    就像在Window环境下,如果要用C++开发窗口程序,我们一般需要使用Windows API或者MFC。同样,在Linux环境下,我们可能在C++项目中引用Qt库来进行Linux下的窗口程序开发。

    在完整版的Fedora中,自带了Qt的库,在目录/usr/lib下面:

clip_image044

    系统默认自带有两个版本的Qt库qt-3.3和qt4,一般我们用qt-3.3。

    编写窗口程序,我们只需要在建立了C++ Project的情况下,对C/C++ Build路径进行设置,指向qt-3.3的库即可。主要开发流程如下:

clip_image046

    第一步:使用Eclipse CDT建立C++ Project。

    第二步:设置Build路径指向Qt。在项目管理器中右击项目文件设置项目属性,在C/C++ Build的Settings的Tool Settings中进行设置。

clip_image048

    【GCC C++ Compiler】--【Directories】添加包含的文件路径:/usr/lib/qt-3.3/include。这个是C++的编译器包含的头文件路径,因为是建立的C++ Project,所以一定要设置。

clip_image050

    【GCC C Compiler】--【Directories】添加包含的文件路径:/usr/lib/qt-3.3/include。这个是设置C语言编译器包含的头文件路径,因为有时候C++中会考虑到兼容一些C语言的语法和关键字,所以最好也进行相关设置。

clip_image052

    【GCC C++ Linker】--【Libraries】添加编译时引用的库路径:/usr/lib/qt-3.3/lib(注意:不要写成include了)。并设置库搜索命令参数:qt-mt。

第三步:编写引用了Qt库的C++程序。

第四步:运行程序。

程序运行效果如下图:

clip_image054

    总结:通过上面对Linux下面的控制台程序及窗口程序的介绍,我们已经对Linux系统下的简单程序开发流程有了简单了解。下面开始介绍arm-Linux程序的开发。

五、使用Eclipse开发Arm-linux程序 

5.1 Arm-linux硬件平台 

clip_image056

    Arm-Linux机器采用的是飞凌嵌入式技术公司的FL2440开发板。在飞凌公司购买开发板的时候,会随开发板一起赠送的相关入门教程《飞凌开发板配套教程》并附有一张光盘,里面有各种写FL2440相关的开发资源。

    在正式进入程序开发之前,先对FL2440开发板及arm-linux系统进行熟悉。

    Fl2440开发板:熟悉Bootloader的使用方法、学会烧写内核、烧写文件系统等等。

    Arm-linux系统:熟悉利用一些文件系统和网络设置相关的命令。如果你对Linux命令已经有了一定了解,那么arm-linux上的命令也基本一样。

详细操作过程请参考《飞凌开发板配套教程》一书

5.2开发控制台程序

    主要开发流程图如下:

image

    在早期的开发环境方式中,是先用文本编辑器编写c或者cpp文件,然后再直接在Linux机器上通过交叉编译命令,编译代码文本文件并生成可执行程序,然后将可执行程序传送到arm-linux板上,然后就可以在arm-linux机器上运行程序了。

    现在的开发模式和早期的开发模式一样,只是在编写代码的工具上进行了改进。早期编写代码的工具只要是能编辑文本的软件就可以,甚至在Linux中通过终端的vi命令就可以搞定,Linux机器的职能仅仅是编写代码和编译代码。现在则使用Eclipse CDT,可以在Linux机器上编写C/C++代码并进行调试,Linux机器基本上可以模拟arm-linux系统上除了一些硬件相关度高的应用程序(如驱动程序)之外的绝大部分其它程序的运行环境。

5.2.1使用Eclipse CDT编写代码

    其实和用Eclipse CDT编写Linux环境下的控制台程序是完全一样。除了在一些特别的场合,比如编写驱动程序,需要注意差别外,其余的功能的实现方法基本上一样。

    这方面属于程序设计的基本功,需要长期学习和积累,所以在此不再多述。

5.2.2建立交叉编译环境

    虽然生成程序的源码是一样的,但是在Linux机器上编译生成的可执行文件是不能在arm-linux系统上运行的,需要用arm-linux专用的编译器进行编译后,才能生成可在arm-linux系统上运行的可执行文件,当然此时应用程序又显然不能在Linux系统上运行了。

    将交叉编译工具cross-2.95.3.tar.bz2(可以到网上下载,也可以到开发板附带的光盘资源中找到)通过共享目录传送到Linux系统中,然后在Linux系统终端中先进入其文件目录,然后执行解压命令:

tar xjvf cross-2.95.3.tar.bz2

    然后在/usr/local/arm文件目录下可以看到解压后的2.95.3的库了,或者如果你解压的是cross-3.4.1.tar.bz2的版本,那么将会在对应目录下生成3.4.1的目录。

clip_image060

    然后设置环境变量。因为Linux机器上存在不止一种编译器,为了避免环境变量冲突,最好新建一个账号,比如新建账号arm-linux-gcc,然后在对应的账号目录中找到.bash_profile文件,设置环境变量,编辑.bash_profile,在最后一行增加路径(vi打开文本文件,按i表示insert修改文本文件,然后Esc退出insert模式,再shift zz表示保存退出文件,详细的命令介绍可以到网上查阅相关资料):

export PATH=/usr/local/arm/2.95.3/bin:$PATH

clip_image062

    可以通过echo $PATH来查看环境变量是否设置成功:

clip_image064

5.2.3编译并运行程序

    在编辑好了代码文件并建立好了交叉编译环境后,就开始编译代码生成可执行程序,并移植到arm板上运行程序。

    在Linux系统的终端中通过输入arm-linux-gcc/arm-linux-g++来编译C/C++文件。例如,我们对前面编写的最简单的CppHelloWorld.cpp文件进行编译:

arm-linux-g++ CppHelloWorld.cpp –o CppHello

clip_image066

    然后在对应目录下会生成一个可在arm-linux系统上运行的应用程序CppHello。

    然后通过SSH服务和FTP服务,将可执行文件从Linux文件系统网络传送到arm-linux文件系统(在此用到了两个小软件SSH Secure和LeapFTP,在后面再对软件的功能进行一下简要介绍)。

clip_image068

    然后在Windows机器上远程登录arm-linux系统开发板,并控制程序运行

clip_image070

    注意:需要先通过chmod +x CppHello来告诉系统此文件是可执行文件,然后再通过./CppHello来运行程序。

    我们可以看到程序运行的结果:在屏幕上打印出一行字“Hello World”

5.3一些常用的软件介绍

    在上面介绍的一些操作中,在进行文件传送的时候用到了一些软件,在此进行简要介绍。

LeapFtp

一个基于Ftp协议的文件互传软件。一般情况下,我们对arm-linux机器上开启Ftp服务,然后就可以实现Windows机器和arm-linux机器之间文件互传。

SSH Secure File Transfer Client

一个基于SSH协议的文件互传软件,可以实现FTP的功能。虽然Linux机器和Windows机器之间可以通过共享目录进行文件交互,但是因为共享目录实际上相当于Linux机器的一个虚拟的外接设备,在每次编写代码保存后,系统都会重读一次,给操作上造成一点小麻烦,所以建议使用SSH进行文件传送。

SSH Secure Shell Client

一个基于SSH的远程登录软件,可以实现telnet功能。因为Fedora默认关闭了telnet功能,而采用更安全的SSH协议来实现telnet的相关功能。

    三系统之间的主要网络架构如下:

image

    注意:

    1.如果arm-linux系统的ftp和telnet连接不上,一般情况下是arm-linux默认没有开启相应的服务或者默认ip和windows机器不在同一网段。可以通过串口线将arm板连接到电脑上,然后打开超级终端,输入命令vsftpd&开启ftp服务,输入命令telnetd开启telnet服务,ifconfig eth0 192.168.1.16设置IP到同一网段。

    2.如果Linux系统的SSH连接不上,则一般情况下是Linux系统开启了SSH的防火墙,则只需要在Linux系统中对防火墙进行相关设置,关闭针对SSH的防火墙。【System】--【Administration】--【Firewall】,然后勾选全能SSH。

clip_image074

clip_image076

    还有一些其它软件,比如小组协作时候,需要使用SVN进行代码管理;还有远程桌面VNC Viewer,可以进行远程桌面控制(但是效果不太好,桌面显示的延时好像比较严重)等等。

5.4开发arm-linux窗口程序

5.4.1建立Qt交叉编译环境

    在Linux系统中新建目录/root/yizhi,然后将已经编译好的arm-QT库复制到此目录下面。

clip_image078

    然后将上面那六个tar.gz压缩文件解压到/root/yizhi目录。

clip_image080

    在进行arm-linux下的Qt编译的时候,也涉及到环境变量设置问题,所以我们也最好再新建一个账户,专门用于编译arm-Qt程序。

    例如,在Linux系统终端中添加用户zsm,然后进入到/home/zsm中,对.bash_profile进行修改,设置环境变量:

clip_image082

    在命令终端中ls –a 显示隐藏的所有文件 找到.bash_profile,输入:

gedit .bash_profile &

    用geidt打开此文件后,在最后面添加下面的环境变量设置:

export PATH=/root/yizhi/qtopia-free-2.2.0/qtopia/bin:/root/yizhi/qtopia-free-2.2.0/tmake/bin:/root/yizhi/qtopia-free-2.2.0/qt2/bin:/usr/local/arm/2.95.3/bin:$PATH

export QTDIR=/root/yizhi/qtopia-free-2.2.0/qt2

export QTEDIR=/root/yizhi/qtopia-free-2.2.0/qtopia/

export LD_LIBRARY_PATH=$QTDIR/lib:$QPEDIR/lib:$LD_LIBRARY_PATH

export CC=/usr/local/arm/2.95.3/bin/arm-linux-gcc

export TMAKEDIR=/root/yizhi/qtopia-free-2.2.0/tmake

export TMAKEPATH=$TMAKEDIR/lib/qws/linux-arm-g++

    设置好后最好重新登录此账号,然后在终端中输入echo $PATH来检验环境变量是否设置成功:

clip_image084

    如果出现上面的输出,则表示arm-linux平台下的Qt交叉编译环境的环境变量已经设置成功。接下来就可以进行Qt程序开发了。

5.4.2编译生成可执行窗体程序

    在3.2节中已经写好了一个单文件的项目QtHello,并在项目的src目录下生成了一个QtHello.cpp文件,然后我们要做的就是利用arm-linux下的Qt编译器对其进行编译。

    编译Qt窗体项目比编译普通控制台项目要稍微麻烦一点,需要自己写makefile来建立编译规则,编译如上的QtHello.cpp的makefile有如下模板:

#############################################################################

# Makefile for building hello

# Generated by tmake at 20:58, 2011/04/14

# Project: hello

# Template: app

#############################################################################

####### Compiler, tools and options

CC = arm-linux-gcc

CXX = arm-linux-g++

CFLAGS = -pipe -Wall -W -O2 -DNO_DEBUG

CXXFLAGS= -pipe -DQWS -fno-exceptions -fno-rtti -Wall -W -O2 -DNO_DEBUG

INCPATH = -I. -I$(QTDIR)/include

LINK = arm-linux-gcc

LFLAGS =

LIBS = $(SUBLIBS) -L$(QTDIR)/lib -lm -lqte

MOC = $(QTDIR)/bin/moc

UIC = $(QTDIR)/bin/uic

TAR = tar -cf

GZIP = gzip -9f

####### Files

TARGET = QtHello

HEADERS = $(TARGET).h

SOURCES = $(TARGET).cpp

OBJECTS = $(TARGET).o

DIST =

INTERFACE_DECL_PATH = .

####### Implicit rules

.SUFFIXES: .cpp .cxx .cc .C .c

.cpp.o:

$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cxx.o:

$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cc.o:

$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.C.o:

$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.c.o:

$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<

####### Build rules

all: $(TARGET)

$(TARGET): $(OBJECTS)

$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)

dist:

$(TAR) hello.tar hello.pro $(SOURCES) $(HEADERS) $(INTERFACES) $(DIST)

$(GZIP) hello.tar

clean:

-rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) $(TARGET)

-rm -f *~ core

####### Sub-libraries

###### Combined headers

####### Compile

$(TARGET).o: $(TARGET).cpp

    用zsm账号登录(因为关于arm-Qt库的编译环境变量是在此账号中设置的),然后执行如下步骤:

1.将makefile模板文件放置到src目录下面

2.用eclipse或者其它文本编辑器,修改makefile里面的TARGET一项为当前项目名称

3.打开Teminal控制终端,进入到src目录,输入make

clip_image086

4.然后会在src目录下面生成一个指定名称相应的QtHello文件,这个就是arm目标板上的运行程序了。

5.将QtHello文件传送到arm板并运行程序(详细操作方法在4.2.3节中有介绍)。

clip_image088

    在Windows机器上远程登录arm板,控制程序运行,然后可以看到arm板上运行的结果了。

六、高级Linux程序设计

    前面所介绍的不管是控制台还是窗体程序,都属于单文件项目的范围。而当程序的功能比较复杂时,则往往需要很多模块和文件,这样在向arm-linux上移植程序时会更加繁琐一些,需要开发人员自己写makefile,建立多文件的编译规则。

    因为我对此没有进入深入一点的研究,所以只能提供下大致思路和在开发程序时遇到的一些常见问题及解决方案。如果今后有机会有时间的话,则会对makefile进行深入一点的研究,最好是能以Eclipse自己生成的makefile模板为基础进行简单的修改,然后就可以编译生成arm板上的可执行程序。

6.1多文件控制台项目

    多文件的控制台程序的makefile可能会容易一些,自己也没有研究过,以前在使用Magic C++编写C++控制台程序的时候,只需要对Magic C++生成的makefile模块中的编译器进行修改就可以轻松为多文件生成基于arm-linux平台上的控制台程序。

clip_image090

    (关于如何对Eclipse的makefile模板进行修改,目前还没有研究过,今后有时间研究的话,再补充上吧。)

6.2多文件Qt项目

    目前只对简单的多文件项目进行了尝试:一个main函数文件,一个窗体头文件,一个窗体实现文件。

6.2.1使用Qt Designer设置界面

    在Linux系统中打开Qt Designer,然后进行可视化窗口设计。然后点击保存为mydialog.ui文件。

clip_image092

    打开mydialog.ui文件,发现其实只是一个xml文件:

clip_image094

    显然这个文件是不能直接被C++项目引用的,需要使用Qt Designer的编译器进行编译,生成和界面对应的h和cpp文件。

    在Terminal终端里面运行以下命令:

uic xxx.ui -o xxx.h 生成.h文件

uic xxx.ui -i xxx.h -o xxx.cpp 生成.cpp文件

clip_image096

    然后生成的mydialog.h和mydialog.cpp文件就是和mydialog.ui相对应的程序代码文件了。可以在Eclipse项目中直接对此文件进行引用,就可以显示对应的窗体了。

6.2.2多文件Qt开发时的一些经典错误

    经典错误一: 

“undefined reference to ……”

clip_image098

    这是在引用Qt的库时,产生了某些歧义,需要进行一些预先处理,生成和界面文件相对应的moc文件,关于问题的详细介绍可以参考下面的帖子:

http://hi.baidu.com/asky007/blog/item/7aad95ccbee5ba1601e928d7.html

   解决方案:

    在Linux控制终端中进入到项目代码文件目录,执行

qmake –project

qmake

make

    然后此目录下会生成一系列的文件,如moc_xx.cpp,moc_xx.o,src,src_pro等等。然后再到Eclipse中编译此项目,则错误消失。

    经典错误二:

    在Linux机器上能运行的Qt窗口程序,在arm-linux下的Qt编译器下无法通过。

    可能的问题是Qt库版本问题,或者是有些Qt运行环境在Linux机和arm-linux机上有所不同,这就需要重新寻找新的代替解决方案。正是因为这些很多不确定的因素,所以在进行arm-linux界面程序开发时,需要经常在编写一段新代码就要在arm板上进行测试,可以避免做太多无用功。

6.3关于makefile

    关于多文件Qt项目向arm-linux系统上的移植,比较核心的技术应该就在makefile上吧,目前自己了解太少,只限于对模板的应用,所以下面的就写不下去了。

    下面有一篇到网上找到的关于makefile结构分析的帖子,今后有机会再研究吧。

http://blog.csdn.net/liang13664759/archive/2007/09/04/1771246.aspx

七、学习资料

    关于Linux下的Qt开发,在安装了的Fedora里面有相关的本地reference和相关的源码。如:Qt Assistant

clip_image100

    关于arm-linux下的Qt开发,安装交叉编译环境时候,也有相关文档和源码:

clip_image102

//**************************************************************************

结语:OK,写到这里了。在上个学期就花过一段时间学习Linux,然后中断了半年,这个学期又进行了深入的学习,把以前的内容和现在的内容串接起来了,终于有了比较清晰一点的思路和体会了,所以总结一下,也让将来的自己再回头学习时有一点借鉴吧。感谢胡师兄的一点一滴的指导。

2011-5-5

于武汉大学

------------------------------------------------------------------

Author:一点一滴的Beer

Email /Gtalk:dreamzsm@gmail.com

From:http://www.cnblogs.com/beer

Notes:欢迎转贴,但请在页面中加个链接注明出处

original:http://www.cnblogs.com/beer/archive/2011/05/05/2037449.html

2018-05-09 16:17:26 feifansong 阅读数 5382

这是因为工作写的一个文档,主要是我们开发人员都不会Linux不会vi也不会命令行,于是研究了一下Windows系统调试ARM Linux程序的办法,在这共享一下。

1. 概述

嵌入式Linux系统的应用程序开发,编译器一般是gcc,一般都说是要在Linux虚拟机中进行开发和编译。本文提供了一种能够在Windows系统下编译、调试Linux应用程序的方法,可大大简化Linux软件开发环境的搭建难度,保留原开发人员的操作习惯,让Linux程序开发和开发VxWorks一样方便快捷。

2. 软件包

2.1. IDE环境:EclipseIDE for C/C++ Developers

地址:

Eclipse IDE for C/C++ Developers

Eclipse下载后,无需安装配置,直接解压到program files目录即可运行,可放快捷方式到桌面。

2.2. 交叉编译工具:Linaro GCC

地址:

Linaro Releases

编译器版本选择,建议与CPU官方开发包提供的版本一致或接近,不必要追求最新版本。Windows下的编译器,命名一般为:gcc-linaro-4.9.4-2017.01-i686-mingw32_arm-linux-gnueabihf.tar.xz。带有mingw32字样的,就是Windows版的。

安装方法:

将下载的包用7zip解压到D:\gcc(winRAR似乎有问题,待确认),目录结构如下:

其中主要的几个目录位置如下:

bin/ 交叉编译工具目录

arm-linux-gnueabihf/libc/usr/include Linux user-space程序头文件目录

添加环境变量:

解压文件后,将D:\gcc\bin目录,添加到系统PATH环境变量中(系统属性-高级属性-环境变量),确保在任何位置调用arm-linux-gnueabihf-gcc均能成功。

2.3. Cygwin环境

地址:Cygwin Installation

根据安装向导进行在线安装,随本文档提供离线安装包

注意:

1、 源选择国内的某个edu.cn源,或网上寻找合适的国内源(如163mirror)

2、 软件包选择一定要包含“man”包,其他开发包根据需要可以以后追加

安装完成后,就可以在Windows环境使用Linux命令了

2.4. Linux API man库

地址:Index of /pub/linux/docs/man-pages

需要下载两个包:

man-pages

man-pages-posix

均可选择最新版本下载

下载后解压,将其中的man1~man7,man1p~man7p目录,复制到Cygwin安装目录下Cygwin_base/usr/share/man,如果重名则选择覆盖。

完成后,打开Cygwin终端测试:

man aio

manpthread_mutex_lock

如果能正确打开对应的帮助文档,说明安装完成。

以后开发中,可以随时通过man程序查看函数手册。

3. 目标板准备

目标板应能正常运行Linux系统,与开发机网络连通。在此基础上,确保以下功能被配置正确。本章节的准备工作,一般可由内核或rootfs维护人员处理,应用程序开发工程师一般不需要处理。

3.1. 开启SSH服务器

确保系统打开了SSH服务,一般在嵌入式Linux下,由dropbear提供该功能。

通过以下命令确认是否开启:

ps | grep dropbear

如果没有开启,需要找内核和rootfs维护人员处理。

3.2. GDB Server

远程调试依赖GDB Server功能,需要确保目标板上的GDB Server版本与开发环境中的一致,可复制位于GCC环境下的gdbserver到目标板。Windows下的gdbserver位于如下路径:

D:\gcc\bin\gdbserver

3.3. 调试临时目录

程序开发调试时,会反复地把编译好的应用程序复制到目标板的文件系统中。当目标板中Linux系统完全运行在Flash并无NFS文件系统时,下载文件的速度可能较慢,反复下载也可能导致Flash寿命提前结束。

为了提高调试效率,保证寿命,我们可以在目标板上申请一块tmpfs内存目录,调试程序都可以在该目录下进行。

这里我们约定基于tmpfs的调试目录为/run/app,后续文档中说明的应用程序调试目录均在此。

335x系统中,可修改/etc/default/volatiles/00_core,增加下面一行后自动创建app目录:

d root root 1777 /run/app none

4. 应用程序开发

4.1. Eclipse配置

Window-Preference

搜索path

在C/C++的Source Lookup Path中,添加一个File System Dir.,路径指向

D:\gcc\arm-linux-gnueabihf\libc\usr\include

并包含其子目录


4.2. 创建连接

File – New –Other

Remote SystemExplorer – Connection

创建一个连接:

连接类型为Linux:


输入HostName和IP地址:


下一步后,选择文件传输方式为SSH方式:

下一步,选择进程控制方式为通过系统shell控制

图略,同上

下一步,选择ssh.shells

图略,同上

下一步,选择ssh.terminals:

图略,同上

点击Finish完成。

测试

Window – View中打开Remote Systems窗口


右键Connect,当提示输入密码时,输入目标板用户名、密码(通常为root,密码空)

如果一切正常,可以展开SftpFiles查看目标板上的文件,右键SSH Terminals可以启动一个ssh终端。


4.3. 创建工程

新建一个工程,选择CProject

输入工程名,工程类型选择Executable—EmptyProject –Cross GCC

Cross GCC设置中,输入gcc前缀和gcc路径:

创建工程后,选择工程属性

C/C++ Build中,Builder选择内建builder:InternalBuilder

完成配置后,编译程序,应能成功:


4.4. 程序调试

打开DebugConfigurations


在C/C++ RemoteApplication下新建一个config.


在右侧配置页Main中

选择Connection为之前创建的Linux目标板连接LINUX_PMC-1308V2
远程运行程序路径,选择3.3调试临时目录中指定的调试目录,并在后面追加调试程序名:/run/app/appdemo

在Debugger选项卡中,指定gdb程序名为arm-linux-gnueabihf-gdb

配置完成后,即可点击对话框右下角Debug按钮启动调试。

剩下的工作,和Windows系统其他基于Eclipse的嵌入式开发环境下调试单片机程序、VxWorks程序没什么区别了。

2019-06-14 20:04:39 qq_41035588 阅读数 3763

嵌入式知识点复习一

1、 嵌入式系统的一般组成结构

在这里插入图片描述

2、嵌入式硬件系统的结构
(1)嵌入式处理器+外围硬件
(2)常见的外围硬件:电源、时钟、内存、I/O、通信、调试;
3、嵌入式处理器
(1)ARM、S3C6410、STM32单片机、华为海思、高通骁龙等
(2)Intel /AMD 都不是嵌入式处理器
4、嵌入式操作系统
功能:
种类:嵌入式linux;WinCE;Vxworks;μC/OS-II;Android;IOS。注意:linux不是嵌入式操作系统;MAC OS WINDOWS XP/7/8/10都不是

嵌入式知识点复习二 --体系结构

1、ARM:ADVANCED RISC MACHINES,是一款嵌入式微控制器,也是一家嵌入式处理器设计厂商。设计高性能、低功耗的嵌入式处理器。
2、ARM微处理器工作状态:两种指令对应两种状态(通常情况)
(1)Thumb状态、ARM状态;
(2)32位定长ARM指令,16位定长Thumb指令。
(3)ARM1176支持ARM指令、Thumb指令、Jazelle指令,故有三种状态:ARM状态、Thumb状态、Jazelle状态。
3、异常:
(1)处理器执行某些区别于用户指令的任务,如中断处理、复位、调试等;为了区分用户指令,因此称为异常;
(2)异常的种类与类型(1176为例):7种,中断(IRQ)、快中断(FIQ)、未定义(Undef)、数据中止(DABT)、预取指中止(PABT)、软中断、复位(reset)
4、工作模式:根据系统执行正常或异常指令不同,分为8种工作模式:用户模式、系统模式、中断模式、快中断模式、未定义模式、中止模式(对应数据中止异常、预取指中止)、SVC管理模式(软中断、复位)、SM安全监视器模式。
5、寄存器:
(1)ARM处理器均为32位寄存器;
(2)ARM1176寄存器数量:40个
(3)ARM1176寄存器包括:未分组寄存器、分组寄存器、CPSR、SPSR;
(4)未分组寄存器(所有模式通用):9个,R0~R7;R15(PC)
(5)分组寄存器(不同工作模式下专用,不同模式稍有不同):
① R8~R14;
② 6个不同模式下的SPSR寄存器:SPSR_irq,SPSR_fiq,SPSR_abt,
SPSR_und,SPSR_svc,SPSR_mon
(6)可复用寄存器:
① SP堆栈指针寄存器-R13,用于保存子程序调用或异常处理的临时数据;
② LR连接寄存器-R14,用于保存子程序调用或异常处理时,主程序调用指令/中断跳转指令的下一条指令的入口地址,以便于恢复主程序;
③ PC程序计数器-P15,用于保存要执行的指令的地址。
(7)PSR程序状态寄存器:
① 包括CPSR当前程序状态寄存器和SPSR备份的程序状态寄存器;
② CPSP用于保存当前模式下处理器模式、状态、中断使能、大小端模式及条件位等信息;
③ SPSR用于备份异常发生前的CPSR寄存器的值,以便异常处理结束时能返回用户程序状态。
6、ARM支持两种中断:IRQ和FIQ
7、ARM数据存储格式:大端(big endian)和小端(little endian)
8、采用RISC架构的ARM微处理器一般具有如下特点:
 
① 体积小、低功耗、低成本、高性能;
② 支持Thumb(16位)/ARM(32位)双指令集,能很好地兼容8位/16位器件;
③ 大量使用寄存器,指令执行速度更快;
④ 大多数数据操作都在寄存器中完成;
⑤ 寻址方式灵活简单,执行效率高;
⑥ 指令长度固定;
⑦ 指令支持按 条件执行;
⑧ 内存访问采用load/store实现。

嵌入式知识点复习三 --ARM-LINUX嵌入式开发环境

一、交叉开发模式
1、组成结构
(1)宿主机:开发主机,一般由PC、发行版linux系统、开发工具(本地及交叉编译)(代码编辑器Vi,编译器GCC、调试器GDB、工程管理器MAKE、NFS等)组成;
(2)目标机:嵌入式系统,一般由ARM硬件、BOOTLOADER、内核、根文件系统构成;
(3)连接工具:串口线、网线、USB线等。
2、理解编译工具链与交叉编译工具链的异同
(1)相同点:
① 用于支持的语言的编译、链接与调试,编译器用法相同;
② 通常都有编译器、链接器、调试器、库及其他二进制工具构成。
(2)不同点:
① 编译工具链一般用于本机编译、本机执行的开发模式;
② 交叉编译工具链用于宿主机编译,目标机运行的交叉开发模式;
③ 编译器一般Linux发行版都配备,直接调用gcc命令即可;
④ 交叉编译器一般需根据宿主机软硬件环境,进行gcc、相关库、工具进行有针对性的定制。
⑤ 实验室使用的OK6410开发板定制的编译器为32位的,其交叉编译工具链主要arm-linux-gcc,arm-linux-g++arm-linux-gdb等构成。
二、开发工具的用法
1、Vi的工作模式及其切换-掌握使用Vi完成源代码编辑、保存及退出的常见按键操作;
2、GCC:GNU Compiler Collection,GUN编译器套件,特点:
① 支持绝大多数高级语言的编译,既支持传统的C/C++,Fortan,Objective-C ,也支持java,python,go等语言;
② 支持汇编语言;
③ 支持绝大多数的主流处理器平台;
④ 便于构建交叉编译工具链。
3、gcc/arm-linux-gcc用法:
① 基本用法:gcc hello.c;arm-linux-gcc hello.c;输出a.out
② 推荐用法:gcc hello.c -o hello/arm-linux-gcc hello.c -o hello ,可以指定输出文件名称;
③ 主要的编译参数
-Wall 打印全部警告信息;
-O{0-3,s} 支持代码优化,0无优化;
-g 支持gdb调试;
-lpthread 支持多线程。

4、make及Makefile
(1)make:工程管理器,利用执行Makefile文件实现工程管理(编译、链接、生成工程镜像、安装、清理、卸载等);
(2)make用法:编写Makefile,在终端下执行make命令即可。
(3)Makefile文件编写示例:
一个工程,2个源文件testa.c ,testb.c,一个头文件testb.h,编译器为arm-linux-gcc,生成的可执行文件为test,需支持代码优化、打印警告信息,支持gdb调试等编译选项,其Makefile文件如下:
SRC=testa.testb b.c testb.h
EXEC=test
CC=arm-linux-gcc
CFLAGS=-Wall -O2 -g
(EXEC):(EXEC):(SRC)
$(CC) $(SRC) -o $(EXEC) $(CFLAGS)

嵌入式知识点复习四 --arm-linux文件编程

1、linux文件编程概述
(1)文件描述符:Linux中文件分为4种:普通文件、目录文件、链接文件、设备文件要区分这些文件就要了解“文件描述符”;
文件描述符是一个非负的整数,他是一个索引值,并指向内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符,当需要读/写文件时,也需要把文件描述符作为参数传递给相应的函数。
(2)基本I/O操作
Linux的输入/输出(I/O)操作,通常为5个方面:打开,读取,写入,和关闭
对应的有5个系统调用:
open,read,write,close,lseek
所需要的头文件:
#include <sys/types.h>
#include <unistd.h>
1.open函数
open函数的原型如下:
int open(const char *pathname, int flags, mode_t mode)
函数传入参数含义如下:
pathname:为字符串,表示被打开的文件名称,可以包含路径。
flags :为一个或多个标志,表示文件的打开方式,常用标志如表所示:
O_RDONLY 只读方式打开
O_WRONLY 只写方式打开
O_RDWR  读/写方式打开
O_CREAT 如果文件不存在,就创建新的文件
O_EXCL 如果使用O_CREAT时文件存在,则可返回错误消息
O_TRUNC  如果文件已存在,且以只读或只写成功打开,则先全部删除文件中原有的数据
O_APPEND  以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾、
注意:在open函数中,flags参数可以用过“|”组合而成,O_RDONLY,O_WRONLY,O_RDWR这三种方式是互斥的,不可同时使用,因此这3个参数只能出现一个。

mode 被打开文件的存取权限模式,可以使用八进制数来表示新文件的权限,也可以采用<sys/stat.h>中定义的符号常量,当打开已有文件时,将忽略这个参数,函数返回值:成功则返回文件描述符,出错返回-1。

文件模式符号常量:
S_IRWXU   00700    所属用户读。写和执行权限
S_IRUSR   00400   所属用户读权限
S_IWUSR   00200   所属用户写权限
S_IXUSR   00100   所属用户执行权限

S_IRWXG  00070   组用户读,写和执行权限
S_IRGRP   00040   组用户读权限 
S_IWGRP   00020  组用户写权限
S_IXGRP   00010  组用户执行权限

S_IRWXO  00007  其他用户读,写和执行权限
S_IROTH  00004  其他用户读权限
S_IWOTH  00002  其他用户写权限
S_IXOTH  00001  其他用户执行权限
2.read和write函数
函数原型如下:
ssize_t read(int fd, void *buf,size_t count)
ssize_t write(int fd,const void *buf, size_t count)
函数传入参数含义如下:
fd 文件描述符
buf 指定存储器独处数据的缓冲区
count 指定读出或写入的字节数
3.close函数
当使用完文件时可以使用close关闭文件,close会让缓冲区中的数据写回磁盘,并释放文件所占的资源,close的原型如下:
int close(int fd)
函数传入参数:fd文件描述符
函数返回值:若文件顺利关闭则返回0,发生错误则返回-1,并置errno,通常文件在关闭时出错是不常见的,但也不是不可能的情况,他别是在关闭通过网络访问的文件时就会出现这种情况。
4.lseek函数
主要用于移动文件读写指针,主要用于获取文件大小和拓展文件(先分配空间、然后再填充内容),函数原型如下:
off_t lseek(int fd, off_t offset, int whence)
参数 fd:文件描述符。
offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)
whence
(当前位置基点): SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小。
SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量。
SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小。
返回值 成功:文件的当前位移
-1:出错

实例:(1)参考实验2:linux文件编程;
(2)网盘:/linux编程源代码/IO(readwrite、fcntl)下相关代码

嵌入式知识点复习五 --arm-linux进程编程

一、Linux进程编程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配和调度的基本单位,是操作系统结构的基础。
1 进程控制
子进程创建:fork()函数
在Linux中创建一个新进程的唯一方法是使用fork()函数。fork()函数是Linux中一个非常重要的函数,和以往遇到的函数有一些区别,因为fork()函数看起来执行一次却返回两个值。
1)fork()函数说明
fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。
使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文、代码段、进程堆栈、内存信息、打开的文件描述符、符号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。
因为子进程几乎是父进程的完全复制,所以父子两进程会运行同一个程序。这就需要用一种方式来区分它们,并使它们照此运行,否则,这两个进程不可能做不同的事。
实际上是在父进程中执行fork()函数时,父进程会复制一个子进程,而且父子进程的代码从fork()函数的返回开始分别在两个地址空间中同时运行,从而使两个进程分别获得所属fork()函数的返回值,其中在父进程中的返回值是子进程的进程号,而在子进程中返回0。因此,可以通过返回值来判断该进程的父进程还是子进程。
2)fork()函数语法
在这里插入图片描述
进程等待函数
1)wait()函数,无条件等待,父进程阻塞直到子进程结束
在这里插入图片描述
2)waitpid()函数,指定等待某个子进程结束以及等待的方式(阻塞或非阻塞)
所需头文件 #include <sys/types.h>
#include <sys/wait.h>
函数原型 pid_t waitpid(pid_t pid, int *status, int options)
函数参数 pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1:等待任何一个子进程退出,此时和wait作用一样。
pid=0:等待其组ID等于调用进程的组ID的任一子进程。
pid<-1:等待其组ID等于pid的绝对值的任一子进程。
status 同wait
options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
0:同wait,阻塞父进程,等待子进程退出。
函数返回值 正常:结束的子进程的进程号
使用选项WNOHANG且没有子进程结束时:0
调用出错:-1
所需头文件 #include <sys/types.h>
#include <sys/wait.h>

函数原型 pid_t waitpid(pid_t pid, int *status, int options)
函数参数 pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1:等待任何一个子进程退出,此时和wait作用一样。
pid=0:等待其组ID等于调用进程的组ID的任一子进程。
pid<-1:等待其组ID等于pid的绝对值的任一子进程。
status 同wait
options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
0:同wait,阻塞父进程,等待子进程退出。
函数返回值 正常:结束的子进程的进程号
使用选项WNOHANG且没有子进程结束时:0
调用出错:-1

进程结束:exit()和_exit()

所需头文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函数原型 exit:void exit(int status);
_exit:void _exit(int status);
函数传入值 status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束。
在实际编程时,可以用wait系统调用接收子进程的返回值,进行相应的
处理。

所需头文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函数原型 exit:void exit(int status);
_exit:void _exit(int status);
函数传入值 status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束。
在实际编程时,可以用wait系统调用接收子进程的返回值,进行相应的
处理。

两者的区别:
(1)_exit()函数的作用最为简单:直接使进程终止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
(2)exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。
(3)exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。
Linux下的进程间通信
进程间通信用于实现参数传递及通信功能;Linux支持的常用的进程间通信方法:管道、消息队列、共享内存、信号量、套接口等等。
实例:(1)实验三:Linux进程编程;
(2)网盘linux编程源代码目录下fork文件下相关实例(FIFO、msgque、shm)。

嵌入式知识点复习六 --arm-linux网络编程

1、程序流程
(1)网络通信程序架构-客户端/服务器架构
(2)流程如下图:
在这里插入图片描述
TCP通信

2、函数说明
socket()
Sockfd=socket(AF_INET,SOCK_STREAM,0);

Bind()
s_add.sin_family=AF_INET;IPV4协议
s_add.sin_addr.s_addr=inet_addr(“192.168.1.123”);IP地址192.168.1.123
s_add.sin_port=htons(0x8888);端口号是8888

if(-1 == bind(Sockfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))

listen()服务器端侦听函数
listen(Sockfd,5)服务器侦听来自客户端的请求
accept()服务器端接受客户端连接请求
nfp = accept(Sockfd, (struct sockaddr *)(&c_add), sizeof(struct sockaddr);

send()数据发送函数
send(nfp,“hello,welcome to my server”,32,0)
recv()数据接收函数
recv(nfp,buffer,1024,0)
关闭连接
Close(nfp)
关闭服务器
Close(Sockfd)
实例:(1)实验四:网络聊天室设计
(2)网盘/linux编程源代码/socket下相关代码

嵌入式知识点复习七 --linux字符型设备驱动初步

一、Linux字符设备驱动初步
1、Linux设备类型
(1)字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序进行。字符设备是面向流的设备,常见的字符设备如鼠标、键盘、串口、控制台、LED等。
(2)块设备:是指可以从设备的任意位置读取一定长度的数据设备。块设备如硬盘、磁盘、U盘和SD卡等存储设备。
(3)网络设备:网络设备比较特殊,不在是对文件进行操作,而是由专门的网络接口来实现。应用程序不能直接访问网络设备驱动程序。在/dev目录下也没有文件来表示网络设备。

2、开发流程

3、关键函数讲解(以2.6以下版本内核为例)
(1)驱动模块注册register_chrdev()函数
原型:register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
major:主设备号,该值为 0 时,自动运行分配。而实际值不是 0 ;
name:设备名称;
fops:操作函数,实现驱动定义的open、read、write、close等内核函数与应用程序调用的open、read、write、close间的映射;
返回值:
major 值为 0 ,正常注册后,返回分配的主设备号。如果分配失败,返回 EBUSY 的负值 ( -EBUSY ) 。major 值若大于 linux/major.h (2.4内核)中声明的最大值 (#define MAX_CHRDEV 255) ,则返回EINVAL 的负值 (-EINVAL) 。指定 major 值后,若有注册的设备,返回 EBUSY 的负值 (-EBUSY)。若正常注册,则返回 0 值
(2)驱动注销unregister_chrdev()函数
原型:
#include <linux.fs.h>
int unregister_chrdev (unsigned int major, const char *name)
变量:
major 主设备号
name 设备文件
返回值:
major 值若大于 linux/major.h (2.4 内核)中声明的最大值 (#define MAX_CHRDEV 255),返回 EINVAL的负值 (-EINVAL)。指定了 major的值后,若将要注销的 major 值并不是注册的设备驱动程序,返回 EINVAL的负值 ( -EINVAL )。正常注销则返回 0值。
(3)File_operation结构体
file_operations结构是建立驱动程序和设备编号的连接,内部是一组函数指针,每个打开的文件,也就是file结构,和一组函数关联,这些操作主要用来实现系统调用的
struct file_operations {
  struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES
loff_t (*llseek) (struct file *, loff_t, int);//用来修改文件当前的读写位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//从设备中同步读取数据
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向设备发送数据
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的读取操作
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的写入操作
  int (*readdir) (struct file *, void *, filldir_t);//仅用于读取目录,对于设备文件,该字段为NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入
  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令
  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl
  long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替
  int (*mmap) (struct file *, struct vm_area_struct *); //用于请求将设备内存映射到进程地址空间
  int (*open) (struct inode *, struct file *); //打开
  int (*flush) (struct file *, fl_owner_t id);
  int (*release) (struct inode *, struct file *); //关闭
  int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待处理的数据
  int (*aio_fsync) (struct kiocb *, int datasync); //异步刷新待处理的数据
  int (*fasync) (int, struct file *, int); //通知设备FASYNC标志发生变化
  int (*lock) (struct file *, int, struct file_lock *);
  ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  int (*check_flags)(int);
  int (*flock) (struct file *, int, struct file_lock *);
  ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  int (*setlease)(struct file *, long, struct file_lock **);
};
实例:见网盘/linux编程源代码/ok6410ledrv

2016-01-29 18:04:19 ielife 阅读数 1566

电子书的下载地址:(版权归本人所有,下载地址并非编著者本人发布,仅供学习交流,否则追究法律责任)

http://download.csdn.net/detail/comer123/6851765

http://www.verycd.com/topics/2968132/


书名:

构建嵌入式Linux核心软件系统实战




简介:

杨铸、李奎编著的《构建嵌入式Linux核心软件系统实战》以实战的方式,讲解了构建嵌入式linux核心软件系统的五大组件:交叉编译工具链、BootLoader、LinuxKernel、根文件系统、图形界面系统。其中包含了大量解决实际工作中常遇到的典型问题的方法、技巧和经验。

《构建嵌入式Linux核心软件系统实战》适合大学本、专科学生,培训机构学生,自学人员以及研究生学习嵌入式Linux及图形界面软件系统的移植和开发;同时,从事该方向的软件开发工程师也可将本书作为案头的技术手册来进行查阅和参考


大纲:

全书共8章节,内容包括嵌入式Linux系统开发综述、嵌入式Linux开发环境的搭建、体验嵌入式Linux系统之旅、制作交叉编译工具链、构建Boot Loader、构建嵌入式Linux内核,构建嵌入式Linux文件系统,构建QT图形系统


需要书籍内部配套学习光盘资料可以给我留言

2017-08-23 11:20:32 qq_35144795 阅读数 4323

ARM-Linux开发步骤

拿到一块YC2440(s3c2440)的开发板,经过几天的学习,我对arm-linux系统开发步骤有了一些认识。就以开发这个开发板为例,arm-linux开发工作大概分4个部分

1.       硬件(hardware)

2.       引导加载器(bootloader)

3.       内核(kernel)

4.       文件系统(file system)

 

硬件

我并不是硬件工程师,但我知道硬件的设计基本上是从性能,结构,可靠性等方面的需求方面来考虑。比如串口调试很常用,那么硬件就需要设计串口。在比如硬件需要接LCD,就必须提供LCD接口

bootloader

bootloader是什么?

bootloader是一个引导程序,它最主要的功能是加载内核,所谓加载内核就是让内核代码常驻内存,并且得到执行。

 

bootloader因为什么而存在?

每一种CPU都有自己的启动方式

a)       CPU上电后从某个地址开始取指令运行,这样的指令往往是已经固化的,因为RAM刚上电时,里面的内容是没有意义的,很多单片机是这样方式。可以说这根本不是boot

b)      CPU上电后从ROM读代码到RAM,然后跳到RAM里开始执行,这种方式的CPU一般会拷贝固定长度的二进制代码到RAM,因为它不知道有效代码有长,只有一个固定的长度拷贝完成后,CPU才知道拷贝工作完成,以便从RAM执行。这就是boot

c)       方式二只能拷贝固定长度的代码到RAM运行,为了拷贝更多的代码到RAM运行,方式二就做了改进,首先进入RAM的代码不是一个功能固件,而是另一个功能代码的加载器(loader),这就是bootloader

 

armbootloader

arm会拷贝4K长度的代码运行。显然arm不是为4K的固件设计的。拷贝代码到RAM并不需要很多指令,因为ARMRAM的管理需要一个MMU控制器(可以让CPU访问更多的RAM或许)而这个控制器需要配置相关寄存器,所以代码可能要多一点,另外可能还有许多别的功能,所以代码可能会更多。当然都不超过4K时都没问题,但往往还是要过4K的。所以真正arm-linuxbootloader一般有两步骤:

a)       拷贝4K代码到RAM,开始执行

b)      拷贝另一段代码到RAM并初始化一些必须的硬件设置,开始执行

 

u-boot

 

u-boot是一种很流行的bootloader,除了加载内核,它还提供了许多其他功能。基本上u-boot是一个精简的linux,它提供人机交换的,一般现在linux开发都采用串口方式使用u-boot

关于u-boot的说明有很多,我简单说明一下

a)       u-boot可以被打断,通过串口向u-boot输入命令后,u-boot中断,可以执行各种命令,这些命令有专门的手册可以查询。串口其实就是u-boot的一个远程终端。

b)      u-boot可以设置网络,通过tftp服务,u-boot可以下载代码到RAM然后执行,也可以烧写到flash

c)       u-boot之所以有这么多功能是因为里面集成了许多驱动,如果要让u-boot有更多的功能可以在u-boot源代码里添加,如果要用硬件就需要添加驱动。

d)      如果要修改u-boot需要。。编译。。。。。。。。。。。。

 

内核

Linux内核部分是工作量比较多的部分

1.         交叉编译

2.         BSP

3.         Kconfig以及内核裁减

4.         镜像制作和烧写

交叉编译

关于交叉编译,网络上有很多文章。以ubuntu 8.10说明一下:

a)         下载编译器,比如arm-linux-gcc 3.4.1

b)        sudo tar vxjf arm-linux-gcc 3.4.1.bz2 –C /

c)         命令行编译需要设置环境变量

sudo gedit /etc/bash.bashrc

在文件最后添加 export PATH=$PATH:/usr/local/arm/3.4.1/bin

重新登录

d)        arm-linux-gcc –v 查看版本便知道交叉编译器是否安装成功

 

BSP

LinuxBSP其实就是外设驱动集合。比如扩了一个串口,需要编写设备驱动。关于设备驱动编写是一个很大的话题,我想这是另外需要一本书的《Linux Device Driver.3rdEdition》。看不懂可以看看参考http://www.deansys.com/doc/ldd3/index.html

 

Kconfig以及内核裁减

Kconfig是用于定制内核的,有了交叉环境、BSP以及内核源码后,就可以做Kconfig.源码包的Makefile需要从.config得到信息以便把需要的东西编译到内核,不需要的东西不放进来,这样的内核是最精简有效的。问题是这些信息是庞大的,正如管理一个大的工程用Makefile一样,管理一个越来越复杂的内核用Kconfig

 

以下引用自互联网

Kconfig文档的作用

内核源码树的目录下都有两个文档Kconfig2.4版本是Config.in)和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在内核配置make menuconfig(xconfig)时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文档中。在内核编译时,主Makefile调用这个.config,就知道了用户的选择。

*上面的内容说明了,Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,能够修改Kconfig,这样就能够选择这个驱动,假如想使这个驱动被编译,要修改Makefile

so添加新的驱动时需要修改的文档有两种(注意不只是两个)

*Kconfig

*Makefile

要想知道怎么修改这两种文档,就要知道两种文档的语法结构

Kconfig

每个菜单都有一个关键字标识,最常见的就是config

语法:

config

symbol是个新的标记的菜单项,options是在这个新的菜单项下的属性和选项

其中options部分有:

1、类型定义:

每个config菜单项都要有类型定义,bool布尔类型、 tristate三态:内建、模块、移除 string字符串、 hex十六进制、 integer整型

例如config HELLO_MODULE

bool "hello test module"

bool类型的只能选中或不选中,tristate类型的菜单项多了编译成内核模块的选项,假如选择编译成内核模块,则会在.config中生成一个CONFIG_HELLO_MODULE=m的配置,假如选择内建,就是直接编译成内核影响,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置.

2、依赖型定义depends onrequires

指此菜单的出现和否依赖于另一个定义

config HELLO_MODULE

bool "hello test module"

depends on ARCH_PXA

这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效。

3、帮助性定义

只是增加帮助用关键字help---help---

内核的Makefile

 

linux2.6.x/Documentation/kbuild目录下有周详的介绍有关kernel makefile的知识。

内核的Makefile分为5个组成部分:

Makefile     最顶层的Makefile

.config        内核的当前配置文档,编译时成为定层Makefile的一部分

arch/$(ARCH)/Makefile    和体系结构相关的Makefile

s/ Makefile.*      一些Makefile的通用规则

kbuild Makefile           各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译规则,将源代码编译成模块或编入内核

顶层的Makefile文档读取 .config文档的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。 s目录下的Makefile文档包含了任何用来根据kbuild Makefile 构建内核所需的定义和规则。

(其中.config的内容是在make menuconfig的时候,通过Kconfig文档配置的结果。

举个例子:

   假设想把自己写的一个flash的驱动程式加载到工程中,而且能够通过menuconfig配置内核时选择该驱动该怎么办呢?能够分三步:

 第一:将您写的flashtest.c 文档添加到/driver/mtd/maps/ 目录下。

 第二:修改/driver/mtd/maps目录下的kconfig文档:

        config MTD_flashtest

             tristate “ap71 flash"

         这样当make menuconfig ,将会出现 ap71 flash选项。

第三:修改该目录下makefile文档。

ü       添加如下内容:obj-$(CONFIG_MTD_flashtest)       += flashtest.o

这样,当您运行make menucofnig时,您将发现ap71 flash选项,假如您选择了此项。该选择就会保存在.config文档中。当您编译内核时,将会读取.config文档,当发现ap71 flash 选项为yes 时,系统在调用/driver/mtd/maps/下的makefile 时,将会把 flashtest.o 加入到内核中。即可达到您的目的

 

 

make menuconfig后这个蓝色的终端里,有许多复杂的配置,根据需要配置好后保存就可以了。

 

ubuntu 8.10出现make menuconfig失败,一堆错误,这个需要

sudo apt-get install libncurses5-dev

 

镜像制作和烧写

内核镜像是被bootloader加载的,比如u-boot可以把内核镜像加载到RAM并执行。制作u-boot可加载的镜像需要使用mkimage工具,所以

sudo cp ~/tools/mkimage /usr/bin

make uImage

需要注意的是如果mkimage权限不对make uImage是会出错的,可以设置一下权限

sudo chmod 777 /usr/bin/mkimage

如果一切成功那么在linux-xxxx/arch/arm/boot下就有uImage文件了。

如果要更清楚里面的细节,需要对mkimage做进一步了解。

烧写的工作还是交给u-boot吧,大概工作是这样的:

a)         中断u-boot

b)        需要一个tftp服务器,比如Windows XP下安装tftpwin就可以了

c)         调用u-boot命令启动下载烧写