第8章 Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)_第1頁(yè)
第8章 Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)_第2頁(yè)
第8章 Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)_第3頁(yè)
第8章 Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)_第4頁(yè)
第8章 Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)_第5頁(yè)
已閱讀5頁(yè),還剩43頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

《嵌入式系統(tǒng)原理與開(kāi)發(fā)教程》Linux系統(tǒng)應(yīng)用程序開(kāi)發(fā)基礎(chǔ)主講人:賴樹明東莞理工學(xué)院01Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)03Linux系統(tǒng)Makefile使用04Linux文件IO編程05課程作業(yè)任務(wù)02Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)01Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)Linux程序設(shè)計(jì)概述GCC編譯器學(xué)習(xí)Linux系統(tǒng)標(biāo)準(zhǔn)main函數(shù)Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)Linux程序設(shè)計(jì)概述01在Windows系統(tǒng)中,開(kāi)發(fā)工具多以集成開(kāi)發(fā)環(huán)境IDE的形式展現(xiàn)給最終用戶。例如,VS2019集成了編輯器,宏匯編ml,C/C++編譯器cl,資源編譯器rc,調(diào)試器,文檔生成工具,nmake。在Linux系統(tǒng)中,開(kāi)發(fā)工具被切割成一個(gè)個(gè)獨(dú)立的小工具,各自處理不同的問(wèn)題。編輯器(emacs,vim,gedit)用來(lái)進(jìn)行編輯程序調(diào)試器(gdb)用來(lái)調(diào)試程序編譯器(GCC)用來(lái)編譯和鏈接程序本節(jié)重點(diǎn)講解GCC使用方法,這是踏入Linux編程世界的第一步,要求必須掌握。Linux歷史Linux程序設(shè)計(jì)概述Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)GCC編譯器01GNU是一個(gè)計(jì)劃或者叫運(yùn)動(dòng),在GNU計(jì)劃開(kāi)發(fā)了很多的工作和項(xiàng)目,包括核心的gcc和glibc。Linux系統(tǒng)下的gcc(GNUCCompiler)是GNU推出的功能強(qiáng)大、性能優(yōu)越的多平臺(tái)編譯器。gcc是可以在多種硬體平臺(tái)上編譯出可執(zhí)行程序的超級(jí)編譯器,其執(zhí)行效率與一般的編譯器相比平均效率要高20%~30%。gcc編譯器能將C、C++語(yǔ)言源程序、匯程式化序和目標(biāo)程序編譯、連接成可執(zhí)行文件。在Linux系統(tǒng)中,可執(zhí)行文件沒(méi)有統(tǒng)一的后綴,系統(tǒng)從文件的屬性來(lái)區(qū)分可執(zhí)行文件和不可執(zhí)行文件。而gcc則通過(guò)后綴來(lái)區(qū)別輸入文件的類別。Linux歷史GCC編譯器介紹Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)GCC編譯器學(xué)習(xí)01.c為后綴的文件,C語(yǔ)言源代碼文件;

.a為后綴的文件,是由目標(biāo)文件構(gòu)成的檔案庫(kù)文件;

.C或.cc或.cxx為后綴的文件,是C++源代碼文件;

.h為后綴的文件,是程序所包含的頭文件;

.i為后綴的文件,是已經(jīng)預(yù)處理過(guò)的C源代碼文件;

.ii為后綴的文件,是已經(jīng)預(yù)處理過(guò)的C++源代碼文件;

.m為后綴的文件,是Objective-C源代碼文件;

.o為后綴的文件,是編譯后的目標(biāo)文件;

.s為后綴的文件,是匯編語(yǔ)言源代碼文件;

.S為后綴的文件,是經(jīng)過(guò)預(yù)編譯的匯編語(yǔ)言源代碼文件。Linux歷史GCC支持的文件擴(kuò)展名Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)GCC編譯器學(xué)習(xí)01C語(yǔ)言從源代碼到可執(zhí)行文件需要經(jīng)歷四個(gè)相互關(guān)聯(lián)的步驟,如下所示:GCC編譯程序流程預(yù)處理(Preprocessing)源代碼文件中以#開(kāi)頭的代碼進(jìn)行處理,如#include,#define,#if等),生成不帶#開(kāi)頭代碼的源中間文件編譯(Compilation)把預(yù)處理的文件編譯生成以.s為后綴的匯編代碼文件。匯編(Assembly)把上一步得到的匯編文件使用匯編器進(jìn)行編譯,生成以.o為后綴的二進(jìn)制目標(biāo)文件,但是這時(shí)的文件還不能執(zhí)行。鏈接(Linking)把所有的.o文件使用鏈接器進(jìn)行鏈接,整合成一個(gè)可執(zhí)行程序。Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)GCC編譯器學(xué)習(xí)01gcc常用選項(xiàng)選項(xiàng)含義-c只編譯不鏈接,源文件編譯成目標(biāo)代碼(.o),默認(rèn)生成目標(biāo)文件“.o”-S(注意是大寫S)生成匯編代碼-E只進(jìn)行預(yù)編譯,不做其他處理-g在可執(zhí)行程序中包含標(biāo)準(zhǔn)調(diào)試信息-o<輸出目標(biāo)文件名>指定輸出文件名-O<0~3優(yōu)化級(jí)別>代碼優(yōu)化選項(xiàng),-ON:指定優(yōu)化級(jí)別,0<=N<=3,默認(rèn)為1-v打印出編譯內(nèi)部編譯各過(guò)程的命令行信息和編譯器的版本-Wall打開(kāi)所有警告-Werror把所有警告當(dāng)成錯(cuò)誤處理-w關(guān)閉所有警告-static鏈接靜態(tài)庫(kù),默認(rèn)情況下gcc只鏈接動(dòng)態(tài)庫(kù)(靜態(tài)庫(kù):以.a為擴(kuò)展名,動(dòng)態(tài)庫(kù):帶.so擴(kuò)展名的庫(kù)文件)靜態(tài)鏈接:生成的可執(zhí)行程序包含所有調(diào)用的函數(shù)實(shí)現(xiàn)代碼動(dòng)態(tài)鏈接:生成的可執(zhí)行程序是運(yùn)行時(shí)才在so動(dòng)態(tài)庫(kù)中搜索其調(diào)用的函數(shù)的。-I<頭文件路徑>指定編譯時(shí)包含的頭文件路徑-L<庫(kù)文件路徑>指定鏈接時(shí)第三庫(kù)文件的路徑-l

<庫(kù)文件名>(L的小字字母)指定鏈接時(shí)庫(kù)文件的名稱

在Linux系統(tǒng)中庫(kù)文件命名lib庫(kù)名.so[*]或lib庫(kù)名.a,指定庫(kù):-l庫(kù)名Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)GCC編譯器學(xué)習(xí)01main.c源碼清單:#include<stdio.h>externintadd(int,int);externintsub(int,int);intmain(void){printf(“1+2:%d\r\n",add(1,2));printf(“20-10:%d\r\n",sub(20,10));}gcc編譯示例add.c源碼清單:intadd(inta,intb){returna+b;}sub.c源碼清單:intsub(inta,intb){returna-b;}編譯過(guò)程:分別編譯三個(gè)文件為二進(jìn)制目標(biāo)文件gcc-Emain.c-omain.igcc-Smain.i-omain.sgcc-cmain.s-omain.ogcc-Eadd.c-oadd.igcc-Sadd.i-oadd.sgcc-cadd.s-oadd.ogcc-Esub.c-osub.igcc-Ssub.i-osub.sgcc-csub.s-osub.o鏈接:gccmain.osub.oadd.o-omain運(yùn)行:./maingcc編譯器也支持一次編譯生成可執(zhí)行程序,如上面三個(gè)c程序,執(zhí)行以下指令:gccmain.csub.cadd.c-omain可以直接生成可執(zhí)行程序main。Linux系統(tǒng)程序設(shè)計(jì)基礎(chǔ)Linux標(biāo)準(zhǔn)main函數(shù)01在Linux系統(tǒng)或Windows系統(tǒng)中,啟動(dòng)應(yīng)用程序時(shí)可以給程序傳遞參數(shù),例如:“l(fā)s-l/home”中,“l(fā)s”是程序名,

“-l”是參數(shù)1,“/home”是參數(shù)2,如有更多依次類推。程序要接收啟動(dòng)的參數(shù),由需要通過(guò)main函數(shù)來(lái)完成。示例:以下app-arg.c把命令行中輸入的參數(shù)數(shù)量及每個(gè)參數(shù)全部輸出。app-arg.c源碼清單:#include<stdio.h>intmain(intargc,char*argv[]){ inti=0; printf("argc:%d\r\n",argc); for(i=0;i<argc;i++){ printf("argv[%d]:%s\r\n",i,argv[i]); }}系統(tǒng)級(jí)標(biāo)準(zhǔn)main函數(shù)說(shuō)明:argc記錄了啟動(dòng)程序時(shí)參數(shù)個(gè)數(shù),程序名本身算一個(gè)參數(shù);argv是一個(gè)char*類型的數(shù)組,每個(gè)元素保存了命令行為每個(gè)字符串參數(shù)地址,通過(guò)argv的下標(biāo)可以取得啟動(dòng)程序時(shí)傳遞給程序的參數(shù)。編譯:$gccapp-arg.c-oapp-arg運(yùn)行測(cè)試:$./app-argxyd123

argc:4argv[0]:./app-argargv[1]:xydargv[2]:123argv[3]:結(jié)果分析:以空格分隔的,每個(gè)字符串是一個(gè)參數(shù),分別保存在argv數(shù)組中。02Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)相關(guān)編譯選項(xiàng)靜態(tài)庫(kù)的創(chuàng)建及使動(dòng)態(tài)庫(kù)的創(chuàng)建及使動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)的比較Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)概述02函數(shù)庫(kù)是能提供一系列功能函數(shù)給第三方程序調(diào)用的文件,可分為靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)(也稱為共享庫(kù)),在使用上對(duì)應(yīng)靜態(tài)鏈接和動(dòng)態(tài)鏈接。編譯鏈接程序時(shí),鏈接器會(huì)根據(jù)命令選項(xiàng)采用動(dòng)態(tài)庫(kù)還是靜態(tài)庫(kù)中的函數(shù)。函數(shù)庫(kù)定義動(dòng)態(tài)庫(kù)命名:

libname.so.x.y.zlib:固定名稱前綴;name:真正的庫(kù)名稱;

so:固定后綴x:主版本號(hào);

y:次版本號(hào);z:發(fā)行版本號(hào)

,其中.x.y.z是可選的靜態(tài)庫(kù)命名:

libname.a庫(kù)命名規(guī)則

把功能函數(shù)寫到單獨(dú)的C文件中,使用編譯器封裝成.a文件,第三方程序要調(diào)用其中的函數(shù)時(shí)通過(guò)編譯選項(xiàng)-static-l庫(kù)名

形式把調(diào)用的函數(shù)對(duì)應(yīng)代碼復(fù)制一份到當(dāng)前程序中,運(yùn)行時(shí)候就再依賴靜態(tài)庫(kù)文件。靜態(tài)庫(kù)使用原理把功能函數(shù)寫到單獨(dú)的C文件中,使用編譯器封裝成libname.so.x.y.z動(dòng)態(tài)庫(kù)文件,第三方程序要調(diào)用其中的函數(shù)時(shí)通過(guò)編譯選項(xiàng)-l庫(kù)名

形式來(lái)找到庫(kù),記錄函數(shù)符號(hào),并沒(méi)有復(fù)制代碼到當(dāng)前程序中,而是運(yùn)行時(shí)才加載動(dòng)態(tài)庫(kù)文件到,找到函數(shù)執(zhí)行。動(dòng)態(tài)庫(kù)使用原理Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)相關(guān)編譯選項(xiàng)02如果gcc編譯命令中指定該選項(xiàng),表示代碼中使用到來(lái)自第三方庫(kù)的函數(shù)必須存在靜態(tài)庫(kù),不能是動(dòng)態(tài)庫(kù),否則鏈接失敗。-static選項(xiàng)如果gcc編譯指令中指定該選項(xiàng),表示優(yōu)先使用動(dòng)態(tài)庫(kù)鏈接,即代碼中使用來(lái)自第三方庫(kù)的函數(shù),如果同時(shí)存在動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù),會(huì)優(yōu)先使用動(dòng)態(tài)庫(kù)鏈接,如果只存在靜態(tài)庫(kù),才會(huì)使用靜態(tài)庫(kù)文件鏈接。-shared選項(xiàng)如果gcc編譯指令中指定該選項(xiàng),表示要生成相對(duì)地址位置無(wú)關(guān)的目標(biāo)代碼,通常使用gcc的-shared選項(xiàng)把生成位置無(wú)關(guān)目標(biāo)文件編譯成動(dòng)態(tài)庫(kù)文件。-fPIC選項(xiàng)在使用第三方庫(kù)時(shí),如果沒(méi)有把第三方庫(kù)文件復(fù)制到系統(tǒng)存放庫(kù)文件的標(biāo)準(zhǔn)路徑中,則要在編譯階段使用-L選項(xiàng)來(lái)指定第三方庫(kù)的存放位置。而-I后面跟著的是庫(kù)文件存放路徑,后面可以加空格,也可以不加空格直接寫庫(kù)文件路徑,路徑可以是相對(duì)路徑,也可以使用絕對(duì)路徑。-L<dir>選項(xiàng)鏈接時(shí),采用鏈接名為libname.a靜態(tài)庫(kù)或libname.so動(dòng)態(tài)庫(kù)的庫(kù)文件或其中的一個(gè)。若兩個(gè)庫(kù)文件都存在,則根據(jù)編譯時(shí)指定的選項(xiàng)(-static或-shared或不寫)來(lái)進(jìn)行鏈接。-lname選項(xiàng)aad.c:intadd(inta,intb){intc;c=a+b;returnc;}Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)03編寫功能函數(shù)靜態(tài)庫(kù)的創(chuàng)建及使用sub.c:intsub(inta,intb){intc;c=a-b;returnc;}aad.h:#ifndef__ADD_H__#define__ADD_H__intadd(inta,intb);#endifsub.h:#ifndef__SUB_H__#define__SUB_H__intsub(inta,intb);#endifgcc-cadd.c-oadd.ogcc-csub.c-osub.o編譯函數(shù)為.o文件ar-crsvlibfunction.aadd.osub.o把.o文件封裝成.a執(zhí)行上面命令后會(huì)生成libfunction.a靜態(tài)庫(kù)文件,后面就可以供第三方程序使用。main.c:#include<stdio.h>#include"add.h"http://引入函數(shù)聲明#include"sub.h"http://引入函數(shù)聲明intmain(void){printf("2+1=%d;\r\n2-1=%d\r\n",add(2,1),sub(2,1));return0;}Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)03測(cè)試代碼編寫靜態(tài)庫(kù)的創(chuàng)建及使用工程文件存放結(jié)構(gòu)├──include│├──add.h│└──sub.h└──src├──add.c├──libfunction.a├──main.c└──sub.c說(shuō)明:編譯為.a文件后,可以把a(bǔ)dd.c、sub.c刪除,我們只需要.a文件即可。編譯:gcc-omainmain.clibfunction.a-I../include/

--->這種是把庫(kù)當(dāng)成源文件一樣使用或者:gcc-omainmain.c-I../include-L./-lfunction--->這種是標(biāo)準(zhǔn)的使用方法編譯生成main可執(zhí)行程序后可以刪除.a文件,不會(huì)影響到后面可執(zhí)行程序的運(yùn)行,因?yàn)樗褟?fù)制一份代碼到其中。運(yùn)行:./mainaad.c:intadd(inta,intb){intc;c=a+b;returnc;}Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)03編寫功能函數(shù)動(dòng)態(tài)庫(kù)的創(chuàng)建及使用sub.c:intsub(inta,intb){intc;c=a-b;returnc;}aad.h:#ifndef__ADD_H__#define__ADD_H__intadd(inta,intb);#endifsub.h:#ifndef__SUB_H__#define__SUB_H__intsub(inta,intb);#endifgcc-fPIC-cadd.c-oadd.ogcc-fPIC-csub.c-osub.o編譯函數(shù)為.o文件gcc-olibfunction.so-sharedadd.osub.o把.o文件封裝成.a執(zhí)行上面命令后會(huì)生成libfunction.so動(dòng)態(tài)庫(kù)文件,后面就可以供第三方程序使用。補(bǔ)充:也支持把上三條指令合并成為條:gcc-olibfunction.so-shared-fPICadd.csub.cmain.c:#include<stdio.h>#include"add.h"http://引入函數(shù)聲明#include"sub.h"http://引入函數(shù)聲明intmain(void){printf("2+1=%d;\r\n2-1=%d\r\n",add(2,1),sub(2,1));return0;}Linux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)03測(cè)試代碼編寫動(dòng)態(tài)庫(kù)的創(chuàng)建及使用工程文件存放結(jié)構(gòu)├──include│├──add.h│└──sub.h└──src├──add.c├──libfunction.so├──main.c└──sub.c說(shuō)明:編譯為.so文件后,可以把

add.c、sub.c刪除,我們只需要

.so文件即可。編譯:gcc-omainmain.clibfunction.so-I../include/

--->這種是把庫(kù)當(dāng)成源文件一樣使用或者:gcc-omainmain.c-I../include-L./-lfunction--->這種是標(biāo)準(zhǔn)的使用方法編譯生成main可執(zhí)行程序后可以刪除.a文件,不會(huì)影響到后面可執(zhí)行程序的運(yùn)行,因?yàn)樗褟?fù)制一份代碼到其中。運(yùn)行:./mainLinux靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)03運(yùn)行測(cè)試程序動(dòng)態(tài)庫(kù)的創(chuàng)建及使用由于采用動(dòng)態(tài)庫(kù),生成main可執(zhí)行程序在鏈接時(shí)并沒(méi)有把調(diào)用的add,sub函數(shù)實(shí)現(xiàn)代碼復(fù)制到程序當(dāng)中,而在運(yùn)行時(shí)候在系統(tǒng)庫(kù)環(huán)境變量中指定的路徑去搜索動(dòng)態(tài)庫(kù)文件,加載到內(nèi)在中,然后再調(diào)用已經(jīng)加載到內(nèi)在的so文件中的函數(shù)代碼,因此,要想正確運(yùn)行使用了動(dòng)態(tài)庫(kù)的程序,必須把依賴的動(dòng)態(tài)庫(kù)也復(fù)制到系統(tǒng)的環(huán)境變量指定的目標(biāo)當(dāng)中,一般可以復(fù)制到/lib目錄即可,當(dāng)然其他系統(tǒng)環(huán)境變量指定的庫(kù)存放目錄也是可以的。復(fù)制動(dòng)態(tài)庫(kù)文件到/lib目錄中:sudocplibfunction.a/lib/運(yùn)行測(cè)試程序:./main

補(bǔ)充:如果不復(fù)制到系統(tǒng)環(huán)境變量指定的庫(kù)路徑,也可以通過(guò)臨時(shí)導(dǎo)出環(huán)境變量的方式,不過(guò)不推薦使用這種,每次都需要操作一次,比較麻煩:exportLD_LIBRARY_PATH=$PWD

。另一種方法:修改/etc/ld.so.conf配置文件,把動(dòng)態(tài)庫(kù)文件所在路徑寫到其中,然后

執(zhí)行“sudoldconfig”命令讓系統(tǒng)重新加載

/etc/ld.so.conf配置文件可,系統(tǒng)會(huì)到指定路徑加載動(dòng)態(tài)庫(kù)

。03Linux系統(tǒng)Makefile使用Makefile概述Makefile語(yǔ)法Makefile編程進(jìn)階少量代碼可以直接使用:gcc源代碼列表-o可執(zhí)行程序名命令直接編譯,如果文件數(shù)量龐大,每次都使用上面命令編譯則會(huì)耗費(fèi)大量時(shí)間(輸入命令、哪怕是沒(méi)有修改地的文件都重新編譯都需要花費(fèi)時(shí)間)Linux中使用makefile來(lái)解決文件編譯的問(wèn)題,Makefile中定義了一系列的規(guī)則,指定哪文件的編譯順序,哪些文件需要重新編譯,或?qū)崿F(xiàn)更復(fù)雜的功能操作。Makefile就像一個(gè)Shell腳本一樣,Makefile文件中也使用Linux系統(tǒng)的命令。Makefile可以實(shí)現(xiàn)自動(dòng)化編譯”,只需要一個(gè)make命令,整個(gè)工程完全自動(dòng)編譯,極大的提高了軟件開(kāi)發(fā)的效率。使用make命令來(lái)是解釋Makefile編寫的編譯規(guī)則。Makefile使用:把命令終端工作目錄切換到包含編寫好的Makefile的目錄,輸入make命令即可。Linux系統(tǒng)Makefile使用03概述Makefile概述目標(biāo)1:[依賴1依賴2依賴3…]TAB鍵

所有依賴都實(shí)現(xiàn)后會(huì)執(zhí)行的命令語(yǔ)句1TAB鍵

所有依賴都實(shí)現(xiàn)后會(huì)執(zhí)行的命令語(yǔ)句2……依賴1:[依賴1

…]TAB鍵

所有依賴都實(shí)現(xiàn)后會(huì)執(zhí)行的命令語(yǔ)句1……目標(biāo)2:[依賴1依賴2依賴3…]TAB鍵

所有依賴都實(shí)現(xiàn)后會(huì)執(zhí)行的命令語(yǔ)句1……Linux系統(tǒng)Makefile使用03Makefile文件格式Makefile語(yǔ)法Makefile中的目標(biāo)名,根據(jù)需要隨意定義;目標(biāo)名一般是對(duì)應(yīng)于硬盤上的一個(gè)同名文件,目標(biāo)規(guī)則下方的命令語(yǔ)句必須以tab鍵開(kāi)頭,命令語(yǔ)句可根據(jù)需要編寫,可以使用Linux各種命令依賴可以是一個(gè)文件,也可以是Makefile中一個(gè)目標(biāo)規(guī)則;命令終端輸入make命令后,make程序會(huì)在當(dāng)前目錄查找名為Makefile/makefile的文件,執(zhí)行其中的第一個(gè)目標(biāo)規(guī)則下的命令;某些操作并不需要生成文件,則PHONY關(guān)鍵字聲明為一個(gè)偽目標(biāo);聲明偽目標(biāo)的語(yǔ)法:PHONY:目標(biāo)名1目標(biāo)名2

如:PHONY:rebuildclean被聲明為偽目標(biāo)的目的規(guī)則名make程序不會(huì)視為文件,不會(huì)關(guān)心硬盤上是否存在這個(gè)文件,而是無(wú)條件執(zhí)行目標(biāo)名下對(duì)應(yīng)的命令;main:main.oadd.o gcc-omainmain.oadd.omain.o:main.c gcc-cmain.cadd.o:add.c gcc-cadd.c#把clean聲明為偽目標(biāo)PHONY:cleanclean: rm*.omainLinux系統(tǒng)Makefile使用03Makefile入門示例Makefile語(yǔ)法注意:和shell編程相同,在Makefile中,也用“#”號(hào)表示注釋執(zhí)行Makefile中指定目標(biāo):

語(yǔ)法:make[目標(biāo)名]說(shuō)明:不指定目標(biāo)名則默認(rèn)第一個(gè)目標(biāo)

例如:make執(zhí)行第一個(gè)目標(biāo)規(guī)則下方的命令語(yǔ)句makeclean執(zhí)行clean目標(biāo)下方的命令語(yǔ)句makeadd.o 執(zhí)行add.o目標(biāo)下方的命令語(yǔ)句make命令會(huì)根據(jù)Makefile遞歸推導(dǎo)目標(biāo)規(guī)則依賴實(shí)現(xiàn)方法,當(dāng)所有依賴實(shí)現(xiàn)Makefile中可以定義變量,與C語(yǔ)言不同,沒(méi)有類型說(shuō)明,值全部以字符形式表示;Makefile定義變量:直接命名一個(gè)合法標(biāo)識(shí)符,同時(shí)對(duì)它進(jìn)行初始化Makefile變量初始化有四種方法:使用=

:=+=?=+==:最普通的賦值方式

;:=:

變量值簡(jiǎn)單變量展開(kāi)(類似于C語(yǔ)言賦值),是覆蓋之前的值,通常采用這種形式;

?=:如果當(dāng)前變量沒(méi)有賦值才進(jìn)行賦值,這種方式一般用于可以通過(guò)make變量名=新值方式來(lái)替換Makefile中的定義的默認(rèn)值;

比如:makefile中定義變量var?=123,命令行輸入makevar=567,則var值會(huì)被567替換;+=:追加上原來(lái)的數(shù)值,如:A+=123A+=www則結(jié)果是A值為123www

變量引用:要取得變量的值,使用$(變量名)或$變量名,建議使用$(變量名)

Linux系統(tǒng)Makefile使用03使用普通變量Makefile編程進(jìn)階APP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS) gcc-o$(APP_NAME)$(OBJS)main.o:main.c gcc-cmain.c-omain.oadd.o:add.c gcc-cadd.c-oadd.o#聲明偽目標(biāo) PHONY:rebuildcleanclean: rm-rf$(APP_NAME)$(OBJS)*~Linux系統(tǒng)Makefile使用03Makefile普通變量示例Makefile編程進(jìn)階edu118@localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*~edu118@localhost:02_makefile$makegcc-cmain.c-omain.ogcc-cadd.c-oadd.ogcc-omainmain.oadd.o運(yùn)行生成的可執(zhí)行程序:edu118@localhost:02_makefile$./mains:3hellolinux!在Makefile規(guī)范中定義了一些具有特定含義的變量,我們可以使用這些變量進(jìn)一步優(yōu)化Makefile,以下列出比較常用的。Linux系統(tǒng)Makefile使用03使用自動(dòng)變量Makefile編程進(jìn)階變量名說(shuō)明$@當(dāng)前規(guī)則的目標(biāo)名$<當(dāng)前規(guī)則的第一個(gè)依賴如main:main.oadd.o,則命令中$<結(jié)果是main.o$^當(dāng)前規(guī)則的所有依賴文件,以空格分隔,如main:main.oadd.o,則命令中$^結(jié)果是main.oadd.o$?規(guī)則中日期新于目標(biāo)文件的所有相關(guān)文件列表,逗號(hào)分隔$(@D)目標(biāo)文件的目錄名部分,如目標(biāo)名是bin/main則命令中$(@D)得到bin$(@F)目標(biāo)文件的文件名部分,如目標(biāo)名是bin/main則命令中$(@F)得到main#外部可以傳入新值替換這里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS) gcc-o$@

$^main.o:main.c gcc-c$<

-o$@add.o:add.c gcc-c$<

-o$@#聲明偽目標(biāo) PHONY:rebuildcleanclean: rm-rf$(APP_NAME)$(OBJS)*~Linux系統(tǒng)Makefile使用03Makefile自動(dòng)變量示例Makefile編程進(jìn)階edu118@localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*~編譯:edu118@localhost:02_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.o運(yùn)行生成的可執(zhí)行程序:edu118@localhost:02_makefile$./mains:3hellolinux!前面使用使用變量?jī)?yōu)化的Makefile還存在很多不足的,比如每添加增加一個(gè)C文件,必須增加一個(gè)生成.o文件的規(guī)則,如下:mul.o:mul.c gcc-c$<

-o$@Makefile規(guī)則中支持使用模式規(guī)則,所謂模式匹配規(guī)則即是通過(guò)匹配模式找字符串,你可以理解為類似命令的通配置符。Makefile中規(guī)定使用“%”匹配1或多個(gè)任意字符串。上面的mul.o:mul.c演變?yōu)椋?.o:%.c,表示任意目標(biāo)文件依賴文件是與目標(biāo)文件同名.c的文件;Linux系統(tǒng)Makefile使用03模式規(guī)則%.o:%.cMakefile編程進(jìn)階#外部可以傳入新值替換這里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS) gcc-o$@

$^%.o:%.c gcc-c$<

-o$@#聲明偽目標(biāo) PHONY:rebuildcleanclean: rm-rf$(APP_NAME)$(OBJS)*~Linux系統(tǒng)Makefile使用03Makefile模式規(guī)則示例Makefile編程進(jìn)階edu118@localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*~編譯:edu118@localhost:02_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.o運(yùn)行生成的可執(zhí)行程序:edu118@localhost:02_makefile$./mains:3hellolinux!#外部可以傳入新值替換這里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS) gcc-o$@

$^%.o:%.c gcc-c$<

-o$@#聲明偽目標(biāo) PHONY:rebuildcleanclean: rm-rf$(APP_NAME)$(OBJS)*~Linux系統(tǒng)Makefile使用03模式規(guī)則使用示例Makefile編程進(jìn)階edu118@localhost:03_makefile$makecleanrm-rfmainmain.oadd.o*~編譯:edu118@localhost:03_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.o運(yùn)行生成的可執(zhí)行程序:edu118@localhost:03_makefile$./mains:3hellolinux!上面的Makefile當(dāng)項(xiàng)目文件增加時(shí),還需要再修改Makefile,如:修改OBJS:=main.oadd.o變量值解決:使用Makefile函數(shù)的來(lái)遍歷指定目錄的c文件,然后把后綴名去掉,得到目標(biāo)名文件列表常用幾個(gè)Makefile函數(shù)有wildcard,patsubst,addprefixLinux系統(tǒng)Makefile使用03Makefile函數(shù)使用Makefile編程進(jìn)階#外部可以傳入新值替換這里的mainAPP_NAME?=main#得到當(dāng)前目錄的c文件列表SRCS:=$(wildcard*.c)#把.c替換為.o,得到.o文件列表OBJS:=$(patsubst

%.c,%.o,$(SRCS))$(APP_NAME):$(OBJS) gcc-o$@

$^%.o:%.c gcc-c$<

-o$@#聲明偽目標(biāo) PHONY:rebuildcleanclean: rm-rf$(APP_NAME)$(OBJS)*~Makefile函數(shù)使用示例edu118@localhost:04_makefile$makecleanrm-rfmainmain.oadd.o*~編譯:edu118@localhost:04_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.oedu118@localhost:04_makefile$makemake:'main'isuptodate.運(yùn)行生成的可執(zhí)行程序:edu118@localhost:04_makefile$./mains:3hellolinux!04Linux文件IO編程Linux文件類型Linux文件IO分類非緩沖文件IO編程緩沖文件IO編程--選修Linux系統(tǒng)中一切皆文件,對(duì)普通文件和硬件設(shè)備的操作都是文件操作。Linux系統(tǒng)文件分為普通文件,管道文件,目錄文件,鏈接文件,套接字文件和設(shè)備文件。普通文件:也稱磁盤文件,并且能夠進(jìn)行隨機(jī)的存儲(chǔ)數(shù)據(jù)(能夠自由seek定位到某一個(gè)位置);管道文件:是一個(gè)從一端發(fā)送數(shù)據(jù),另一端接收數(shù)據(jù)的數(shù)據(jù)通道;目錄文件:它包含了保存在目錄中文件列表的簡(jiǎn)單文件。套接字文件:在Linux中,套接字也可以當(dāng)作文件來(lái)進(jìn)行處理。設(shè)備文件:Linux下各種硬件設(shè)備在內(nèi)核中都表現(xiàn)為一個(gè)設(shè)備文件,通過(guò)設(shè)備文件操作對(duì)應(yīng)的硬件設(shè)備。

設(shè)備文件有兩種類型:字符型設(shè)備和塊設(shè)備。

字符設(shè)備文件:是以字節(jié)為單位進(jìn)行順序讀寫的設(shè)備,如鼠標(biāo)、鍵盤、終端、打印機(jī)、聲卡,串口等,各類傳感器;

塊設(shè)備文件:以塊為單位來(lái)讀出或者寫入數(shù)據(jù),如CD-ROM、硬盤、SD卡,U盤等大容量存儲(chǔ)類型設(shè)備;對(duì)文件操作一般步驟:打開(kāi)文件,讀/寫/移動(dòng)讀寫指針等操作,關(guān)閉文件。

其中打開(kāi)文件是第一步,是為后續(xù)操作做準(zhǔn)備的。Linux文件IO編程Linux文件類型04在Linux系統(tǒng)中,對(duì)文件進(jìn)行讀寫操作有兩套機(jī)制:緩沖文件IO操作和非緩沖文件IO操作;緩沖文件IO操作:這種文件操作就是標(biāo)準(zhǔn)C庫(kù)提供的文件操作;對(duì)文件讀寫是帶緩沖區(qū)的,一般使用來(lái)操作硬盤上的數(shù)據(jù)文件,如電影,音樂(lè),文檔等普通文件。非緩沖文件IO操作:這種文件操作就是Linux系統(tǒng)特有的文件操作,只能在Linux系統(tǒng)中使用,對(duì)文件讀寫的讀寫是不帶緩沖區(qū)的,一般使用來(lái)操作硬件設(shè)備在系統(tǒng)中的設(shè)備文件,如鼠標(biāo),鍵盤,傳感器,UART等對(duì)應(yīng)的設(shè)備文件,當(dāng)然,它也可以使用來(lái)操作硬盤上的數(shù)據(jù)文件,如電影,音樂(lè),文檔。IO分類Linux文件IO編程Linux文件IO分類04文件描述符:是內(nèi)核為了高效的管理已經(jīng)被打開(kāi)的文件所創(chuàng)建的編號(hào),它是一個(gè)非負(fù)整數(shù),用于指代被打開(kāi)的文件,所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都是通過(guò)文件描述符完成的。當(dāng)某個(gè)程序打開(kāi)文件時(shí),操作系統(tǒng)返回相應(yīng)的文件描述符,程序?yàn)樘幚碓撐募仨氁么嗣枋龇K^的文件描述符是一個(gè)低級(jí)的正整數(shù)。最前面的三個(gè)文件描述符(0,1,2)分別與標(biāo)準(zhǔn)輸入(stdin),標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)對(duì)應(yīng)。每次打開(kāi)的文件時(shí)(含socket)必須使用當(dāng)前進(jìn)程中最小可用的文件描述符號(hào)碼。Linux文件IO編程非緩沖文件IO編程04主要函數(shù)文件描述符open(打開(kāi))、read(讀)、write(寫)、close(關(guān)閉)、lseek(調(diào)整讀寫位置)Linux文件IO編程非緩沖文件IO編程04open函數(shù)頭文件:#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>原型1:intopen(constchar*pathname,intflags);原型2:intopen(constchar*pathname,intflags,mode_tmode);功能:打開(kāi)一個(gè)現(xiàn)有文件或創(chuàng)建一個(gè)新文件

參數(shù):pathname:帶路徑的文件名,表示要操作哪個(gè)文件。

flags:文件打開(kāi)方式,常用值:O_RDONLY:只讀模式O_WRONLY:只寫模式O_RDWR:可讀可寫O_CREAT:如果文件不存在,則創(chuàng)建;mode:當(dāng)創(chuàng)建新文件時(shí)設(shè)置文件訪問(wèn)權(quán)限的初始值,和用戶掩碼umask有關(guān);返回值:>=0:打開(kāi)成功,值為文件描述符,這個(gè)數(shù)值關(guān)聯(lián)pathname表示的文件;-1:打開(kāi)失敗。mode可取值:S_IXOTH:其他用戶有執(zhí)行權(quán)0o001S_IWOTH:其他用戶有寫權(quán)限0o002S_IROTH:其他用戶有讀權(quán)限0o004S_IRWXO:其他用戶有全部權(quán)限(權(quán)限掩碼)0o007S_IXGRP:組用戶有執(zhí)行權(quán)限0o010S_IWGRP:組用戶有寫權(quán)限0o020S_IRGRP:組用戶有讀權(quán)限0o040S_IRWXG:組用戶有全部權(quán)限(權(quán)限掩碼)0o070S_IXUSR:擁有者具有執(zhí)行權(quán)限0o100S_IWUSR:擁有者具有寫權(quán)限0o200S_IRUSR:擁有者具有讀權(quán)限0o400S_IRWXU:擁有者有全部權(quán)限(權(quán)限掩碼)0o700Linux文件IO編程非緩沖文件IO編程04read函數(shù)頭文件:#include<unistd.h>原型:ssize_tread(intfd,void*buf,size_tcount);功能:從fd關(guān)聯(lián)的文件中讀取最多count字節(jié)數(shù)據(jù)保存到buf指向的內(nèi)存首地址;參數(shù):fd:要讀取得文件描述符;buf:數(shù)據(jù)指針,指向保存讀取到的數(shù)據(jù)的內(nèi)存地址;count:要讀取的字節(jié)數(shù)量;返回值:出錯(cuò):-1;0:讀文件結(jié)束;>0:成功讀取到的字節(jié)數(shù);0<=返回值<count時(shí)表示已經(jīng)把文件數(shù)據(jù)讀取完成;==count并不能判斷已經(jīng)讀取完成,即使文件只count字節(jié)。注意:每讀取成功1字節(jié),文件讀寫位置指針增加1。write函數(shù)頭文件:#include<unistd.h>原型ssize_twrite(intfd,constvoid*buf,size_tcount);功能:把buf指向的內(nèi)存開(kāi)始的數(shù)據(jù),寫入到fd關(guān)聯(lián)的文件中,最多寫入ount字節(jié);參數(shù):fd:要讀取得文件描述符;buf:數(shù)據(jù)指針,指向要寫入的數(shù)據(jù)的內(nèi)存首地址;count:要寫入的的字節(jié)數(shù)量;返回值:-1:出錯(cuò):>0:成功寫入到的字節(jié)數(shù);注意:每寫入成功1字節(jié),文件讀寫位置指針增加1注意1:文件讀寫位置是共用一個(gè)讀寫位置指針的,每讀寫成功1字節(jié),則文件讀寫位置相應(yīng)增加1字節(jié);注意2:讀寫函數(shù)調(diào)用都是從當(dāng)前文件讀寫位置開(kāi)始讀寫數(shù)據(jù)的;Linux文件IO編程非緩沖文件IO編程04lseek函數(shù)頭文件:#include<sys/types.h>#include<unistd.h>原型:off_tlseek(intfd,off_toffset,intwhence);參數(shù):fd:之前用open()獲得的一個(gè)文件描述符;offset:要調(diào)整的讀寫偏移量,可正可負(fù),如何由whence來(lái)確定的;whence參數(shù)分為下列三種:SEEK_SET:最終的讀寫位置=offset。SEEK_CUR:最終的讀寫位置=當(dāng)前讀寫位置+offsetSEEK_END:最終的讀寫位置=文件末尾+offset返回值:>=0:調(diào)用成功,值含義是距離文件開(kāi)頭字節(jié)偏移。-1:調(diào)用失敗,錯(cuò)誤代碼保存在全局變量errno中,常見(jiàn)的erron的錯(cuò)誤代碼:EBADF:fildes不是一個(gè)打開(kāi)的文件描述符。ESPIPE:文件描述符被分配到一個(gè)管道、套接字或FIFO。EINVAL:whence取值不當(dāng)。close函數(shù)頭文件:#include<unistd.h>原型:intclose(intfd);;參數(shù):fd:之前用open()獲得的一個(gè)文件描述符;返回值:成功0,否則返回-1,同時(shí)失敗原因會(huì)被記錄在errno中。常見(jiàn)的錯(cuò)誤原因有:EBADF:fd不是有效的文件描述符EINTR:close()被某個(gè)信號(hào)處理程序中斷EIO:關(guān)閉文件時(shí)發(fā)生了IO錯(cuò)誤Linux文件IO編程非緩沖文件IO編程04創(chuàng)建/寫/讀示例Linux文件IO編程非緩沖文件IO編程04創(chuàng)建/寫/讀示例測(cè)試結(jié)果非緩沖文件IO使用描述符(實(shí)際上一個(gè)整數(shù))關(guān)聯(lián)一個(gè)打開(kāi)的文件,而緩沖文件IO使用文件流指針FILE*來(lái)關(guān)聯(lián)一個(gè)已經(jīng)打開(kāi)的文件;文件結(jié)構(gòu)FILE體內(nèi)部成員一般不需要關(guān)注,編程時(shí)只通過(guò)fopen得到的FILE*類型指針來(lái)進(jìn)行后面的fread,fwrite,fseek,ftell,fclose等函數(shù)進(jìn)行操作。Linux文件IO編程緩沖文件IO編程04主要函數(shù)文件結(jié)構(gòu)指針fopen(打開(kāi))、fread(塊讀)、fwrite(塊寫)、fclose(關(guān)閉)、fseek(調(diào)整讀寫位置),ftell(查詢當(dāng)前文件讀寫位置值);fgtc(單字符讀)、fgets(讀取字符串)、fptc(單字符寫)、fputs(字符串寫);Linux文件IO編程緩沖文件IO編程04fopen函數(shù)頭文件:#include<stdio.h>原型:FILE*fopen(constchar*path,constchar*mode);功能:打開(kāi)一個(gè)現(xiàn)有文件或創(chuàng)建一個(gè)新文件

參數(shù):path字符串包含欲打開(kāi)的文件路徑及文件名;

mode字符串則代表著流形態(tài);"r":以只讀方式打開(kāi)文件,該文件必須存在。

"r+":以可讀寫方式打開(kāi)文件,該文件必須存在。

“w”:只寫方式打開(kāi)文件,若文件存在則文件長(zhǎng)度清為0,即清空文件;

若文件不存在則建立該文件。

“w+”:打開(kāi)可讀寫文件,若文件存在則文件長(zhǎng)度清為零,即清空文件;

若文件不存在則建立該文件。“a”:以追加只寫文件,若文件不存在,則會(huì)建立該文件,

如果文件存在,寫入的數(shù)據(jù)會(huì)被加到文件尾,即文件原先的內(nèi)容會(huì)被保留。

"a+":以追加方式可讀可寫方式打開(kāi)文件,若文件不存在,則會(huì)建立該文件,

如果文件存在,寫入的數(shù)據(jù)會(huì)被加到文件尾后,即文件原先的內(nèi)容會(huì)被保留。返回值:非NULL:打開(kāi)成功,值是指向該流的文件指針NULL:打開(kāi)失敗,錯(cuò)誤代碼存在全局的errno變量中。調(diào)用f

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論