Linux-Cphp
1. C程序 1.1 最簡單的C程序hello.c 1.2 多個源碼文件 1.3 頭文件(include)和目錄 1.4 C預處理器 1.5 鏈接庫 1.6 共享庫 1.6.1 列出共享庫的依賴關係 1.6.2 ld.so怎樣找到共享庫 1.6.3 環境變量LD_LIBRARY_PATH 2. 編譯管理工具make 2.1 make經常使用選項 2.2 make經常使用變量 2.3 makefile常見的宏 2.4 makefile常規目標 2.5 教程手冊 2.6 GNU autotools 安裝步驟 2.7 configure 經常使用的選項 2.8 Autotools的基礎知識(Gentoo開發人員手冊) 2.9 更多相關連接 3. 調試器gdb 4. Lex和Yacc 5. 腳本語言 6. Java
最基本的生成過程: 代碼,編譯,運行. 編譯就會用到C編譯器。
來自LLVM項目的新的C編譯器clang愈來愈流行;但大部分主流的Unix系統上仍然是GNU C編譯器gcc。
html
#include <stdio.h>
main() {
printf("Hello, World. \n");
}
源碼文件(.c); -o編譯爲可執行文件(.out); 運行
編譯 $ cc hello.c
會產生 a.out 的可執行文件
指定文件名編譯,增長-o選項
$ cc -o hello hello.c
運行 $ ./a.out
java
多個源碼文件(.c); -c編譯爲對象文件(.o); -o鏈接爲可執行文件; 運行
main.c, aux.c ...
使用-c選項給每一個文件生成對應的對象文件
$ cc -c main.c
$ cc -c aux.c
產生對象文件: main.o, aux.o ...
對象文件是一種二進制文件。
使用鏈接器將對象文件組合爲可執行文件
$ cc -o myprog main.o aux.o
更復雜的項目, 更多個源碼文件, 須要使用make
node
保存類型和函數聲明的附加文件,好比stdio.h
Unix默認的include目錄是/usr/include, 編譯器通常就看這裏, 除非你指定其餘地方。
$ cc -c -I /usr/junk/include text.c
使用-I選項指定頭文件路徑
#include <stdio.h>
#include "myheader.h"
<*.h>頭文件在系統路徑;
"*.h"表示頭文件不在系統的include目錄中, 一般表示它與源碼在同一目錄。
python
並非C編譯尋找頭文件, 而是C預處理器(C preprocessor, cpp)。
C預處理器是編譯器在解析程序以前先在源碼上運行的一個東西。
C預處理器會將源碼重寫成一種編譯器能理解的形式,使源碼更易讀(並提供捷徑)。
源碼中的預處理器命令叫作指令(directive), 以#開頭, 分爲以下三種。
inculde文件: #inculde * 使預處理器將整個文件包含進來。
宏定義: #define BLAH something 預處理器會將源碼中全部BLAH替換爲something, 約定宏名爲大寫。
條件: 可用 #ifdef, #if, #endif 來對代碼進行分快。
#ifdef MACRO 指令用於檢查宏MACRO是否已定義;
#if condition 則檢查condition 是否非零。當預處理器發現if語句後的條件爲false時,就不會將#if 和 #endif 之間的代碼交給編譯器。
注:也能夠不在源碼中定義宏,而使用編譯器的-D選項,(-DBLAH=something)(#define BLAH something)
C預處理器並不懂C的任何語法,變量,函數或其餘元素,它只看宏和指令。
Unix上的C預處理器是cpp,也能夠用 gcc -E 來運行,不過通常不多須要單獨運行預處理器。
linux
所謂C庫,就是一些已編譯好的,通用的,可以讓你添加到本身程序的函數。例如不少可執行程序會用到的數學庫...
庫主要實在鏈接的時候(鏈接器從對象文件產生可執行程序時)發揮做用。
默認的庫文件路徑(/usr/lib)
使用編譯器的 -l 選項鍊接庫文件。
例如這裏用到通常的gobject庫文件是libgobject.a, 而庫的名字是gobject. 因此完整的鏈接和編譯以下:
$ cc -o textp textp.o -lgobject
使用 -L 選項指定庫文件路徑
例如庫文件不在常規位置,而在/usr/junk/lib/libcrud.a
$ cc -o testp testp.o -lgobject -L/usr/junk/lib -lcrud
在庫中搜索特定的函數,使用nm命令,nm libjobject.a, (可能要用locate命令查找libjobject.a, 不少發行版會將庫放在/usr/lib特定的子目錄)
git
名稱以.a結尾的庫是靜態庫。
鏈接靜態庫時,鏈接器會將庫文件中的機器碼複製到程序中。最終的可執行程序不須要該庫也能運行。
使用靜態庫的優勢是簡單方便,不依賴環境。缺點也很明顯:github
共享庫便可解決這些問題。引用共享庫的程序只會在須要時纔將該庫加載到內存中。並且多個進程能夠共享內存中同一個共享庫。
使用共享庫的的缺點是管理困難,鏈接複雜。但只需搞定以下問題:web
共享庫和靜態庫一般放在同一個地方,Linux的兩大標準庫目錄/lib, /usr/lib. 其中/lib是不該該包含靜態庫的。
共享庫的名字後綴一般含有.so(意爲共享對象)
$ ldd /bin/bash
linux-vdso.so.1 (0x00007fff77fe7000)
libreadline.so.8 => /usr/lib/libreadline.so.8 (0x00007f60035ec000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f60035e7000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f6003424000)
libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f60033b5000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f6003750000)
考慮到最佳性能和靈活性,可執行程序自己一般不知道它所用的共享庫在哪裏,只知道共享庫名字,或只知道一點點尋找共享庫的提示,如上左邊是共享庫名字。
ld.so(運行時動態鏈接器/加載器)能夠爲程序在運行時找到並加載共享庫。如上ldd輸出的右邊是ld.so找到的庫的位置。
最後一行顯示了ld.so的實際位置。
shell
一般的順序是以下的步驟(1),(2); 特殊狀況纔會使用(0)這個步驟。
注: 如其餘配置文件同樣,ld.so.conf 可能會包含 /etc/ld.so.conf.d中的配置。
標準的庫目錄/lib和/usr/lib是隱式的,即不須要包含在如上的配置文件中。
若是改動了ld.so.conf或者改動了某個共享庫的目錄,須要重建共享庫緩存
$ ldconfig -v
-v 選項會輸出被ldcongfig添加到緩存的目錄的詳細信息和他所監測到的改動。
編譯時指定程序的rpath
$ cc -o test test.o -Wl,-rpath=/opt/obscure/lib -L/opt/obscure/lib -lweird
已編譯的程序可用pathchelf加入不一樣的rpath, 不過最好仍是在編譯時就作好。
環境變量LD_LIBRARY_PATH, 用冒號分隔多個路徑。如非必要,請勿濫用。
* 永遠都不要在啓動文件中或在編譯軟件時設置LD_LIBRARY_PATH。
在沒有源碼,又不能使用patchelf指定路徑,最後的辦法。
但也請將它嵌套進shell腳本里。例如:
#!/bin/sh
LD_LIBRARY_PATH=/opt/crummy/lib
export LD_LIBRARY_PATH
exec /opt/crummy/bin/crummy.bin $@
不使用 LD_LIBRARY_PATH 避免大部分共享庫問題,但還可能遇到應用程序接口API的改變,致使裝好的軟件異常。
最好的解決辦法就是預防,在安裝庫時也使用 -Wl, -rpath, 或者使用靜態庫。
您須要一個名爲makefile的文件來告訴您make該怎麼作。一般,makefile告訴make如何編譯和連接程序。
make有本身內置的規則,當你須要.o文件時,他就會自動去找.c文件,並會對.c文件運行cc -c命令,已達到得到.o文件的目標。
編譯時經過一個 Makefile 文件進行,把這個 Makefile 文件置於 hello.c 同一目錄下.
make命令的使用
大多數的make都支持「makefile」和「Makefile」這兩種默認文件名。
特定的Makefile,你可使用make的「-f」和「--file」參數,如:make -f Make.Linux。
Makefile對格式有要求。
註釋#開頭; 宏定義; 目標:描述; 都頂頭開始,前面不須要空格或tab縮進。
任何真實的命令前面都必需要有tab鍵(不能使用空格鍵)。
$* | 當前目標的基名。 f1.txt, $*就表明這裏的f1 |
$< | 指第一個前置條件。 |
$@ | 寫在規則裏時,表示當前目標。 |
$(@D) $(@F) | 分別指$@目標的目錄名和文件名。 |
$(<D) $(<F) | 分別指$<條件的目錄名和文件名 |
$? | 比目標更新的全部前置條件。 t: p1 p2, 若p2時間戳比t新,$?就表明p2 |
$^ | 指全部前置條件,之間空格分隔。 |
CFLAGS | C編譯器選項。make會將這個選項做爲參數,在將.c變爲.o的階段傳給編譯器。 |
LDFLAGS | 相似CFLAGS, 不過他是在將.o變爲可執行程序的階段傳給編譯器。 |
LDLIBS | 若是使用了LDFLAGS,但不想庫名選項與查找路徑混在一塊兒,能夠將庫名選項寫在這裏。 |
CC | C編譯器,默認是cc。指定爲clang可用 $ make CC=clang |
CPPFLAGS | C預處理器選項。make運行預處理器時,將其做爲參數。 |
CXXFLAGS | GNU使用這個宏做爲C++編譯器選項。 |
clean | 一般會吧全部對象文件和可執行程序都清掉,以便從新構建或者打包軟件。 rm -f … //這個目標無處不在 |
distclean | 它能刪除原包之外的全部東西,包括Makefile。有些可發者更喜歡用 realclean. //GNU autotools所生成的Makefile總會有這個目標。 |
install | 將文件和編譯好的程序放到Makefile認爲適當的地方。可能有風險,最好先用make -n install看看會放在哪裏。 |
test 或 check | 檢驗構建出的東西是否可用。 |
depend | 經過編譯器的-M選項來檢查源碼,以創建依賴關係。 //這是一個不尋常的目標,由於它常常會改動Makefile自身。 |
all | 一般是Makefile的地一個目標 |
https://www.gnu.org/software/make/manual/make.html#Makefile-Contents
Makefile裏主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和註釋。
入門簡易版
https://zhuanlan.zhihu.com/p/47390641
Makefile由淺入深--教程、乾貨
《Makefile文件教程》
https://gist.github.com/isaacs/62a2d1825d04437c6f08
http://www.ruanyifeng.com/blog/2015/02/make.html
Make 命令教程 阮一峯 2015年2月20日
http://www.ruanyifeng.com/blog/2015/03/build-website-with-make.html
使用 Make 構建網站
完整版《GNU Make手冊》
https://www.gnu.org/software/make/manual/make.html
https://seisman.github.io/how-to-write-makefile/introduction.html
跟我一塊兒寫Makefile
http://www.javashuo.com/article/p-kbcqvtyr-md.html
http://www.javashuo.com/article/p-sfuuzyix-mm.html
GNU autoconf 是一套流行的,用於自動產生Makefile的系統。解決跨平臺的問題。
使用此套系統的包都會帶有 configure, Makefile.in, config.h.in文件。其中.in是模板文件。
默認生成的Makefile中的install目標一般使用/usr/local做爲前綴;二進制程序會去到/usr/local/bin. 庫會到/usr/local/lib.
GUN autoconf及不少其餘軟件包的默認前綴都是/usr/local。他是本地安裝軟件的傳統位置。操做系統不會更新/usr/local裏的軟件。因此更新不會是你哪裏的東西丟失。
使用這類帶配置的源碼包安裝步驟大體以下:
01 | 下載: | 官網下載... | |
02-1 | 驗證簽名: | $ gpg --verify *.sig . | 驗證簽名 |
02-2 | 驗證文件: | $ md5sum | 驗證文件. md5sum,sha1sum,sha256sum驗證文件。 |
03-1 | 包內容: | $ tar -tvf | 首先用t選項查看,避免有絕對路徑等問題; |
03-2 | 解包: | $ tar -xvf[壓縮選項] | 再使用xvf[壓縮選項]解包。 |
04 | 查看說明: | $ cat readme | 查看自述文件,install安裝說明等 |
05 | 配置: | $ ./configure | 分析當前系統的特性,而後在Makefile.in文件的基礎上作一些替換,建立出適合本機的構建文件:Makefile |
06-1 | 空跑: | $ make -n | 顯示一次構建所要用到的命令,但並不執行。 |
06-2 | 編譯: | $ make | |
07 | 檢查: | $ make check | 若瞭解程序,也但是嘗試運行生成的可執行文件。 |
08-1 | 空跑: | $ make -n install | 空跑一次,查看安裝那些東西到哪裏。 |
08-2 | 安裝: | $ make install | |
09 | 清理: | $ make clean | 清除編譯鏈接過程當中的一些臨時文件 |
10 | 卸載: | $ make uninstall | 卸載相關應用程序 |
https://devmanual.gentoo.org/general-concepts/autotools/index.html
主要的Autotools組件
Autotools是相關軟件包的集合,當它們一塊兒使用時,消除了建立便攜式軟件所涉及的許多困難。這些工具以及一些相對簡單的上游提供的輸入文件用於爲包建立構建系統。https://devmanual.gentoo.org/general-concepts/autotools/diagram.png
在一個簡單的設置:
...
https://wiki.gentoo.org/wiki/Autotools
Autotools是一個在開源項目中經常使用的構建系統。雖然很常見,但並不是每一個開發人員都喜歡使用自動工具。一些項目試圖避免這種構建系統。
https://devmanual.gentoo.org/eclass-reference/autotools.eclass/index.html
autotools.eclass - 從新生成auto *構建腳本
此eclass用於安全處理須要從新生成其構建腳本的自動化軟件包。若是出現錯誤,全部功能都將停止。
https://wiki.gentoo.org/wiki/Comparison_of_build_systems
構建系統的比較 - 提供各類構建系統的簡要比較。
https://en.wikipedia.org/wiki/List_of_build_automation_software#Build_script_generation_tools
http://www.gnu.org/software/autoconf/
http://www.gnu.org/software/automake/
https://autotools.io/index.html
Autotools Mythbuster Diego Elio 「Flameeyes」 Pettenò 做者和出版商 <flameeyes@flameeyes.com>
Autotools Mythbuster是一個嚴肅的Autotools指南,旨在提供GNU構建鏈中工具的完整集成視圖:autoconf,automake,libtool,pkg-config等。
https://blogs.gentoo.org/lu_zero/2009/03/24/cmake-vs-autotools-a-benchmark/
==============
https://devmanual.gentoo.org/eclass-reference/autotools-utils.eclass/index.html
autotools-utils.eclass - 基於autotools的軟件包的常見ebuild函數
==============
https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Autotools_failures
本指南旨在描述使自動工具沒法在ebuild中運行的常見狀況,並提供有關如何解決這些問題的建議。
介紹
與術語自動工具,咱們一般所說的由GNU工程建立平臺和操做系統無關構建系統,開發工具autoconf,automake和libtool。雖然並不是每一個包裝都同時使用全部包裝,但大多數現代包裝都是這樣作的; 舊的包一般不使用automake和libtool替代; KDE包使用更復雜的構建系統,最終依賴於上述三個軟件。
很容易識別構建系統基於autotools的軟件包:
要構建一個使用基於autotools的構建系統的軟件包,這些工具自己並非絕對須要的:configure腳本是一個簡單的Bourne Shell腳本(一般,但這將在最近討論)並將Makefile.in文件轉換爲簡單的Makefile的make(或者,更多的時候,gmake)。儘管它們是構建軟件的可選項,但解決諸如--as-need構建失敗或自動依賴性等問題所需的補丁一般須要從新運行工具來從新建立腳本和makefile的模板。
本指南不會說明如何使用autotools修復軟件包的錯誤,由於這是一個須要解釋不少內容的普遍主題。有關使用autotools時最多見錯誤的簡單介紹,建議使用autotools文章閱讀最佳實踐。相反,它將描述從新運行autotools致使失敗的常見狀況,不管是在重建腳本仍是在構建時。
================
https://en.wikipedia.org/wiki/GNU_Build_System
https://en.wikipedia.org/wiki/Automake
https://en.wikipedia.org/wiki/Configure_(computing)
https://en.wikipedia.org/wiki/Make_(software)
https://en.wikipedia.org/wiki/Autoconf
https://en.wikipedia.org/wiki/CMake
https://en.wikipedia.org/wiki/Meson_(software)
https://en.wikipedia.org/wiki/Configure_script
https://en.wikipedia.org/wiki/Pkg-config
https://en.wikipedia.org/wiki/GNU_Debugger
https://en.wikipedia.org/wiki/GNU_Bison
https://en.wikipedia.org/wiki/Berkeley_Yacc
https://en.wikipedia.org/wiki/GNU_Compiler_Collection
https://en.wikipedia.org/wiki/List_of_compilers
此頁面旨在列出全部當前編譯器,編譯器生成器,解釋器,轉換器,工具基礎,彙編程序,可自動執行的命令行界面(shell)等。
===========
https://en.wikipedia.org/wiki/List_of_GNU_packages
GNU包列表
GNU工具鏈
主要文章:GNU工具鏈
https://wiki.archlinux.org/index.php/GNU#Build_system
https://www.gnu.org/
構建系統autotools
autoconf
CMake
SCons
gdb 全稱是 GNU Debugger,是 GNU 開源組織發佈的一個強大的 UNIX 下的程序調試工具。
gdb 主要可幫助工程師完成下面 4 個方面的功能:
啓動程序,能夠按照工程師自定義的要求爲所欲爲的運行程序。
讓被調試的程序在工程師指定的斷點處停住,斷點能夠是條件表達式。
當程序被停住時,能夠檢查此時程序中所發生的事,並追索上文。
動態地改變程序的執行環境。
https://wiki.archlinux.org/index.php/Debug_-_Getting_Traces
https://wiki.archlinux.org/index.php/Step-by-step_debugging_guide
https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Backtraces#Introducing_gdb
$ gdb -q /bin/ls
Reading symbols from /bin/ls...
(No debugging symbols found in /bin/ls)
(gdb) set args /usr/share/fonts
(gdb) run
Starting program: /usr/bin/ls /usr/share/fonts
OpenImageIO adobe-source-code-pro cantarell gsfonts misc noto-cjk
TTF adobe-source-han-sans encodings mathjax noto
[Inferior 1 (process 26487) exited normally]
(gdb) q
界面友好的 Eclipse IDE 和 Emacs 系統也是Linux支持的。
想挖掘內存問題和生成統計信息,試試 Valgrind http://valgrind.org
https://www.ibm.com/developerworks/cn/linux/1508_zhangdw_gdb/index.html
使用 GDB 和 KVM 調試 Linux 內核與模塊
若是你要編譯的程序須要讀取配置文件或命令,那你可能要用到Lex和Yacc。這兩個工具是用於製做編程語言的。
Lex, Lexical Analyzar 詞法分析器的生成器,能將文本內容轉換成一個個標記。
GNU/Linux版本叫作flex。可使用編譯器的-ll或-lfl鏈接器標記來鏈接Lex庫。
Yacc, Yet Another Compiler Compiler 語法解析器的生成器,能根據語法來讀取標記。
GNU的解析器是 bison。爲使生成的語法分析器能與yacc兼容,須要執行bison -y。可使用編譯器的-ly鏈接器標記來鏈接Yacc的庫。
https://www.ibm.com/developerworks/cn/linux/sdk/lex/index.html
Yacc 與 Lex 快速入門
Lex
Lex 是一種生成掃描器的工具。掃描器是一種識別文本中的詞彙模式的程序。 這些詞彙模式(或者常規表達式)在一種特殊的句子結構中定義。
Lex 和 C 是強耦合的。一個 .lex 文件(Lex 文件具備 .lex 的擴展名)經過 lex 公用程序來傳遞,並生成 C 的輸出文件。這些文件被編譯爲詞法分析器的可執行版本。
Lex 編程能夠分爲三步:
以 Lex 能夠理解的格式指定模式相關的動做。
在這一文件上運行 Lex,生成掃描器的 C 代碼。
編譯和連接 C 代碼,生成可執行的掃描器。
一個 Lex 程序分爲三個段:
第一段是 C 和 Lex 的全局聲明,第二段包括模式(C 代碼),第三段是補充的 C 函數。
例如, 第三段中通常都有 main() 函數。這些段以%%來分界。
Yacc
Yacc 表明 Yet Another Compiler Compiler。 Yacc 的 GNU 版叫作 Bison。它是一種工具,將任何一種編程語言的全部語法翻譯成針對此種語言的 Yacc 語 法解析器。它用巴科斯範式(BNF, Backus Naur Form)來書寫。按照慣例,Yacc 文件有 .y 後綴。
用 Yacc 來建立一個編譯器包括四個步驟:
經過在語法文件上運行 Yacc 生成一個解析器。
說明語法:
編寫一個 .y 的語法文件(同時說明 C 在這裏要進行的動做)。
編寫一個詞法分析器來處理輸入並將標記傳遞給解析器。 這可使用 Lex 來完成。
編寫一個函數,經過調用 yyparse() 來開始解析。
編寫錯誤處理例程(如 yyerror())。
編譯 Yacc 生成的代碼以及其餘相關的源文件。
將目標文件連接到適當的可執行解析器庫。
如同 Lex 同樣, 一個 Yacc 程序也用雙百分號分爲三段。 它們是:
聲明、語法規則和 C 代碼。
Unix中,全部#!開頭的可執行文本文件都是腳本,後面的路徑是該腳本的解釋器。
#!/usr/bin/python
#!/usr/bin/env python
#!/usr/bin/tail -2
常見的腳本語言
Java跟C同樣都是編譯型語言,他有更簡單的語法和強大的面向對象能力。
多用於Web應用和一些特定的應用。Android應用就一般使用Java來開發的。
Java編譯器分爲兩種:
用於生成機器碼供系統使用的本地編譯器(如C編譯器);
字節碼解釋器(有時也叫虛擬機)使用的字節碼編譯器。在Linux上看到的Java程序都是字節碼。(.class文件)
Java運行時環境(Java Runtime Environment, JRE)包含了運行Java字節碼所需的程序。運行一個字節碼:
$ java file.class
$ java -jar file.jar
(.jar)文件是由一堆.class文件打包而成的字節碼文件。
有時須要將java的安裝路徑設置到JAVA_HOME環境變量中,甚至可能還須要使CLASSPATH變量包含你程序須要的全部class文件目錄。
須要使用(Java Development Kit, JDK)Java開發工具,將.java文件編譯爲字節碼:
$ javac file.java
JDK還包含了jar程序,建立和拆分.jar文件,用法相似tar。