添加编译宏_软件开发——编译链接
對于平常的應用程序開發,我們很少需要關注編譯和鏈接過程。我們平常Xcode開發就是集成的的開發環境(IDE),這樣的IDE一般都將編譯和鏈接的過程一步完成,通常將這種編譯和鏈接合并在一起的過程稱為構建,即使使用命令行來編譯一個源代碼文件,簡單的一句gcc hello.c命令就包含了非常復雜的過程!
正是因為集成開發環境的強大,很多系統軟件的運行機制與機理被掩蓋,其程序的很多莫名其妙的錯誤讓我們無所適從,面對程序運行時種種性能瓶頸我們束手無策。我們看到的是這些問題的現象,但是卻很難看清本質,所有這些問題的本質就是軟件運行背后的機理及支撐軟件運行的各種平臺和工具,如果能深入了解這些機制,那么解決這些問題就能夠游刃有余,收放自如了。
編譯流程分析
現在我們通過一個C語言的經典例子,來具體了解一下這些機制:
在linux下只需要一個簡單的命令(假設源代碼文件名為hello.c):
其實上述過程可以分解為四步:
- 預處理(Prepressing)
- 編譯(Compilation)
- 匯編(Assembly)
- 鏈接(Linking)
預編譯
首先是源代碼文件hello.c和相關的頭文件(如stdio.h等)被預編譯器cpp預編譯成一個.i文件。第一步預編譯的過程相當于如下命令(-E 表示只進行預編譯):
還可以下面的表達
預編譯過程主要處理源代碼文件中以”#”開頭的預編譯指令。比如#include、#define等,主要處理規則如下:
- 將所有的#define刪除,并展開所有的宏定義
- 處理所有條件預編譯指令,比如#if,#ifdef,#elif,#else,#endif
- 處理#include預編譯指令,將被包含的文件插入到該預編譯指令的位置。
- 刪除所有的注釋//和/**/
- 添加行號和文件名標識,比如#2 “hello.c” 2。
- 保留所有的#pragma編譯器指令
截圖個大家看看效果
經過預編譯后的文件(.i文件)不包含任何宏定義,因為所有的宏已經被展開,并且包含的文件也已經插入到.i文件中,所以當我們無法判斷宏定義是否正確或頭文件包含是否正確時,可以查看預編譯后的文件來確定問題。
編譯(compliation)
編譯過程就是把預處理完的文件進行一系列的:詞法分析、語法分析、語義分析及優化后生產相應的匯編代碼文件,此過程是整個程序構建的核心部分,也是最復雜的部分之一。其編譯過程相當于如下命令:
通過上圖我們不難得出,通過命令得到匯編輸出文件hello.s.
匯編(assembly)
匯編器是將匯編代碼轉變成機器可以執行的指令,每一個匯編語句幾乎對應一條機器令。所以匯編器的匯編過程相對于編譯器來講比較簡單,它沒復雜的語法,也沒有語義,也不需要做指令優化,只是根據匯編指令和機器指令的對照表一一翻譯就可以了。其匯編過程相當于如下命令:
或者
或者使用gcc命令從C源代碼文件開始,經過預編譯、編譯和匯編直接輸出目標文件:
鏈接(linking)
鏈接通常是一個讓人比較費解的過程,為什么匯編器不直接輸出可執行文件而是輸出一個目標文件呢?為什么要鏈接?下面讓我們來看看怎么樣調用ld才可以產生一個能夠正常運行的Hello World程序:
鏈接相應的庫
下面在貼出我們的寫出的源代碼是如何變成目標代碼的流程圖:
主要通過我們的編譯器做了以下任務:掃描、語法分析、語義分析、源代碼優化、代碼生成和目標代碼優化
到這我們就可以得到以下的文件,不知道你是否有和我一起操作,玩得感覺還是不錯,繼續往下面看
iOS的編譯器
iOS現在為了達到更牛逼的速度和優化效果,采用了LLVM
- 1.LLVM核心庫:
- LLVM提供一個獨立的鏈接代碼優化器為許多流行CPU(以及一些不太常見的CPU)的代碼生成支持。這些庫是圍繞一個指定良好的代碼表示構建的,稱為LLVM中間表示(“LLVM IR”)。LLVM還可以充當JIT編譯器 - 它支持x86 / x86_64和PPC / PPC64程序集生成,并具有針對編譯速度的快速代碼優化。。
- 2.LLVM IR 生成器Clang: Clang是一個“LLVM原生”C / C ++ / Objective-C編譯器,旨在提供驚人的快速編譯(例如,在調試配置中編譯Objective-C代碼時比GCC快3倍),非常有用的錯誤和警告消息以及提供構建優秀源代碼工具的平臺。
- 3.LLDB項目:
- LLDB項目以LLVM和Clang提供的庫為基礎,提供了一個出色的本機調試器。它使用Clang AST和表達式解析器,LLVM JIT,LLVM反匯編程序等,以便提供“正常工作”的體驗。在加載符號時,它也比GDB快速且內存效率更高。
- 4.libc和libc++:
- libc 和libc++ ABI項目提供了C ++標準庫的標準符合性和高性能實現,包括對C ++ 11的完全支持。
- 5.lld項目:
- lld項目旨在成為clang / llvm的內置鏈接器。目前,clang必須調用系統鏈接器來生成可執行文件。
LLVM采用三相設計,前端Clang負責解析,驗證和診斷輸入代碼中的錯誤,然后將解析的代碼轉換為LLVM IR,后端LLVM編譯把IR通過一系列改進代碼的分析和優化過程提供,然后被發送到代碼生成器以生成本機機器代碼。
編譯器前端的任務是進行:
- 語法分析
- 語義分析
- 生成中間代碼(intermediate representation )
在這個過程中,會進行類型檢查,如果發現錯誤或者警告會標注出來在哪一行。
以上圖解內容所做的是事情和gcc編譯一模模一樣樣!
iOS程序-詳細編譯過程
- 1.寫入輔助文件:將項目的文件結構對應表、將要執行的腳本、項目依賴庫的文件結構對應表寫成文件,方便后面使用;并且創建一個 .app 包,后面編譯后的文件都會被放入包中;
- 2.運行預設腳本:Cocoapods 會預設一些腳本,當然你也可以自己預設一些腳本來運行。這些腳本都在 Build Phases中可以看到;
- 3.編譯文件:針對每一個文件進行編譯,生成可執行文件 Mach-O,這過程 LLVM 的完整流程,前端、優化器、后端;
- 4.鏈接文件:將項目中的多個可執行文件合并成一個文件;
- 5.拷貝資源文件:將項目中的資源文件拷貝到目標包;
- 6.編譯 storyboard 文件:storyboard 文件也是會被編譯的;
- 7.鏈接 storyboard 文件:將編譯后的 storyboard 文件鏈接成一個文件;
- 8.編譯 Asset 文件:我們的圖片如果使用 Assets.xcassets 來管理圖片,那么這些圖片將會被編譯成機器碼,除了 icon 和 launchImage;
- 9.運行 Cocoapods 腳本:將在編譯項目之前已經編譯好的依賴庫和相關資源拷貝到包中。
- 10.生成 .app 包
- 11.將 Swift 標準庫拷貝到包中
- 12.對包進行簽名
- 13.完成打包
總結
以上是生活随笔為你收集整理的添加编译宏_软件开发——编译链接的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jsfor循环终止_js 终止 forE
- 下一篇: 清空临时表oracle,【Oracle相