370 likes | 583 Views
彈性的專案管理工具. MakeFile. 程式編譯流程. 手動用 gcc joe@joe-hp-mini : ~/hello$ gcc hello.c -o hello joe@joe-hp-mini : ~/hello$ ls hello hello.c 使用 Makefile joe@joe-hp-mini : ~/hello$ vim Makefile joe@joe-hp-mini : ~/hello$ make cc hello.c -o hello joe@joe-hp-mini : ~/hello$.
E N D
彈性的專案管理工具 MakeFile
程式編譯流程 • 手動用 gcc joe@joe-hp-mini:~/hello$ gcc hello.c -o hello joe@joe-hp-mini:~/hello$ ls hello hello.c • 使用 Makefile joe@joe-hp-mini:~/hello$ vim Makefile joe@joe-hp-mini:~/hello$ make cc hello.c -o hello joe@joe-hp-mini:~/hello$ hello: hello.c
Makefile 內容格式 • makefile 包含多個 rules,一個 rule 長的像下面 TARGET … : PREREQUISITES … <TAB> COMMAND <TAB> … <TAB> … • 當 PREREQUISITES比 TARGET新時,或當 TARGET不存在時,則執行 COMMAND • make 預期 TARGET rule 會產生 TARGET 檔案 必要條件 目標 命令們 COMMAND 勒?為何不寫也會編譯? 前一個例子的 Makefile hello: hello.c gcc hello.c -o hello # 因為有內定規則,明寫則長這樣
Makefile 內容格式 • 不會產生 TARGET 的 rule • 最常見的例子 --> clean • 先做 clean 再產生 hello joe@joe-hp-mini:~/hello$ make clean hello 前一個例子的 Makefile hello: hello.c gcc hello.c -o hello clean: rm -f hello
程式編譯流程 hello.c hello.s hello.o hello
hello.c 產生 需要 hello.s 產生 需要 joe@joe-hp-mini:~/hello$ gcc -S hello.c joe@joe-hp-mini:~/hello$ ls hello.c hello.s joe@joe-hp-mini:~/hello$ gcc -c hello.s joe@joe-hp-mini:~/hello$ ls hello.c hello.o hello.s joe@joe-hp-mini:~/hello$ gcc hello.o -o hello joe@joe-hp-mini:~/hello$ ls hello hello.c hello.o hello.s joe@joe-hp-mini:~/hello$ hello.o 產生 需要 hello 多餘的中間檔? Makefile hello: hello.o gcc hello.o -o hello hello.o: hello.s gcc -c hello.s hello.s: hello.c gcc -S hello.c
有多份原始碼檔案的程式 Complex.hpp • 缺點?? • 當 Complex.cpp 被修改,main.cpp 仍然被重新編譯一次 main.cpp Complex.cpp main Makefile main: main.cpp Complex.cpp g++ main.cpp Complex.cpp -o main
有多份原始碼檔案的程式 如果改了 Complex.cpp呢?? 程式僅重新編譯 Complex.cpp Complex.hpp main.cpp Complex.cpp main.o Complex.o 幹嘛大費周章寫這麼複雜?? 假設你有一個一千個檔案的 project!!! main Makefile main: main.oComplex.o g++ main.oComplex.o -o main main.o: main.cpp g++ -c main.cpp Complex.o: Complex.cpp g++ -c Complex.cpp
有多份原始碼檔案的程式 Complex.hpp main.cpp Complex.cpp main.o Complex.o main 如果改了 Complex.hpp 呢?? 程式並不會重新編譯 Makefile main: main.oComplex.o g++ main.oComplex.o -o main main.o: main.cpp g++ -c main.cpp Complex.o: Complex.cpp g++ -c Complex.cpp
有多份原始碼檔案的程式 Complex.hpp main.cpp Complex.cpp main.o Complex.o main 如果改了 Complex.hpp 呢?? 程式並不會重新編譯 Makefile main: main.oComplex.o g++ main.oComplex.o -o main main.o: main.cpp Complex.hpp g++ -c main.cpp Complex.o: Complex.cpp Complex.hpp g++ -c Complex.cpp
Make 的樹狀相依 • 當 make main 時,以下的 makefile 會以 main 為首展開成這樣的樹狀圖。 • 他會由下到上的把整個樹狀圖的每個 node 檢查一次,判斷是否要執行 Commands。 main main.o Complex.o main.cpp Complex.hpp Complex.cpp Complex.hpp main: main.oComplex.o g++ main.oComplex.o -o main main.o: main.cpp Complex.hpp g++ -c main.cpp Complex.o: Complex.cpp Complex.hpp g++ -c Complex.cpp
有多份原始碼檔案的程式 Makefile main: main.o Complex.o g++ main.o Complex.o -o main main.o: main.cpp Complex.hpp g++ -c main.cpp Complex.o: Complex.cpp Complex.hpp g++ -c Complex.cpp clean: rm -f main.o Complex.o main
可不可以不要自己寫 Makefile • 有許多工具可以自動生成 Makefile • cmake • autotools • 有許多 IDE 骨子裡也是靠 Makefile 管理 project 的編譯流程 • eclipse • dev-c++ • codeblock • ede
指令的參數、文字處理指令、搜尋指令 More OnUnix Commands
參數的形式 • ls -a • 列出所有檔案(包含 . 開頭的檔案) • ls -l • 以長格式列出檔案 • 同時使用上述兩個 option ls -a -l ls -al ls --all --format=long
命令列的檔名 • 使用萬用字元匹配檔名 • ls –l *.cpp • mv *.jpg mydir/ • rm output* • Unix 不明分主、副檔名 • cp *.* ../ • cp * ../ 只會複製包含 . 的檔名 ( e.g. README 或 hello ) 這樣才對,但我們還漏了什麼?
更多檔名匹配方式 • 多層目錄 • rm ~/*/*.txt • 會刪掉 ~/dir1/file.txt ~/dir2/file2.txt … • 不會刪掉 ~/dir1/dir3/file3.txt ~/dir4/ • 選擇性匹配 • mv comic[1-9][1-9].jpg comics • echo file{1,2,3} * 不能匹配 / 一定要 .txt 結尾
檔案的搜尋 • find暴力搜尋(慢) • find列出目前目錄底下的所有檔案 • find –name ’*.pdf’ • find –name ’*.pdf’ –exec rm {} \; • locate使用做好的 index 搜尋(快) • whereis搜尋執行檔,manpages • which搜尋執行檔(會被執行的)
文字處理指令 • cat將 stdin 或檔案印到 stdout • cat Makefile • cat myfile1 myfile2 • grep搜尋檔案或 stdin 中的文字片段 • grep -n cout ~/*.cpp • grep "hello world" ~/* • head tail印出 stdin 或檔案中的前幾行(末幾行) • head -100 README • wc計算單字數、行數或字元數 • wc -l myfile • tr字符轉換 • tr '\n' ' ' < myfile • sedawk超強文字處理程式
更多文字處理指令 cat grep head tail wc tr xargs sed awk cut sort uniq seq nl expand tac paste join fmt tee
Shell 中的 Piple, RedirectionVariables
Standard IO Standard Output 鍵盤輸入 程序 (process) 螢幕輸出 Standard Input Standard Error fprintf( stderr, ”hello”); 輸出到 stderr fprintf( stdout, ”hello”); 輸出到 stdout printf(”hello”); 輸出到 stdout cout << "bonjour"; 輸出到 stdout cerr << "e rr o"; 輸出到 stderr fscanf( stdin, "%d", &num); 從 stdin取得輸入 scanf( "%d", &num); 從 stdin取得輸入 cin >> num; 從 stdin取得輸入
Pipe(管線) 程序1 (process) Pipe 程序2 (process) Standard Input Standard Output Standard Input Standard Output $ command1 | command2 joseph@green:~$ ls /usr/bin | more joseph@green:~$ ps -ef | grep vim
Redirection(重導向) File1 程序1 (process) File2 Standard Input Standard Output $ command < file1 將 file1 內容作為 stdin $ command > file2將 command 的 stdout 存到 file2(建立新檔) $ command >> file2將 command 的 stdout 存到到 file2(附加) $ command 2> error.log 1> output.log < input.txt stderr stdout
文字處理工具的慣用設計 • 輸入來源通常可以直接指定檔案 • $ command file1 [file2 … ] • 但,有些指令只接受 stdin 的輸入 • $ command < file1 • $ cat file1 [file2 …] | command # 多檔時 • 強迫指令從 stdin 讀取輸入 • $ command | command2 - • 例:ls | vim - 注意此 - 符號
Shell 中的變數與環境變數 • Windows 中也有環境變數
shell 中的變數 • 定義一個變數 joe@joe-hp-mini:~$ MYNAME='Joseph Yen' joe@joe-hp-mini:~$ echo $MYNAME Joseph Yen joe@joe-hp-mini:~$ • 查看有什麼變數 joe@joe-hp-mini:~$ $<tab><tab> $_ $COLUMNS $LANGUAGE $PS2 $BASH $COMP_WORDBREAKS $LINENO $PS4 $bash205 $DIRSTACK $LINES $PWD $bash205b $EUID $LOGNAME $RANDOM …
環境變數 • 並非整個環境共用,僅是能夠向下繼承的變數 joe@joe-hp-mini:~$A=123 joe@joe-hp-mini:~$export B=123 joe@joe-hp-mini:~$bash joe@joe-hp-mini:~$echo A=$A B=$B A= B=123 bash bash2 process1 process1
環境變數 • 並非整個環境共用,僅是能夠向下繼承的變數 joe@joe-hp-mini:~$A=123 joe@joe-hp-mini:~$export B=123 joe@joe-hp-mini:~$C=123 bash joe@joe-hp-mini:~$echo A=$A B=$B C=$C A= B=123 C=123 joe@joe-hp-mini:~$ exit joe@joe-hp-mini:~$ echo A=$A B=$B C=$C A=123 B=123 C= joe@joe-hp-mini:~$ bash bash2
常用的環境變數 • $PATH 執行檔搜尋路徑 • $USERNAM E使用者名稱 • $HOME家目錄 • $LC_ALL語系 • $ export LC_ALL=C • $ export LC_ALL=zh_TW.utf8
Process • 每一個程式執行後都會成為一個 或多個 Process • 每個 Process 都有一個獨立的Process ID
查看系統 Process 某些 Unix 可能不支援這種參數 • ps • ps -ef | grep bash • ps aux | less • pstree • top, htop $ps -ef | grep bash joe 966 965 0 May12 pts/0 00:00:02 bash joe 2864 2835 0 May09 tty1 00:00:00 -bash joe 4133 4103 1 01:27 pts/2 00:00:00 -bash joe 4153 4133 0 01:28 pts/2 00:00:00 grep bash joe 24806 2864 0 May12 tty1 00:00:00 /bin/bash /usr/bin/startx joe 31453 31452 0 May12 pts/1 00:00:05 bash
Proccess 管理 • 將程式丟到背景執行 • $ sleep 1000 & • $ sleep 1000^Z[1]+ Stopped sleep 1000$ bg • 中途結束程式 • $ sleep 1000^C$ • $ sleep 1000^\$ 輸入 Ctrl - Z 讓程式在背景繼續執行 強迫結束 sleep 無法阻止
Process 管理 • 砍掉當掉或不小心忘在背景的 vim $ ps -ef | grep vim joe 984 966 0 May12 pts/0 00:00:00 vim joe 4180 4133 0 01:34 pts/2 00:00:00 grep vim $ kill 984 • 如果當很大,砍不掉(你不要死你不要死) $ kill -9 984 9 是啥?
Process 的控制,一切都是 signal $ man 7 signal 信號 值 動作 說明 --------------------------------------------------------------------- SIGHUP 1 A 在控制終端上是掛起信號, 或者控制進程結束 SIGINT 2 A 從鍵盤輸入的中斷 SIGQUIT 3 C 從鍵盤輸入的退出 SIGILL 4 C 無效硬體指令 SIGABRT 6 C 非正常終止, 可能來自 abort(3) SIGFPE 8 C 浮點運算例外 SIGKILL 9 AEF 殺死進程信號 SIGSEGV 11 C 無效的記憶體引用 SIGPIPE 13 A 管道中止: 寫入無人讀取的管道 SIGALRM 14 A 來自 alarm(2) 的超時信號 SIGTERM 15 A 終止信號 SIGUSR1 30,10,16 A 使用者定義的信號 1 SIGUSR2 31,12,17 A 使用者定義的信號 2 SIGCHLD 20,17,18 B 子進程結束或停止 SIGCONT 19,18,25 繼續停止的進程 SIGSTOP 17,19,23 DEF 停止進程 SIGTSTP 18,20,24 D 終端上發出的停止信號 Process ^\ Signal kernel ^C bg ^Z
進度進度 • 你們現在會了 • Unix Command Line, Shell • Compile and Run a program • Project Manage • 接下來是 • Debug a program • more useful/candy tools