---
# System prepended metadata

title: tea教室02
tags: [tea02, tutorial, tea]

---

tea教室02 
===

[tea教室01問題討論](https://hackmd.io/s/HkNcPw5Il)
[hackfoldr record](http://hackfoldr.org/1ViN2u8YerUjYvCcItW1dtjrkxHafOXotkczGsWyIKMM/https%253A%252F%252Fhackmd.io%252Fs%252FHkNcPw5Il%2523)
[source code](https://github.com/NTHU-TEA/tea_02)

### outline
*    vim使用,Basic linux bash command
*    From Source to Binary :Makefile dive deeper
*    some example : socket


---

*    **vim使用,Basic linux bash command**
*    From Source to Binary :Makefile dive deeper
*    some example: socket


----

### vim使用,Basic linux bash command

 vim模式 | 描述 |
| ------ | ----------- |
| insert mode  | 用key `i` 進入打程式 |
| normal mode | 剛進入的地方 |
| commandline mode  | 執行某些動作 |

https://www.openvim.com/
到行尾shift+4
到開頭 0 


----
 
 
一開始我們在normal mode

![](https://i.imgur.com/VJhE2Am.jpg =320x240)


----

按`i`進入insert mode 
![](https://i.imgur.com/oEaUkWp.jpg =320x240)

----

第一個程式都是hello world搂
![](https://i.imgur.com/2Nn7aGm.jpg =320x240)

----

打完按`esc`離開insert mode
![](https://i.imgur.com/KREeohW.jpg =320x240)

----

`:`代表進入command mode
![](https://i.imgur.com/VLduRG3.jpg =320x240)

----

`:w`   寫入
![](https://i.imgur.com/B8UxMME.jpg =320x240)

----

`:wq` 寫入在離開
![](https://i.imgur.com/Ta1ivUz.jpg =320x240)

----

copy paste
ctrl + shift +c/v
copy: `yy` + `p` (y3y)
delete: `dd`(d3d)

----

多行註解
multi comment
normal mode
`gg` 回到開頭
`ctrl`+`v`  `shift`+`i` //

![](https://i.imgur.com/OUU48wf.png )

uncomment
undo: `u`
find(like ctrl f): / + `n`

----

my vimrc
![](https://i.imgur.com/NRjCYRz.png)

```vim=
set background=dark
set nu
set ic
syntax on
set ignorecase smartcase
set undofile
set undodir=~/.vim/undodir
filetype plugin indent on
set tabstop=4
set softtabstop=4
set expandtab
set cursorline
set cindent
set number
set pastetoggle=<F12>
```




----

**byobu**

`F2` 新增terminal
`F3`,`F4` switch between terminal

`ctrl`+`F6` 刪除terminal

`shift`+`F2`新增水平terminal
`ctrl`+`F2`新增垂直terminal

`shift`+方向鍵 切換


----

**byobu**

`F2` add terminal
`F3`,`F4` switch between terminal

`ctrl`+`F6` delete terminal

`shift`+`F2`add new horizotal terminal
`ctrl`+`F2`add new vertical terminal

`shift`+arrow keys  switch 



----

**縮排vim**
When you what to copy paste someone's code on web site

usually you got this
![](https://i.imgur.com/CncWASl.jpg =320x240)

---- 


按先按`F12`再`i`
![](https://i.imgur.com/AMvGBiW.jpg =320x240)

`ctrl`+`shift`+`v`
![](https://i.imgur.com/9j2rhuO.jpg =320x240)
再按`F12` 離開paste mode
再:wq

:set paste :set nopaste
[ref](http://twed2k.org/viewthread.php?tid=336366#.WHyJ62dq2lM)

[ATOM edittor](https://atom.io/)
sudo dpkg -i atom-64.deb

----
 
**Basic bash command**
Bash background process to foreground `fg`
, (use socket to demo)

`ctrl` + `c` to terminate process

----

![vim cheat sheet](http://blog.vgod.tw.s3.amazonaws.com/wp-content/uploads/2009/12/vim-cheat-sheet-full.png)
[vgod給程式設計師的Vim入門圖解說明](http://blog.vgod.tw/2009/12/08/vim-cheat-sheet-for-programmers/?variant=zh-tw)

---


*    vim使用,Basic linux bash command
*    **From Source to Binary :Makefile dive deeper**
*    some example : socket

---

### From source to Binary:Makefile dive deeper
回憶.c變身成執行檔過程
![](https://i.imgur.com/vlizNGN.png)
from [from source to binary](http://www.slideshare.net/jserv/from-source-to-binary-how-gnu-toolchain-works)

----

Preprocessing 展開header, define, 去除註解
![](https://i.imgur.com/pbxkIBL.jpg)

----

編譯產生組合語言(注意-c是小寫c)
![](https://i.imgur.com/8ZppAVT.jpg)

try: `objdump -d <executable>`

----

組譯生成物件檔01011
main裡面函式的實做可能在其它.cpp中
![](https://i.imgur.com/U3i9WP4.jpg)

----

**動手做hands on**
[original source](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/original)
算兩點距離
`cd ~/tea02/make-example/original`
編譯產生geom.o `gcc -o geom geom.c -l m`

![](https://i.imgur.com/1PUyMUf.jpg)
`./geom`

----

假使今天有另一個檔案tip.c,
也要用到get_double()函式呢?

----

輕鬆~ 
把get_double()整個貼上面就好啦

----

great,
那今天是100個檔案都要用到get_double( )?
![](https://i.imgur.com/8GGLNZf.png  =300x300 )

----

或者把get_double()寫成另外的gd.c, 當其它cpp需要使用只要`#include "gd.c"`請看[version1](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver1)
![](https://i.imgur.com/M6Alof2.jpg)
![](https://i.imgur.com/FXgsUDY.jpg)

----

不過就算這樣,你還是得貼100次 `#include "gd.c"`

![](https://i.imgur.com/iCSqBay.jpg)
另外你每次都得重新編get_double函式, 即使我們不會去修改它。還記得嗎 preprocessing只是把標頭檔展開

----

或者我們事先把gd.c編譯成gd.o就是所謂的函式庫(library)
需要用到get_double()的.c再編譯後再去跟gd.o鏈接(linking)
請看[ver2-prototype](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver2-prototype), 不過geom.c不認得get_double()是什麼啊 於是在最上面要宣告函式原型(Function prototype)

這就是為什麼需要函式原型，因為你的實作在其它地方,但是跟編譯器講函式其實是存在的喔
![](https://i.imgur.com/MSBcv37.jpg)

----

[ver3-empty](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver3-empty)
那如果我們唬爛編譯器, 宣告了function prototype卻沒有函式實作呢? gd.c裡面是空的, 你編了一個空的gd.c

----

gd.c還是能編出gd.o
用objdump反組譯gd.o 其實只加了一些overhead
![](https://i.imgur.com/Bqyvuy7.jpg)
接著終端機執行`gcc gd.o geom.o -o geom`

----

沒法編執行檔
linker無法鏈接get_double的實做
**undefined reference to**
![](https://i.imgur.com/pwNXo4U.jpg)
所以當你往後編譯看到undefined reference to大概就是少了那個library的實作 通常是函式庫路徑指錯了

----

recap what we have done
![](https://i.imgur.com/rPeWNHj.jpg)

----

如果現在tip.c也要用get_double( )
我們也可以
![](https://i.imgur.com/hHyDTlL.jpg)

----

到目前為止，採用的方法是把function獨立成gd.c檔，並且在需要使用的geom.c, tip.c上面宣告function prototype 
`double get_double( char *prompt, double min, double max);//function prototype`

----

如果今天有更多function要用呢? 就要貼很多次function prototype搂?

----

於是有了header標頭檔的存在，幫忙打包function prototype ,比如gd.h
header標頭檔裡面沒有程式碼實作
只把function prototype, 變數的宣告放進去
請看[ver4-header](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver4-header)

----

dependency tree
![](https://i.imgur.com/sfq2TPW.jpg)

----

[ver5-makefile](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver5-Makefile)

formating MakeFile
recipe
`# -*- MakeFile -*- `
make all
Makefile撰寫
``` Make=
# -*- MakeFile -*-                                                                             
#target: dependencies
#   action

all: geom tip 

geom: geom.o gd.o
    gcc geom.o gd.o -o geom -l m

geom.o: geom.c
    gcc -c geom.c

gd.o: gd.c
    gcc -c gd.c

```


今天我們只要生成執行檔geom(目標target)


`# -*- MakeFile -*-`

是把整份文件的格式訂成Makefile格式(有特定的縮排，不能按4次空白鍵 要用`tab`)
```
#target: dependencies
#   action
```
#是註解

目標: 編目標需要的原料(相依檔案們)
    動作(ex: gcc geom.o gd.o -o geom -l m)

```Make=
# -*- MakeFile -*-                                                                             
#target: dependencies
#   action

geom: geom.o gd.o
    gcc geom.o gd.o -o geom -l m
geom.o: geom.c
    gcc -c geom.c

gd.o: gd.c
    gcc -c gd.c
```

GnuMake 會去找第一個目標 `geom`
然後她發現 喔 編geom需要 geom.o ,gd.o
接著又繼續找
要有geom.o 需要 geom.c
要有gd.o 需要 gd.c
直到拆解成原始碼 才不用繼續找下去


----


有多個執行檔要編要打 all
all在這邊不是target 因為它不是一個真的的檔案
只是動作 (make clean, make run也是)

大家可以查查
.PHONY
那不是一個target
代表那不是要編譯出來的target,只是個動作

all: executable1 executable2
`make all`

----

Make不會recompile
Make 只會重新編譯更新時間比較新的(有被修改的檔案)，怎麼做到的呢?
make會從從dependency tree 往回找(下面要時間比較近)
不會重新編所有的東西
geom.o的時間戳記要比gd.c後面(不然會重編)
ex: geom.c修改 再make一次觀察輸出

----

**增加header到Makefile**
當我們新增了功能比如函式add.c , gd.h裡面就要多加function prototype, 我們就需要在Makefile裡面dependency加上gd.h
(如果沒加呢?) 範例[ver6-makeheader](https://github.com/NTHU-TEA/tea_02/tree/master/make-example/ver6-addHeader)

----

好比我們修改gh.h, 比如在gd.h新增亂碼註解之後make
![](https://i.imgur.com/5eSSCWW.jpg)

還是相安無事並沒有重新編,但這不對 我們明明修改了gd.h
儘管它只是註釋, 如果新增了一個function prototype呢?
![](https://i.imgur.com/4r9pJA9.jpg)

----

在Makefile增加gd.h 再make
![](https://i.imgur.com/tSWGVax.jpg)

----

重新編譯
![](https://i.imgur.com/UrxDnE3.jpg)
發現有東西被編出來了

----

其實make會去看檔案被修改的時間, geom.c + gd.h 先編出geom.o, geom再和gd.o,產生執行檔geom
因此dependency tree越下面的檔案時間要比較舊,最上面是最新的。 因此當gd.h被修改, make發現gd.h時間居然比geom.o還新於是geom.o需要被重新產生
![](https://i.imgur.com/PJpxkn9.jpg)

----

![](https://i.imgur.com/eIR11oV.jpg)

----

我們發現只有跟修改gd.h無關的gd.c不會被重新編譯
![](https://i.imgur.com/BdXvvJw.jpg)

----

所以說make只會編有被修改過的檔案, 不會全部重編,這對龐大專案減少編譯時間有一定的幫助。

----

什麼時候Makefile裡要加.h呢?
基本上只要你的.c裡面有 #include "header" 通常 Makefile dependency裡面就要記得加 OOO.h 
不加入#inclde <stdio.h>原因(因為基本上不會去改printf,scanf的內容)

----

所以一開始的 gcc -o geom geom.c -l m真相大白 
geom.c上面#include<math.h> 其實它就是放著 pow.o, 
sqrt.o 這些數學運算的header裡面放著他們的function prototype

----

各位好奇可以在terminal打locate math.h
![](https://i.imgur.com/Nv5AkoO.jpg)
它在/usr/include底下所以用#include<>尖括號
`vim /usr/include/math.h`
啊不過裡面又是一堆.h跟macro歡迎大家跟我講pow或sqrt的function prototype被宣告在哪裡XD


![](https://i.imgur.com/vko8Mox.jpg)

----

至於include什麼.h檔要-lm什麼  可以問男人
比如: `man sqrt`

![](https://i.imgur.com/oPONsr5.jpg)

----

那math.h什麼時候放的?
一開始空空的ubuntu16.04作業系統我打了
```
sudo apt-get update 
sudo apt-get install vim 
sudo apt-get install build-essential
sudo apt-get install libc6-dev
sudo apt-get install manpages
sudo apt-get install manpages-posix 
sudo apt-get install manpages-posix-dev 
sudo apt-get install manpages-dev
```

`libc6-dev` http://packages.ubuntu.com/xenial/libc6-dev
裡面就把pow.o,sqrt.o實作obj放到你的系統資料夾 /usr/lib
或其實它是.a


-l m 相當於代表一整大包比如 pow.o, sqrt.o 

library .a是一堆.o的集合
.a靜態函式庫
.so共享函式庫 靜態函式庫每次被呼叫會產生一個副本 共享函式庫只有一個副本
----


於是lapacke的編譯就真相大白了
``` shell=
g++ -o tea_svd svd_demo.cpp  -I"/home/osboxes/lapack-3.6.1/LAPACKE/include" -L"/home/osboxes/lapack-3.6.1" -llapacke -llapack -lblas -lcblas -lgfortran
```

`-I`:指定 #include header的路徑
`-L`指定.o(library)們的路徑, 這些.o是一些.f被用fortran compilier編成.o的

`-l`:小寫, 剛剛有了路徑 那要找的library名稱是哪一個
我們需要lapacke lapack blas cblas gfortran

而這些.o檔就從我們下載的資料夾或apt-get install liblas之類的來

----

BY 宇賢補充
**為什麼不用-l c就能讓linker連結到stdio.h裡面的printf?**

-l m 相當於代表一整大包比如 pow.o, sqrt.o

那用到printf() scanf()
有#include<stdio.h> 編譯的時候怎麼不用加`-l c`呢?
`gcc -o geom geom.c -l m -l c`?

Ans: 預設
[ref](http://www.programmer-club.com.tw/ShowSameTitleN/c/33367.html)

----

增加make clean
不要每次重新編譯都make clean一次
專案太大要編很久
ps.如果command前面不是打tab而是打4個空白鍵space (Makefile格式)

----

![](https://i.imgur.com/u6rRdlF.jpg)

![](https://i.imgur.com/nwlZTJZ.jpg)

----

`gd.h.gch: GCC precompiled header (version 014) for C`


`make run` 執行程式碼  其實你可以自訂動作 比如`make habonbon` 
facebooc write in c
https://github.com/jserv/facebooc   

.PHONY
那不是一個target
代表那不是要編譯出來的target,只是個動作

----

### some example : [socket](https://github.com/NTHU-TEA/tea_02/tree/master/socket-c)

練習:把socket client跟server包成 Makefile編譯
![](https://i.imgur.com/P6AFwx6.jpg)


#include <header>

c standard library | 描述 | 使用時機 |
| ------ | ----------- |-------------|
| <assert.h>  |  | |
| <float.h> |  | |
|<math.h>  |  | |
| <stdarg.h> |  | |
| <stdlib.h> |  | |
| <ctype.h> |  | |
| <limits.h> |  | |
| <setjmp.h> |  | |
| <stddef.h> |  | |
| <string.h> |  | |
| <errno.h> |  | |
| <local.h> |  | |
| <signal.h> |  | |
| <stdio.h> |  | |
| <time.h> |  | |



**materials to read:**

*about gnu make*
[gnu make](http://itrs.tw/itrs-tutorials/make_tutorial.pdf)--Scott
[from source to binary](http://www.slideshare.net/jserv/from-source-to-binary-how-gnu-toolchain-works)-jserv
[ELF](https://read01.com/zeG4M7.html)
[靜態動態函式庫](http://sp1.wikidot.com/gnulinker)

*about C*
the C programming language
https://hackmd.io/s/H1KTTZP8l
http://hackfoldr.org/dykc/

https://neal.hackpad.com/ep/pad/static/mSZzBXYoUED
https://embedded2015.hackpad.com/Summer2015--PwYbXEAP7ei

bitwise operator
[兩數值變換](http://adrianhuang.blogspot.tw/2011/08/c.html)

[overflow大力光股價](http://finance.technews.tw/2017/01/10/largan-stock-trouble/)

va_list
http://www.cnblogs.com/dong008259/archive/2012/01/04/2312451.html

*about socket*
https://read01.com/8z4oP3.html
http://blog.linux.org.tw/~jserv/archives/2006_06.html

[function pointer](http://140.116.72.245/~q36991217/allenli/?p=153)

server socket
http://wiki.csie.ncku.edu.tw/embedded/2016q1h3


*about parallel programming*
[Pthread](https://read01.com/5Qo4LP.html)
[SIMD](https://hackmd.io/s/BJOTYoHge)
[concurrent](http://opass.logdown.com/posts/784600-concurrency-series-1-the-road-to-understand-concurrency)


*    linker
http://docs.oracle.com/cd/E19253-01/817-1984/

*    git
http://learngitbranching.js.org/

make 和bash


https://yodalee.blogspot.tw/2017/04/makefile-header.html

[makefile](https://hackmd.io/AzCsDMDYCMIWgJwBZSTkgJgg7I82M4BmARnAEMTgMJzIkg==?both#)



###### tags:  `tutorial` `tea` `tea02`