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

----
按`i`進入insert mode

----
第一個程式都是hello world搂

----
打完按`esc`離開insert mode

----
`:`代表進入command mode

----
`:w` 寫入

----
`:wq` 寫入在離開

----
copy paste
ctrl + shift +c/v
copy: `yy` + `p` (y3y)
delete: `dd`(d3d)
----
多行註解
multi comment
normal mode
`gg` 回到開頭
`ctrl`+`v` `shift`+`i` //

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

```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

----
按先按`F12`再`i`

`ctrl`+`shift`+`v`

再按`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
----

[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變身成執行檔過程

from [from source to binary](http://www.slideshare.net/jserv/from-source-to-binary-how-gnu-toolchain-works)
----
Preprocessing 展開header, define, 去除註解

----
編譯產生組合語言(注意-c是小寫c)

try: `objdump -d <executable>`
----
組譯生成物件檔01011
main裡面函式的實做可能在其它.cpp中

----
**動手做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`

`./geom`
----
假使今天有另一個檔案tip.c,
也要用到get_double()函式呢?
----
輕鬆~
把get_double()整個貼上面就好啦
----
great,
那今天是100個檔案都要用到get_double( )?

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


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

另外你每次都得重新編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)
這就是為什麼需要函式原型,因為你的實作在其它地方,但是跟編譯器講函式其實是存在的喔

----
[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

接著終端機執行`gcc gd.o geom.o -o geom`
----
沒法編執行檔
linker無法鏈接get_double的實做
**undefined reference to**

所以當你往後編譯看到undefined reference to大概就是少了那個library的實作 通常是函式庫路徑指錯了
----
recap what we have done

----
如果現在tip.c也要用get_double( )
我們也可以

----
到目前為止,採用的方法是把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

----
[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

還是相安無事並沒有重新編,但這不對 我們明明修改了gd.h
儘管它只是註釋, 如果新增了一個function prototype呢?

----
在Makefile增加gd.h 再make

----
重新編譯

發現有東西被編出來了
----
其實make會去看檔案被修改的時間, geom.c + gd.h 先編出geom.o, geom再和gd.o,產生執行檔geom
因此dependency tree越下面的檔案時間要比較舊,最上面是最新的。 因此當gd.h被修改, make發現gd.h時間居然比geom.o還新於是geom.o需要被重新產生

----

----
我們發現只有跟修改gd.h無關的gd.c不會被重新編譯

----
所以說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

它在/usr/include底下所以用#include<>尖括號
`vim /usr/include/math.h`
啊不過裡面又是一堆.h跟macro歡迎大家跟我講pow或sqrt的function prototype被宣告在哪裡XD

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

----
那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格式)
----


----
`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編譯

#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`