Linux-C
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
1. C程序
最基本的生成過程: 代碼,編譯,運行. 編譯就會用到C編譯器。
來自LLVM項目的新的C編譯器clang越來越流行;但大部分主流的Unix系統上仍然是GNU C編譯器gcc。
1.1 最簡單的C程序hello.c
#include <stdio.h>
main() {
printf("Hello, World. \n");
}
源碼文件(.c); -o編譯為可執行文件(.out); 運行
編譯 $ cc hello.c
會產生 a.out 的可執行文件
指定文件名編譯,增加-o選項
$ cc -o hello hello.c
運行 $ ./a.out
1.2 多個源碼文件
多個源碼文件(.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
1.3 頭文件(include)和目錄
保存類型和函數聲明的附加文件,比如stdio.h
Unix默認的include目錄是/usr/include, 編譯器一般就看這里, 除非你指定其他地方。
$ cc -c -I /usr/junk/include text.c
使用-I選項指定頭文件路徑
#include <stdio.h>
#include "myheader.h"
<*.h>頭文件在系統路徑;
"*.h"表示頭文件不在系統的include目錄中, 通常表示它與源碼在同一目錄。
1.4 C預處理器
並不是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 來運行,不過一般很少需要單獨運行預處理器。
1.5 連接庫
所謂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特定的子目錄)
1.6 共享庫
名稱以.a結尾的庫是靜態庫。
連接靜態庫時,連接器會將庫文件中的機器碼復制到程序中。最終的可執行程序不需要該庫也能運行。
使用靜態庫的優點是簡單方便,不依賴環境。缺點也很明顯:
- 過多使用靜態庫,會使文件越來越大,占用空間。
- 若庫里的函數更新了,原有程序不會改變,需要重新編譯才能使用到最新的庫函數。
共享庫即可解決這些問題。引用共享庫的程序只會在需要時才將該庫加載到內存中。而且多個進程可以共享內存中同一個共享庫。
使用共享庫的的缺點是管理困難,連接復雜。但只需搞定如下問題:
- 如何列出程序需要的共享庫;
- 程序如何查找共享庫;
- 如何讓程序連接共享庫;
- 常見的共享庫陷阱。
1.6.1 列出共享庫的依賴關系
共享庫和靜態庫通常放在同一個地方,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的實際位置。
1.6.2 ld.so怎樣找到共享庫
通常的順序是如下的步驟(1),(2); 特殊情況才會使用(0)這個步驟。
- (0) 參考環境變量LD_LIBRARY_PATH.(沒有源碼,又不能使用patchelf指定,就可以用這個了)
- (1) 通常首先查找(可執行程序預先配置好的運行時搜索路徑(如果有配置) runtime library search pach, 簡稱rpath);
- (2) 接着,會參考系統緩存/etc/ls.so.cache, 看看該庫是否在常規的位置。這是從緩存配置文件/etc/ld.so.conf中的目錄列表獲取的庫文件名字的快速緩存。
注: 如其他配置文件一樣,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, 不過最好還是在編譯時就做好。
1.6.3 環境變量LD_LIBRARY_PATH
環境變量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, 或者使用靜態庫。
2. 編譯管理工具make
您需要一個名為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鍵(不能使用空格鍵)。
2.1 make常用選項
- -f FILE, 將FILE文件作為makefile。
- -n, 顯示一次構建所要用到的命令,但並不執行。
- -p, 打印make的內部數據庫。
- -d, 打印大量調試信息。
- --trace, 打印跟蹤信息。
2.2 make常用變量
$* | 當前目標的基名。 f1.txt, $*就代表這里的f1 |
$< | 指第一個前置條件。 |
$@ | 寫在規則里時,表示當前目標。 |
$(@D) $(@F) | 分別指$@目標的目錄名和文件名。 |
$(<D) $(<F) | 分別指$<條件的目錄名和文件名 |
$? | 比目標更新的所有前置條件。 t: p1 p2, 若p2時間戳比t新,$?就代表p2 |
$^ | 指所有前置條件,之間空格分隔。 |
2.3 makefile常見的宏
CFLAGS | C編譯器選項。make會將這個選項作為參數,在將.c變為.o的階段傳給編譯器。 |
LDFLAGS | 類似CFLAGS, 不過他是在將.o變為可執行程序的階段傳給編譯器。 |
LDLIBS | 如果使用了LDFLAGS,但不想庫名選項與查找路徑混在一起,可以將庫名選項寫在這里。 |
CC | C編譯器,默認是cc。指定為clang可用 $ make CC=clang |
CPPFLAGS | C預處理器選項。make運行預處理器時,將其作為參數。 |
CXXFLAGS | GNU使用這個宏作為C++編譯器選項。 |
2.4 makefile常規目標
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里主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和注釋。
- 顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
- 隱晦規則。由於我們的make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支持的。
- 變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,這個有點你C語言中的宏,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。
- 文件指示。其包括了三個部分,
- 一個是在一個Makefile中引用另一個Makefile,就像C語言中的include一樣;
- 另一個是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;
- 還有就是定義一個多行的命令。有關這一部分的內容,我會在后續的部分中講述。
- 注釋。Makefile中只有行注釋,和UNIX的Shell腳本一樣,其注釋是用“#”字符,這個就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進行轉義,如:“\#”。
2.5 教程手冊
入門簡易版
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
https://blog.csdn.net/ruglcc/article/details/7814546
https://blog.csdn.net/haoel/article/details/2886
2.6 GNU autotools 安裝步驟
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 | 卸載相關應用程序 |
2.7 configure 常用的選項
- --prefix=directory: 指定安裝位置。
- --bindir=directory: 指定可執行程序位置。
- --sbindir=directory: 指定系統級的可執行程序位置。
- --libdir=directory: 指定庫位置。
- --disable-shared: 不構建共享庫(要看具體什么庫)。
- --with-package=directory: 告訴configure需要用到=directory: 目錄的包。當某個庫不在標准位置時,使用這個選項。但並非所有的configure腳本都能識別這個選項。
2.8 Autotools的基礎知識(Gentoo開發人員手冊)
https://devmanual.gentoo.org/general-concepts/autotools/index.html
主要的Autotools組件
Autotools是相關軟件包的集合,當它們一起使用時,消除了創建便攜式軟件所涉及的許多困難。這些工具以及一些相對簡單的上游提供的輸入文件用於為包創建構建系統。https://devmanual.gentoo.org/general-concepts/autotools/diagram.png
在一個簡單的設置:
- 該autoconf程序configure從任一configure.in或產生一個腳本 configure.ac(見下面的注釋)。
- 該automake程序產生一個Makefile.in來自Makefile.am。
- configure運行 該腳本以Makefile從 Makefile.in文件生成一個或多個文件。
- 該make程序使用Makefile編譯程序。
...
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
2.9 更多相關鏈接
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的軟件包:
- 如果有配置腳本,以及configure.in或configure.ac文件,構建系統基於autoconf ;
- 如果各個子目錄中有一個或多個Makefile.am文件,它也是automake基於;
- 如果有一個ltmain.sh腳本,它也在使用libtool。
要構建一個使用基於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工具鏈
- GNU Binutils - 包含GNU匯編程序(as)和GNU鏈接程序(ld)
- GNU bison - 用於替換yacc的解析器生成器
- GNU構建系統(autotools) - 包含Autoconf,Automake,Autoheader和Libtool
- GNU Compiler Collection - 針對許多編程語言優化編譯器,包括C,C ++,Fortran,Ada和Java
- GNU調試器(gdb) - 一種高級調試器
- GNU m4 - 宏處理器
- GNU make - 為GNU制作程序
https://wiki.archlinux.org/index.php/GNU#Build_system
https://www.gnu.org/
構建系統autotools
autoconf
CMake
SCons
3. 調試器gdb
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 內核與模塊
4. Lex和Yacc
如果你要編譯的程序需要讀取配置文件或命令,那你可能要用到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 代碼。
5. 腳本語言
Unix中,所有#!開頭的可執行文本文件都是腳本,后面的路徑是該腳本的解釋器。
#!/usr/bin/python
#!/usr/bin/env python
#!/usr/bin/tail -2
常見的腳本語言
- Python: 文本處理,數據庫訪問,網絡編程,多線程等,支持者眾多。還有強大的交互模式和一套有組織的對象模型。David M. Beazley, Python Essential Reference, 4th edition (Addison-Wesley, 2009)
- Perl: 是Unix上較為老舊的第三方腳本語言。是編程界的“瑞士軍刀”,近年被Python超越。
- PHP: 超文本處理語言,常用於動態網頁編程。http://www.php.net
- Ruby: 面向對象的愛好者和Web開發者尤其喜歡。http://www.ruby-lang.org
- JavaScript: 有一種實現Node.js,可執行程序是node。
- Emacs Lisp: Lisp語言的一個變種。
- Matlab和Octave: Matlab是一套商業矩陣及數學編程語言和庫。Octave是類似Matlab的免費軟件。
- R: 流行的免費統計分析語言。http://www.r-project.org
- Mathematica: 商業的數學編程語言和庫。
- m4: 宏處理語言,常見與GNU autotools。
- Tcl: 工具命令語言,是一種簡單的腳本語言,其擴展有圖形界面的Tk和自動化工具Expect。http://tcl.tk
6. Java
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。