【Linux】linux基礎開發工具(二) 編譯器gcc/g++、動靜態庫感性認識、自動化構建-make/Makefile

文章目錄

  • 一、gcc/g++介紹
  • 二、gcc編譯選項
    • 預處理
    • 編譯
    • 匯編
    • 鏈接
    • 三個細節
  • 三、動靜態庫感性認識
    • 動靜態庫的優缺點
  • 四、自動化構建-make/Makefile
    • 背景知識
    • 初步上手Makefile
    • makefile的推導過程
    • makefile語法


一、gcc/g++介紹

我們之前介紹了編輯器vim,可以讓我們在linux上linux系統里都默認安裝了gcc和g++。gcc只能編譯C語言,g++主要編譯C++,也可以編譯C語言。

gcc編譯文件后默認會生成可執行文件a,out,示例如下:

在這里插入圖片描述

但是gcc編譯文件的最佳實踐不是生成默認的a.out,而是用-o選項,生成我們自己命名的可執行文件。

在這里插入圖片描述

當我們需要編譯多個文件生成一個可執行程序時,可以用下面的格式,反正記住-o選項后面緊跟可執行文件名就不會錯了。

在這里插入圖片描述

二、gcc編譯選項

在這里插入圖片描述

因為gcc支持分步驟編譯代碼,所以我們可以通過實踐來看各階段編譯器做了什么,這里就需要我們通過gcc的不同的編譯指令來查看。gcc編譯文件格式大致如上,小編來挨個介紹:

預處理

(進?宏替換/去注釋/條件編譯/頭?件展開等)

在這里插入圖片描述

-E選項是指從現在開始gcc開啟翻譯工作,當把預處理進行完畢后就停下來,所以hello.i文件里的內容就是hello.c文件經過預處理后的結果,下面我們通過vim來分析預處理階段編譯器會完成的工作:

在這里插入圖片描述

頭文件展開就是指gcc把已經在系統里安裝好了的頭文件內容拷貝一份到指定文件中,不如stdio.h就在系統的如下路徑:

在這里插入圖片描述

條件編譯本質就是通過宏的定義與否對代碼進行裁剪。操作系統的內核裁剪就可以通過條件編譯來實現。

編譯

(將C語言翻譯為匯編語言)

在這里插入圖片描述

-S選項是指從現在開始gcc開啟編譯工作,當把編譯進行完畢后就停下來

匯編

(將匯編語言翻譯為機器可識別二進制代碼)

在這里插入圖片描述

-c選項是指從現在開始gcc開啟匯編工作,當把匯編進行完畢后就停下來
這里的hello.o叫做可重定位目標二進制文件,因為它還無法被直接執行,因為頭文件只包了相關庫函數的聲明(如printf),庫函數是實現在對應的庫里,所以經過匯編后的文件還需要在鏈接期間和相關庫進行鏈接,才能形成可執行文件。
所以在鏈接之前編譯器只會翻譯我們自己寫的代碼。

鏈接

(?成可執??件或庫?件)

在這里插入圖片描述

鏈接指令不需要加額外的選項,直接-o就行了。
我們前面已經初步介紹了.o文件不可執行的原因,因為還需要鏈接這個步驟,那么接下來小編就來介紹鏈接到底做了什么讓.o文件變成了可執行文件。首先.o文件里除了庫函數以外的文件都已經被翻譯成了二進制代碼,而庫函數只是在頭文件里有聲明,沒有具體實現,所以在.o文件里庫函數調用那里是沒有填要調用函數的地址的,只有在鏈接期間.o文件和庫函數鏈接上了庫函數那里才能填上具體要調用庫函數在庫里的地址,因為庫是一組預先編譯好的代碼集合,所以填上地址后當代碼執行到對應庫函數時會跳轉到庫里對應的地址實現庫函數然后再返回繼續執行后續的代碼。所以這里也可以解釋為什么.o文件叫做可重定位二進制文件。

三個細節

1、有了上面的認識,所以我們以后要編寫代碼,必須要提前下載好頭文件和庫,linux下系統會自動幫我們下好,windows下我們在下載IDE時需要勾選相關選項下載。
2、庫的出現是為了讓程序員直接使用,提高開發效率。C++11 C++17 之類的更新本質就是在庫里添加了新的方法或者改變了編譯器的語法規則。
3、庫的分類如下圖所示,庫的名字一般是去掉前綴lib,去掉后綴.so或.a后,剩下的就是庫的名字。

在這里插入圖片描述

三、動靜態庫感性認識

靜態庫是指編譯鏈接時,把庫?件的代碼全部加?到可執??件中,因此?成的?件?較?,但在運?時也就不再需要庫?件了。其后綴名?般為“.a”
動態庫與之相反,在編譯鏈接時并沒有把庫?件的代碼加?到可執??件中,?是在程執?時由運?時鏈接?件加載庫,這樣可以節省系統的開銷。

動靜態庫和動靜態鏈接之間的聯系:庫是鏈接的對象,無論是靜態庫還是動態庫,都是在鏈接過程中為程序提供所需的代碼和功能,鏈接是將庫與應用程序結合起來的操作。

前面我們認識到鏈接分為靜態鏈接和動態鏈接,我們看下面這個案例可以知道編譯器默認采用動態鏈接的方式生成可執行程序。我們用file來查看編譯生成的可執行文件的詳細屬性。
ldd可用來查看一個可執行程序依賴的庫。

在這里插入圖片描述

如果我們想讓編譯器采用靜態鏈接的方式生成可執行程序,需要加一個-static選項。

在這里插入圖片描述

但是實踐操作系統會提示編譯失敗,因為我們的系統里沒有安裝c/c++的靜態庫,在cnetos下安裝靜態庫的指令如下:
sudo yuminstall -y glibc-static
sudo yum install -y libstdc++-static

動靜態庫的優缺點

動態鏈接:(類比網吧)
需要的方法需要跳轉到庫里去執行
優點:節省資源
缺點:一但丟失,程序無法直接運行
稍微慢一點

靜態鏈接:(類比一人一臺電腦)
把你想要的方法拷貝到你的可執行程序中。
優點:不依賴任何庫,程序自己能獨立運行
缺點:體積大,占據資源多(占據磁盤空間,內存空間)
加載速度慢

四、自動化構建-make/Makefile

背景知識

1、會不會寫makefile,從?個側?說明了?個?是否具備完成?型?程的能?。
2、?個?程中的源?件不計數,其按類型、功能、模塊分別放在若?個?錄中,makefile定義了?系列的規則來指定,哪些?件需要先編譯,哪些?件需要后編譯,哪些?件需要重新編譯,甚?于進?更復雜的功能操作。
3、makefile帶來的好處就是?“?動化編譯”,?旦寫好,只需要?個make命令,整個?程完全?動編譯,極?的提?了軟件開發的效率。
4、make是?個命令?具,是?個解釋makefile中指令的命令?具,?般來說,?多數的IDE都有這個命令,?如:Delphi的make,VisualC++的nmake,Linux下GNU的make。可?,makefile都成為了?種在?程??的編譯?法。
5、make是?條命令,makefile是?個?件,兩個搭配使?,完成項??動化構建。

初步上手Makefile

(注釋Makefile里的內容用#)
首先我們要明確make是linux系統內置的命令,Makefile是一個需要我們自己創建的文件。我們先來感受一下make的便捷:

在這里插入圖片描述

這上面的操作要建立在我們自己創建出makefile文件的基礎上,下面小編來介紹如何創建makefile(makefile本質就是編寫依賴關系和依賴方法):

在這里插入圖片描述

我們看上面的樣例,前兩行就是編譯源文件需要在makefile寫的依賴方法。
后三行表示移除生成的可執行文件(項目清理),.PHONY表示跟在它后面的被修飾的目標是一個偽目標,偽目標的特點是總是會被執行,而且依賴文件列表為空。那么什么是不會總是被執行呢,比如我們的code.exe就不是偽目標,當它被make構建出來后,如果源代碼code.c沒更新make編譯器就不會再執行把code.c編一遍,這樣做是為了讓編譯工作高效一些,因為重復編譯會浪費資源。所以這里的最佳實踐是可執行程序不需要被.PHONY修飾,clean需要被.PHONY修飾。因為清理工作效率很高,而且清理需要清理徹底。
這里又有一個問題,make是怎么知道code.c是否被編譯過呢?這里就涉及文件的修改時間,我們來看下面:

在這里插入圖片描述

一般只要文件內容改變,文件屬性會跟著改變,因為涉及文件大小的變化,即便文件大小沒變,modify本身也是文件屬性,修改文件內容modify一定會被更改,所以change會隨著modify的改變而改變。如果我們修改文件權限的話就只有change改變。
編譯器判斷源文件是否被編譯過就是比較源文件和它的可執行文件的文件內容修改時間哪個更新,如果源文件更新編譯器就會編譯源文件,如果可執行文件更新說明源文件已經被編譯過了,而且源文件沒有被修改,那么就不會重新編譯。因為一開始只有源文件,所以兩者的modify時間一定有先有后,不可能重疊。

在這里插入圖片描述

所以被.PHONY修飾過的文件總是被執行的原理就是讓make忽略源文件和可執行文件之間modify時間的對比,只要make就會執行依賴方法。

make指令默認只會形成一個目標文件,就是make在makefile里從上到下掃描遇到的第一個目標文件,如果我們要指定make其他文件就需要在make指令后面跟上其他目標文件的文件名。我們在工程中的最佳實踐是把要生成的可執行文件放前面,clean放后面。

makefile的推導過程

make根據依賴關系對makefile進行正向解析,解析過程中將依賴方法依次入棧,解析到末尾依次將依賴方法出棧并執行依賴方法,就可完成單次可執行程序的翻譯。

在這里插入圖片描述

但是我們實際上是不會把編譯過程拆分的這么細的,我們平時的最佳實踐是把多個源文件都翻譯成.o文件,然后將多個.o文件與庫做鏈接生成最后的可執行程序。我們之前的例子只有一個源文件,所以直接將源文件翻譯成可執行程序也沒有任何問題。
補充:gcc的-S -c選項如果后面不跟-o指定文件的話會默認生成同名的.s和.o文件,如code.c會生成code.o。

在這里插入圖片描述

makefile語法

前面我們編寫makefile是直接將方法和文件寫在makefile里,不過在實際工程中喜歡將它們設定義為變量,所以就會涉及一系列語法,小編來一一介紹。

  • @

(關閉指令回顯)
我們前面在make 和 make clean之后系統會把具體指令顯示出來,如果我們不想讓他顯示就在makefile的指令前面加上@

在這里插入圖片描述
在這里插入圖片描述

  • $

(取這個符號后面的括號里變量的內容)

在這里插入圖片描述

有了這個符號我們在makefile里編寫指令就不用再出現具體的文件和指令了,我們只用寫出通用的makefile,只要想改變某個變量的內容一鍵替換就行了,類似于宏和全局變量。注意每個$()之間要用空格隔開。示例如下:

在這里插入圖片描述

  • $@、$^

($@代表:左邊的內容,$^代表:右邊所有內容)
$^可以包括:右邊所有文件,只是這里只有一個文件。

在這里插入圖片描述

第一次優化:
我們之前介紹說先把源文件翻譯成目標文件然后再整體鏈接成可執行文件,所以我們這里也按這個思路優化一下makefile:

在這里插入圖片描述

  • wildcard函數

(獲取當前目錄下所有以.c結尾的源文件)
如果我們有很多源文件時,SRC=后面要把源文件挨個寫出來,很麻煩,所以這里引入wildcard函數(touch file{1…10}.c 表示一次性創建file1.c到file10.c 10個文件):

在這里插入圖片描述
第二次優化:

我們已經可以把一次性所有,c文件獲取到全部翻譯成.o文件了,可是我們目前還無法一次性獲取所有.o文件,那么我們要把所有.o文件鏈接為可執行程序就要挨個將.o文件寫一遍嗎?并非如此,下面這條指令可以簡化我們的工作:

在這里插入圖片描述

它可以將SRC里的所有.c 文件替換為.o文件然后將所有.o文件放到OBJ里。

在這里插入圖片描述
一步登天:
在這里插入圖片描述

這是我們要構建多個文件時makefile的最終形態,我們先提前科普幾個概念:
$(OBJ): $(SRC):
$(OBJ) 中每個.o 文件的生成,都依賴于 $(SRC) 中所有 .c 文件,大部分場景這種粗暴的依賴方式都用不到,而鏈接時是$(BIN): $(OBJ),需要由多個$(OBJ)里的目標文件鏈接成一個在$(BIN)里的可執行程序,所以鏈接時符合這個依賴關系。
%.o:%.c
任何 .o 文件的生成,都依賴于同名的 .c 文件,這個就正好符合我們后面會介紹的將源文件翻譯成目標文件的場景。
$^
將:右邊的所有文件一次性交給gcc來編譯。
$<
將:右邊的所有文件一個一個的依次交給gcc來編譯,gcc一次只會編譯一個文件。

在這里插入圖片描述

因為編譯源文件到目標文件需要一個一個文件單獨編譯,所以不能用$(BIN): $(OBJ)
依賴關系和$^,它們是用來一次性make多個文件的。最后鏈接操作符合我們上面介紹的規則。依賴方法執行完后還可以echo一句提示來讓用戶知道make具體做了哪些工作。

以上就是小編分享的全部內容了,如果覺得不錯還請留下免費的關注和收藏如果有建議歡迎通過評論區或私信留言,感謝您的大力支持。
一鍵三連好運連連哦~~

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91367.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91367.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91367.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CentOS 7 上使用 Docker 安裝 Jenkins 完整教程

目錄 前言 準備工作 系統要求 檢查系統信息 更新系統 安裝Docker 第一步:卸載舊版本Docker(如果存在) 第二步:安裝必要的軟件包 第三步:添加Docker官方倉庫 第四步:安裝Docker CE 第五步:啟動Docker服務 第六步:驗證Docker安裝 第七步:配置Docker用戶權限…

30.【.NET8 實戰--孢子記賬--從單體到微服務--轉向微服務】--單體轉微服務--公共代碼--用戶上下文會話

在前面的文章中&#xff0c;我們會看到使用ContextSession來獲取當前用戶的UserId和UserName。這篇文章我們就一起來看看如何實現ContextSession。 一、ContextSession的實現 我們在公共類庫SP.Common中創建一個名為ContextSession的類&#xff0c;用于獲取當前請求的用戶信息。…

BaseDao

#### 10.1 DAO概念> DAO&#xff1a;Data Access Object&#xff0c;數據訪問對象。 > > Java是面向對象語言&#xff0c;數據在Java中通常以對象的形式存在。一張表對應一個實體類&#xff0c;一張表的操作對應一個DAO對象&#xff01;>> 在Java操作數據庫時&a…

USRP捕獲手機/路由器數據傳輸信號波形(中)

目錄&#xff1a; USRP捕獲手機/路由器數據傳輸信號波形&#xff08;上&#xff09; USRP捕獲手機/路由器數據傳輸信號波形&#xff08;中&#xff09; USRP捕獲手機/路由器數據傳輸信號波形&#xff08;下&#xff09; 三、雙工通信信號捕獲 3.1 信號接收系統 5805e6Hz&a…

使用 Kiro AI IDE 3小時實現全棧應用Admin系統

Hello&#xff0c; 大家好&#xff0c;我是程序員海軍, 全棧開發 |AI愛好者 &#xff5c; 獨立開發。 之前我是采用Node生態開發的大模型以及MCP Server,大模型開發的生態主要是Python語言&#xff0c;為了更好的學習大模型開發&#xff0c;于是開了新坑。開始學習Python, 以及…

瀏覽器pdf、image顯示

瀏覽器地址欄 pdf data:application/pdf;base64, data:application/pdf;base64,JVBERi0xLjcKJeLjz9MKMjMgMCBvYmoKPDwv image data:image/jpeg;base64, data:image/jpeg;base64,/9j/4Q3fRXhpZgAATU0AKgAAAAgABwE

《Linux運維總結:銀河麒麟V10 SP3啟動docker容器報錯permission denied》

總結&#xff1a;整理不易&#xff0c;如果對你有幫助&#xff0c;可否點贊關注一下&#xff1f; 更多詳細內容請參考&#xff1a;Linux運維實戰總結 一、環境信息 二、背景 1、使用docker啟動一個nginx容器&#xff0c;報錯信息如下&#xff1a; docker: Error response from…

PDF源碼解析

PDF源碼解析打開PDF解析PDF?0. 文件頭關鍵信息解析技術原理圖解文件頭的重要性實際文件結構示例開發者注意事項歷史背景1. 根目錄整體結構關鍵字段解析核心概念解釋實際應用場景完整對象關系圖技術總結2. 頁面樹對象結構關鍵字段解析頁面樹工作原理技術要點總結實際應用3. 圖像…

java開閉原則 open-closed principle

基本知識 1.核心思想&#xff1a;面向抽象編程 2.基本內涵&#xff1a;對修改關閉&#xff0c;對擴展開放 3.要求&#xff1a;盡可能不修改源碼而是增加新功能 例子 以spring5核心原理與30個類手寫實戰中的為例 package com.gupaoedu.vip.design.principle.openclose;/*** Crea…

擁抱智慧物流時代:數字孿生技術的應用與前景

概述 在數字經濟全面推進的當下&#xff0c;物流行業正經歷著前所未有的智能化升級。作為新一代信息技術的重要代表&#xff0c;數字孿生技術正悄然改變著物流的運作方式和決策模式。所謂數字孿生&#xff0c;是指在虛擬空間中創建與現實物流系統高度一致的數字模型&#xff0…

libnest2d-頭文件分析-libnest2d.hpp-幾何類型-策略類型-參數配置

libnest2d 庫的主頭文件&#xff0c;定義了一個用于 二維不規則形狀自動排樣&#xff08;Nesting&#xff09; 的C接口。以下是詳細解析&#xff1a;1. 頭文件結構 (1) 防止重復包含 #ifndef LIBNEST2D_HPP #define LIBNEST2D_HPP // ... #endif // LIBNEST2D_HPP確保頭文件只被…

【Docker】部署Docker可視化管理面板Dpanel

一、DPanel 介紹 1.1 DPanel 簡介 DPanel 是一款專為 Docker 設計的可視化管理面板&#xff0c;旨在降低容器、鏡像及相關資源的管理門檻。通過簡潔直觀的圖形化界面&#xff0c;即使是對 Docker 不熟悉的用戶&#xff0c;也能輕松上手&#xff0c;實現容器化應用的高效部署與管…

GCC/G++ + Makefile/make 使用

一、gcc\g編譯器 什么是gcc和g&#xff0c;它們的區別又是什么&#xff1f; gcc編譯器是專門用來編譯C語言的&#xff0c;而g編譯器既可以編譯C語言又可以用來編譯C&#xff0c;但是主要還是用來編譯C。 我們都知道代碼形成可執行程序都是需要經過預處理、編譯、匯編和鏈接這四…

重復文件查找工具:DataSecurity Plus 全面提升企業文件管理效率

企業日常運營經常會出現這樣的場景&#xff1a;員工在文件傳輸、共享與備份過程中&#xff0c;因操作不當或系統設置問題&#xff0c;出現文件重復存儲&#xff1b;跨部門協作時&#xff0c;相同的項目資料可能被多次保存&#xff1b;隨著數據遷移與系統升級&#xff0c;重復文…

【軟件架構】資源池架構設計中的三種主流模式

在資源池架構設計中&#xff0c;三種主流模式——集中式、分布式和混合式資源池——各有其獨特的優勢、劣勢和適用場景。理解它們的區別對于設計高效、可靠和可擴展的系統至關重要。 下面是對這三種模式的詳細分析和比較&#xff1a;集中式資源池 核心概念&#xff1a; 將所有計…

Java 類加載沖突

在某次線上部署過程中&#xff0c;我們遇到了一個十分詭異的問題&#xff1a;同樣的應用&#xff0c;在 ext3 文件系統下運行正常&#xff0c;但部署到 ext4 文件系統下卻出現了如下異常&#xff1a;The methods class, com.ctc.wstx.io.StreamBootstrapper, is available from…

VMware安裝 統信UOS桌面專業版

前言 近年來&#xff0c;隨著Linux發行版在開發者、企業環境中的應用逐漸增多&#xff0c;國產操作系統統信UOS&#xff08;基于Debian&#xff09;因其良好的圖形化界面和本地化支持&#xff0c;成為不少用戶體驗Linux生態的選擇之一。本文將以VMware Workstation Pro 17為例…

SAP Datasphere 02 - 建模

創建連接創建到 HANA Cloud 實例的連接查看 HANA Cloud實例連接 Endpoint創建連接選擇連接類型配置連接信息&#xff0c;授權方式&#xff0c;用戶名密碼等配置連接名稱驗證連接導入數據源表創建目錄 Hotel &#xff0c;放置建模對象點擊新建目錄&#xff0c;導入遠程表選擇數據…

isasssim robotiq夾爪踩坑

1. usd導出urdf失敗在isasssim的仿真中的 robotiq 2f夾爪&#xff0c;首先目前4.5asset里面的usd不能直接轉urdf&#xff0c;因為模型中存在 “閉環連接”&#xff0c;即某個部件&#xff08;或關節&#xff09;同時與兩個及以上的父部件相連&#xff0c;形成類似 “三角形” 的…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | Pokedex(寶可夢圖鑒)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— Pokedex組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 結合 PokeAPI 來創建一個炫酷的寶可夢圖鑒應用。通過這個…