NJU-計算機系統基礎PA0-搭建開發環境

PA0 - 世界誕生的前夜: 開發環境配置

 

預計耗時 10小時

1. 實驗要求在一臺物理機上直接安裝Debian10系統,這樣做的好處是能鍛鍊裝系統的能力,麻煩的地方是最好準備一臺不使用的地方,以及做好踩坑的準備。使用虛擬機或者雲服務器能少走一些彎路。還有一種方法是win10 WSL系統的使用。不過是Ubuntu 20

 

2. 接下來,實驗要求熟悉終端操作界面

Now you can see how much disk space Debian occupies. Type the following command:

df -h

 

3. 接下來是需要安裝必要的軟件,首先測試下網絡

Inside NJU, you should easily obtain an IPv6 address. To test this, try to ping a mirror host with IPv6 support:

ping mirrors.tuna.tsinghua.edu.cn -c 4

If you do not have an IPv6 address, you may access the Internet by IPv4 address. You can try to ping a host outside the university LAN:

ping www.baidu.com -c 4

爲了網速,需要使用鏡像apt源

Run the following commands to update the APT source file:

bash -c 'echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ stable main" > /etc/apt/sources.list'

 

However, you will receive an error message:

bash: /etc/apt/sources.list: Permission denied

This is because the APT source file is owned by root, and you do not have the permission to modify it.

One solution is first switching to the root account. But to avoid switching, an alternative way is to use sudo. If you find an operation requires superuser permission, append sudo before that operation. First, you should add your account to the sudo group:

su -   # we still need to switch to the root account first
adduser username sudo  # change `username` to your user name
exit

To let the changes to take effect, you should log out or reboot. After that, try

whoami
sudo whoami

If it is the first time you run sudo, enter the password of your account. You should find that sudo whoami will output root.

Now you can use sudo to modify the APT source file. This time you should modify it successfully. To check this, you can output the file:

cat /etc/apt/sources.list

You should see it really outputs the line you just echoed.

 

接下來嘗試更新apt

Now you can tell apt to retrieve software information from the sources:

apt-get update

However, you will receive an error message:

E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/

This is because apt-get requires superuser privilege to run. Run the command with superuser privilege. Since it requires Internet accessing, it may cost some time to finish.

 

Installing tools for PAs

The following tools are necessary for PAs:

apt-get install build-essential    # build-essential packages, include binary utilities, gcc, make, and so on
apt-get install man                # on-line reference manual
apt-get install gdb                # GNU debugger
apt-get install git                # revision control system
apt-get install libreadline-dev    # a library to use compile the project later
apt-get install libsdl2-dev        # a library to use compile the project later
apt-get install libc6-dev-i386     # a library to use compile the project later
apt-get install qemu-system        # QEMU

The usage of these tools is explained later.

 

接下來是配置vim編輯器

 

 

小知識點STFW( Google查)

你或許會想, 我問別人是爲了節省我的時間.

但現在是互聯網時代了, 在網上你能得到各種信息: 比如diff格式這種標準信息, 網上是100%能搜到的; 就包括你遇到的問題, 很大概率也是別人在網上求助過的. 如果對於一個你本來只需要在搜索引擎上輸入幾個關鍵字就能找到解決方案的問題, 你都沒有付出如此微小的努力, 而是首先想着找人來幫你解決, 佔用別人寶貴的時間, 你將是這個時代的"失敗者".

於是有了STFW (Search The F***ing Web) 的說法, 它的意思是, 在向別人求助之前自己先嚐試通過正確的方式使用搜索引擎獨立尋找解決方案.

正確的STFW方式能夠增加找到解決方案的概率, 包括

如果你沒有使用上述方式來STFW, 請不要抱怨找不到解決方案而開始向別人求助, 你應該想, "噢我剛纔用的是百度, 接下來我應該試試Google". 關於使用Google, 在學校可以嘗試設置IPv6, 或者設置"科學上網", 具體設置方式請STFW.

 

當然配置vim的方法和細節很多。這裏暫略。。

 

熟悉Linux命令

$ mkdir temp      # 創建一個目錄temp
$ cd temp         # 切換到目錄temp
$ touch newfile   # 創建一個空文件newfile
$ mkdir newdir    # 創建一個目錄newdir
$ cd newdir       # 切換到目錄newdir
$ cp ../newfile . # 將上級目錄中的文件newfile複製到當前目錄下
$ cp newfile aaa  # 將文件newfile複製爲新文件aaa
$ mv aaa bbb      # 將文件aaa重命名爲bbb
$ mv bbb ..       # 將文件bbb移動到上級目錄
$ cd ..           # 切換到上級目錄
$ rm bbb          # 刪除文件bbb
$ cd ..           # 切換到上級目錄
$ rm -r temp      # 遞歸刪除目錄temp

進階的例子:

 

統計代碼行數

第一個例子是統計一個目錄中(包含子目錄)中的代碼行數. 如果想知道當前目錄下究竟有多少行的代碼, 就可以在命令行中鍵入如下命令:

find . | grep '\.c$\|\.h$' | xargs wc -l

如果用man find查看find操作的功能, 可以看到find是搜索目錄中的文件. Linux中一個點.始終表示Shell當前所在的目錄, 因此find .實際能夠列出當前目錄下的所有文件. 如果在文件很多的地方鍵入find ., 將會看到過多的文件, 此時可以按CTRL + c退出.

同樣, 用man查看grep的功能——"print lines matching a pattern". grep實現了輸入的過濾, 我們的grep有一個參數, 它能夠匹配以.c.h結束的文件. 正則表達式是處理字符串非常強大的工具之一, 每一個程序員都應該掌握其相關的知識. 有興趣的同學可以首先閱讀一個基礎的教程, 然後看一個有趣的小例子: 如何用正則表達式判定素數. 正則表達式還可以用來編寫一個30行的java表達式求值程序(傳統方法幾乎不可能), 聰明的你能想到是怎麼完成的嗎? 上述的grep命令能夠提取所有.c.h結尾的文件.

剛纔的findgrep命令, 都從標準輸入中讀取數據, 並輸出到標準輸出. 關於什麼是標準輸入輸出, 請參考這裏. 連接起這兩個命令的關鍵就是管道符號|. 這一符號的左右都是Shell命令, A | B的含義是創建兩個進程AB, 並將A進程的標準輸出連接到B進程的標準輸入. 這樣, 將findgrep連接起來就能夠篩選出當前目錄(.)下所有以.c.h結尾的文件.

我們最後的任務是統計這些文件所佔用的總行數, 此時可以用man查看wc命令. wc命令的-l選項能夠計算代碼的行數. xargs命令十分特殊, 它能夠將標準輸入轉換爲參數, 傳送給第一個參數所指定的程序. 所以, 代碼中的xargs wc -l就等價於執行wc -l aaa.c bbb.c include/ccc.h ..., 最終完成代碼行數統計.

 

統計磁盤使用情況

以下命令統計/usr/share目錄下各個目錄所佔用的磁盤空間:

du -sc /usr/share/* | sort -nr

du是磁盤空間分析工具, du -sc將目錄的大小順次輸出到標準輸出, 繼而通過管道傳送給sortsort是數據排序工具, 其中的選項-n表示按照數值進行排序, 而-r則表示從大到小輸出. sort可以將這些參數連寫在一起.

然而我們發現, /usr/share中的目錄過多, 無法在一個屏幕內顯示. 此時, 我們可以再使用一個命令: moreless.

du -sc /usr/share/* | sort -nr | more

此時將會看到輸出的前幾行結果. more工具使用空格翻頁, 並可以用q鍵在中途退出. less工具則更爲強大, 不僅可以向下翻頁, 還可以向上翻頁, 同樣使用q鍵退出. 這裏還有一個關於less的小故事.

 

進入了正確的目錄後, 輸入相應的命令就能夠開始編輯文件. 例如輸入

vi hello.c
或emacs hello.c

就能開啓一個文件編輯. 例如可以鍵入如下代碼(對於首次使用viemacs的同學, 鍵入代碼可能會花去一些時間, 在編輯的同時要大量查看網絡上的資料):

#include <stdio.h>
int main(void) {
  printf("Hello, Linux World!\n");
  return 0;
}

保存後就能夠看到hello.c的內容了. 終端中可以用cat hello.c查看代碼的內容. 如果要將它編譯, 可以使用gcc命令:

gcc hello.c -o hello

gcc-o選項指定了輸出文件的名稱, 如果將-o hello改爲-o hi, 將會生成名爲hi的可執行文件. 如果不使用-o選項, 則會默認生成名爲a.out的文件, 它的含義是assembler output. 在命令行輸入

./hello

就能夠運行改程序. 命令中的./是不能少的, 點代表了當前目錄, 而./hello則表示當前目錄下的hello文件. 與Windows不同, Linux系統默認情況下並不查找當前目錄, 這是因爲Linux下有大量的標準工具(如test等), 很容易與用戶自己編寫的程序重名, 不搜索當前目錄消除了命令訪問的歧義.

 

使用重定向

有時我們希望將程序的輸出信息保存到文件中, 方便以後查看. 例如你編譯了一個程序myprog, 你可以使用以下命令對myprog進行反彙編, 並將反彙編的結果保存到output文件中:

objdump -d myprog > output

>是標準輸出重定向符號, 可以將前一命令的輸出重定向到文件output中. 這樣, 你就可以使用文本編輯工具查看output了.

但你會發現, 使用了輸出重定向之後, 屏幕上就不會顯示myprog輸出的任何信息. 如果你希望輸出到文件的同時也輸出到屏幕上, 你可以使用tee命令:

objdump -d myprog | tee output

使用輸出重定向還能很方便地實現一些常用的功能, 例如

> empty                  # 創建一個名爲empty的空文件
cat old_file > new_file  # 將文件old_file複製一份, 新文件名爲new_file

如果myprog需要從鍵盤上讀入大量數據(例如一個圖的拓撲結構), 當你需要反覆對myprog進行測試的時候, 你需要多次鍵入大量相同的數據. 爲了避免這種無意義的重複鍵入, 你可以使用以下命令:

./myprog < data

<是標準輸入重定向符號, 可以將前一命令的輸入重定向到文件data中. 這樣, 你只需要將myprog讀入的數據一次性輸入到文件data中, myprog就會從文件data中讀入數據, 節省了大量的時間.

下面給出了一個綜合使用重定向的例子:

time ./myprog < data | tee output

這個命令在運行myprog的同時, 指定其從文件data中讀入數據, 並將其輸出信息打印到屏幕和文件output中. time工具記錄了這一過程所消耗的時間, 最後你會在屏幕上看到myprog運行所需要的時間. 如果你只關心myprog的運行時間, 你可以使用以下命令將myprog的輸出過濾掉:

time ./myprog < data > /dev/null

/dev/null是一個特殊的文件, 任何試圖輸出到它的信息都會被丟棄, 你能想到這是怎麼實現的嗎? 總之, 上面的命令將myprog的輸出過濾掉, 保留了time的計時結果, 方便又整潔.

 

 

使用Makefile管理工程

大規模的工程中通常含有幾十甚至成百上千個源文件(Linux內核源碼有25000+的源文件), 分別鍵入命令對它們進行編譯是十分低效的. Linux提供了一個高效管理工程文件的工具: GNU Make. 我們首先從一個簡單的例子開始, 考慮上文提到的Hello World的例子, 在hello.c所在目錄下新建一個文件Makefile, 輸入以下內容並保存:

hello:hello.c
    gcc hello.c -o hello    # 注意開頭的tab, 而不是空格

.PHONY: clean

clean:
    rm hello    # 注意開頭的tab, 而不是空格

返回命令行, 鍵入make, 你會發現make程序調用了gcc進行編譯. Makefile文件由若干規則組成, 規則的格式一般如下:

目標文件名:依賴文件列表
    用於生成目標文件的命令序列   # 注意開頭的tab, 而不是空格

我們來解釋一下上文中的hello規則. 這條規則告訴make程序, 需要生成的目標文件是hello, 它依賴於文件hello.c, 通過執行命令gcc hello.c -o hello來生成hello文件.

如果你連續多次執行make, 你會得到"文件已經是最新版本"的提示信息, 這是make程序智能管理的功能. 如果目標文件已經存在, 並且它比所有依賴文件都要"新", 用於生成目標的命令就不會被執行. 你能想到make程序是如何進行"新"和"舊"的判斷的嗎?

上面例子中的clean規則比較特殊, 它並不是用來生成一個名爲clean的文件, 而是用於清除編譯結果, 並且它不依賴於其它任何文件. make程序總是希望通過執行命令來生成目標, 但我們給出的命令rm hello並不是用來生成clean文件, 因此這樣的命令總是會被執行. 你需要鍵入make clean命令來告訴make程序執行clean規則, 這是因爲make默認執行在Makefile中文本序排在最前面的規則. 但如果很不幸地, 目錄下已經存在了一個名爲clean的文件, 執行make clean會得到"文件已經是最新版本"的提示. 解決這個問題的方法是在Makefile中加入一行PHONY: clean, 用於指示"clean是一個僞目標". 這樣以後, make程序就不會判斷目標文件的新舊, 僞目標相應的命令序列總是會被執行.

對於一個規模稍大一點的工程, Makefile文件還會使用變量, 函數, 調用Shell命令, 隱含規則等功能. 如果你希望學習如何更好地編寫一個Makefile, 請到互聯網上搜索相關資料.

 

 

綜合示例: 教務刷分腳本

使用編輯器編輯文件jw.sh爲如下內容(另外由於教務網站的升級改版, 目前此腳本可能不能實現正確的功能):

這個shell腳本實現了一個爬蟲功能,將成績信息輸出到終端

#!/bin/bash
save_file="score" # 臨時文件
semester=20102 # 刷分的學期, 20102代表2010年第二學期
jw_home="http://jwas3.nju.edu.cn:8080/jiaowu" # 教務網站首頁地址
jw_login="http://jwas3.nju.edu.cn:8080/jiaowu/login.do" # 登錄頁面地址
jw_query="http://jwas3.nju.edu.cn:8080/jiaowu/student/studentinfo/achievementinfo.do?method=searchTermList&termCode=$semester" # 分數查詢頁面地址

name="09xxxxxxx" # 你的學號
passwd="xxxxxxxx" # 你的密碼

# 請求jw_home地址, 並從中找到返回的cookie. cookie信息在http頭中的JSESSIONID字段中
cookie=`wget -q -O - $jw_home --save-headers | \
    sed -n 's/Set-Cookie: JSESSIONID=\([0-9A-Z]\+\);.*$/\1/p'`
# 用戶登錄, 使用POST方法請求jw_login地址, 並在POST請求中加入userName和password
wget -q -O - --header="Cookie:JSESSIONID=$cookie" --post-data \
    "userName=${name}&password=${passwd}" "$jw_login" &> /dev/null
# 登錄完畢後, 請求分數查詢頁面. 此時會返回html頁面並輸出到標準輸出. 我們將輸出重定向到文件"tmp"中.
wget -q -O - --header="Cookie:JSESSIONID=$cookie" "$jw_query" > tmp
# 獲取分數列表. 因爲教務網站的代碼實在是實現得不太規整, 我們又想保留shell的風味, 所以用了比較繁瑣的sed和awk處理. list變量中會包含課程名稱的列表.
list=`cat tmp | sed -n '/<table.*TABLE_BODY.*>/,/<\/table>/p' \
        | sed '/<--/,/-->/d' | grep td \
        | awk 'NR%11==3' | sed 's/^.*>\(.*\)<.*$/\1/g'`
# 對list中的每一門課程, 都得到它的分數
for item in $list; do
    score=`cat tmp | grep -A 20 $item | awk "NR==18" | sed -n '/^.*\..*$/p'`
    score=`echo $score`
    if [[ ${#score} != 0 ]]; then # 如果存在成績
        grep $item $save_file &>/dev/null # 查找分數是否顯示過
        if [[ $? != 0 ]]; then # 如果沒有顯示過
        # 考慮到嘗試的同學可能沒有安裝notify-send工具, 這裏改成echo  -- yzh
            # notify-send "新成績:$item $score" # 彈出窗口顯示新成績
            echo "新成績:$item $score" # 在終端裏輸出新成績
            echo $item >> $save_file # 將課程標記爲已顯示
        fi
    fi
done

運行這個例子需要在命令行中輸入bash jw.sh, 用bash解釋器執行這一腳本. 如果希望定期運行這一腳本, 可以使用Linux的標準工具之一: cron. 將命令添加到crontab就能實現定期自動刷新.

爲了理解這個例子, 首先需要一些HTTP協議的基礎知識. HTTP請求實際就是來回傳送的文本流——瀏覽器(或我們例子中的爬蟲)生成一個文本格式的HTTP請求, 包括header和content, 以文本的形式通過網絡傳送給服務器. 服務器根據請求內容(header中包含請求的URL以及瀏覽器等其他信息), 生成頁面並返回.

用戶登錄的實現, 就是通過HTTP頭中header中的cookie實現的. 當瀏覽器第一次請求頁面時, 服務器會返回一串字符, 用來標識瀏覽器的這次訪問. 從此以後, 所有與該網站交互時, 瀏覽器都會在HTTP請求的header中加入這個字符串, 這樣服務器就"記住"了瀏覽器的訪問. 當完成登錄操作(將用戶名和密碼發送到服務器)後, 服務器就知道這個cookie隱含了一個合法登錄的帳號, 從而能夠根據帳號信息發送成績.

得到包含了成績信息的html文檔之後, 剩下的事情就是解析它了. 我們用了大量的sedawk完成這件事情, 同學們不用去深究其中的細節, 只需知道我們從文本中提取出了課程名和成績, 並且將沒有顯示過的成績顯示出來.

我們講解這個例子主要是爲了說明新環境下的工作方式, 以及實踐Unix哲學:

  • 每個程序只做一件事, 但做到極致
  • 用程序之間的相互協作來解決複雜問題
  • 每個程序都採用文本作爲輸入和輸出, 這會使程序更易於使用

一個Linux老手可以用腳本完成各式各樣的任務: 在日誌中篩選想要的內容, 搭建一個臨時HTTP服務器(核心是使用nc工具)等等. 功能齊全的標準工具使Linux成爲工程師, 研究員和科學家的最佳搭檔.

 

解決問題方法論,查閱官方手冊

 

RTFM是STFW的長輩, 在互聯網還不是很流行的年代, RTFM是解決問題的一種有效方法. 這是因爲手冊包含了查找對象的所有信息, 關於查找對象的一切問題都可以在手冊中找到答案.

你或許會覺得翻閱手冊太麻煩了, 所以可能會在百度上隨便搜一篇博客來嘗試尋找解決方案. 但是, 你需要明確以下幾點:

  • 你搜到的博客可能也是轉載別人的, 有可能有坑
  • 博主只是分享了他的經歷, 有些說法也不一定準確
  • 搜到了相關內容, 也不一定會有全面的描述

最重要的是, 當你嘗試了上述方法而又無法解決問題的時候, 你需要明確"我剛纔只是在嘗試走捷徑, 看來我需要試試RTFM了".

 

 

學習GDB調試器

 

 

安裝tmux

tmux is a terminal multiplexer. With it, you can create multiple terminals in a single screen. It is very convenient when you are working with a high resolution monitor. To install tmux, just issue the following command:

 

我們先來看兩個例子.

1. 如何比較兩個文件是否完全相同?

這個例子看上去非常簡單, 在Linux下使用diff命令就可以實現. 如果文件很大, 那不妨用md5sum來計算並比較它們的MD5. 對一個Linux用戶來說, 鍵入這些命令只需要花費大約3秒的時間. 但在Windows下, 這件事要做起來就不那麼容易了. 也許你下載了一個MD5計算工具, 但你需要點擊多少次鼠標才能完成比較呢? 也許你覺得一次好像也省不了多少時間, 然而真相是, 你的開發效率就是這樣一點點降低的.

2. 如何列出一個C語言項目中所有被包含過的頭文件?

這個例子比剛纔的稍微複雜一些, 但在Windows下你幾乎無法高效地做到它. 在Linux中, 我們只需要通過一行命令就可以做到了:

find . -name "*.[ch]" | xargs grep "#include" | sort | uniq

通過查閱man, 你應該不難理解上述命令是如何實現所需功能的. 這個例子再次體現了Unix哲學:

  • 每個工具只做一件事情, 但做到極致
  • 工具採用文本方式進行輸入輸出, 從而易於使用
  • 通過工具之間的組合來解決複雜問題

Unix哲學的最後一點最能體現Linux和Windows的區別: 編程創造. 如果把工具比作代碼中的函數, 工具之間的組合就是一種編程. 而Windows的工具之間幾乎無法組合, 因爲面向普通用戶的Windows需要強調易用性.

所以, 你應該使用Linux的原因非常簡單: 作爲一個碼農, Windows一直在阻礙你思想, 能力和效率的提升.

 

我們先來看兩個例子.

1. 如何比較兩個文件是否完全相同?

這個例子看上去非常簡單, 在Linux下使用diff命令就可以實現. 如果文件很大, 那不妨用md5sum來計算並比較它們的MD5. 對一個Linux用戶來說, 鍵入這些命令只需要花費大約3秒的時間. 但在Windows下, 這件事要做起來就不那麼容易了. 也許你下載了一個MD5計算工具, 但你需要點擊多少次鼠標才能完成比較呢? 也許你覺得一次好像也省不了多少時間, 然而真相是, 你的開發效率就是這樣一點點降低的.

2. 如何列出一個C語言項目中所有被包含過的頭文件?

這個例子比剛纔的稍微複雜一些, 但在Windows下你幾乎無法高效地做到它. 在Linux中, 我們只需要通過一行命令就可以做到了:

find . -name "*.[ch]" | xargs grep "#include" | sort | uniq

通過查閱man, 你應該不難理解上述命令是如何實現所需功能的. 這個例子再次體現了Unix哲學:

  • 每個工具只做一件事情, 但做到極致
  • 工具採用文本方式進行輸入輸出, 從而易於使用
  • 通過工具之間的組合來解決複雜問題

Unix哲學的最後一點最能體現Linux和Windows的區別: 編程創造. 如果把工具比作代碼中的函數, 工具之間的組合就是一種編程. 而Windows的工具之間幾乎無法組合, 因爲面向普通用戶的Windows需要強調易用性.

所以, 你應該使用Linux的原因非常簡單: 作爲一個碼農, Windows一直在阻礙你思想, 能力和效率的提升.

 

  1. 卸載Windows, 解放思想, 擺脫Windows對你的阻礙. 與其默認"沒辦法, 也只能這樣了", 你應該去嘗試"看看能不能把這件事做好".
    • Linux下也有相應的常用軟件, 如Chrome, WPS, 搜狗輸入法, mplayer...
    • 沒有Windows你也可以活下去
    • 實在不行可以裝個Windows虛擬機備用
  2. 熟悉一些常用的命令行工具, 並強迫自己在日常操作中使用它們
    • 文件管理 - cdpwdmkdirrmdirlscprmmvtar
    • 文件檢索 - catmorelessheadtailfilefind
    • 輸入輸出控制 - 重定向, 管道, teexargs
    • 文本處理 - vimgrepawksedsortwcuniqcuttr
    • 正則表達式
    • 系統監控 - jobspstopkillfreedemsglsof
    • 上述工具覆蓋了程序員絕大部分的需求
      • 可以先從簡單的嘗試開始, 用得多就記住了, 記不住就man
  3. RTFM + STFW
  4. 堅持.
    • 心態上, 相信總有對的工具能幫助我做得更好
    • 行動上, 願意付出時間去找到它, 學它, 用它

 

事實上, 學習使用Linux是一個低成本, 高成功率的鍛鍊機會. 只要你願意STFW和RTFM, 就能解決絕大部分的問題. 相比較而言, 你之後(後續PA中/後續課程中/工作中)遇到的問題只會更加困難. 因此, 獨立解決這些簡單的小問題, 你就會開始積累最初的信心, 從而也慢慢相信自己有能力解決更難的問題.

 

 

接下來就是客隆項目,並熟悉git開發

 

Now get the source code for PA by the following command:

git clone -b 2020 https://github.com/NJU-ProjectN/ics-pa.git ics2020

A directory called ics2020 will be created. This is the project directory for PAs. Details will be explained in PA1.

Then issue the following commands to perform git configuration:

git config --global user.name "191220000-Zhang San" # your student ID and name
git config --global user.email "[email protected]"   # your email
git config --global core.editor vim                 # your favorite editor
git config --global color.ui true

You should configure git with your student ID, name, and email. Before continuing, please read this git tutorial to learn some basics of git.

Enter the project directory ics2020, then run

git branch -m master
bash init.sh nemu
bash init.sh abstract-machine

to initialize some subprojects. The script will pull some subprojects from github. We will explain them later.

Besides, the script will also add some environment variables into the bash configuration file ~/.bashrc. These variables are defined by absolute path to support the compilation of the subprojects. Therefore, DO NOT move your project to another directory once finishing the initialization, else these variables will become invalid. Particularly, if you use shell other than bash, please set these variables in the corresponding configuration file manually.

To let the environment variables take effect, run

source ~/.bashrc

Then try

echo $NEMU_HOME
echo $AM_HOME
cd $NEMU_HOME
cd $AM_HOME

to check whether these environment variables get the right paths. If both the echo commands report the right paths, and both the cd command change to the target paths without errors, we are done. If not, please double check the steps above and the shell you are using.

Git usage

We will use the branch feature of git to manage the process of development. A branch is an ordered list of commits, where a commit refers to some modifications in the project.

You can list all branches by

git branch

You will see there is only one branch called "master" now.

* master

To create a new branch, use git checkout command:

git checkout -b pa0

This command will create a branch called pa0, and check out to it. Now list all branches again, and you will see we are now at branch pa0:

  master
* pa0

From now on, all modifications of files in the project will be recorded in the branch pa0.

Now have a try! Modify the STUID and STUNAME variables in nemu/Makefile.git:

STUID = 191220000  # your student ID
STUNAME = 張三     # your Chinese name

Run

git status

to see those files modified from the last commit:

On branch pa0
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   nemu/Makefile.git

no changes added to commit (use "git add" and/or "git commit -a")

Run

git diff

to list modifications from the last commit:

diff --git a/nemu/Makefile.git b/nemu/Makefile.git
index c9b1708..b7b2e02 100644
--- a/nemu/Makefile.git
+++ b/nemu/Makefile.git
@@ -1,4 +1,4 @@
-STUID = 191220000
-STUNAME = 張三
+STUID = 191221234
+STUNAME = 李四

  # DO NOT modify the following code!!!

You should see STUID and STUNAME are modified. Now add the changes to commit by git add, and issue git commit:

git add .
git commit

The git commit command will call the text editor. Type modified my info in the first line, and keep the remaining contents unchanged. Save and exit the editor, and this finishes a commit. Now you should see a log labeled with your student ID and name by

git log

Now switch back to the master branch by

git checkout master

Open nemu/Makefile.git, and you will find that STUID and STUNAME are still unchanged! By issuing git log, you will find that the commit log you just created has disappeared!

Don't worry! This is a feature of branches in git. Modifications in different branches are isolated, which means modifying files in one branch will not affect other branches. Switch back to pa0 branch by

git checkout pa0

You will find that everything comes back! At the beginning of PA1, you will merge all changes in branch pa0 into master.

The workflow above shows how you will use branch in PAs:

  • before starting a new PA, new a branch pa? and check out to it
  • coding in the branch pa? (this will introduce lot of modifications)
  • after finish the PA, merge the branch pa? into master, and check out back to master

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章