2018/11/07

自製 make menuconfig

linux kernel 提供的 kconfig 功能十分好用,openwrt 和 buildroot 也都拿來使用,但是內容太龐大,整包拿來用並不輕鬆,所幸找到一包已經從 kconfig 抽出來的 standalong 版本 (github 連結),可以好好的利用,以下就是利用這個 github 當基礎來建立一個簡單的 menuconfig template。

資料夾結構

名稱(Name) 描述(Descript)
~/build/ 編譯空間
~/defconfig/ 放置 defconfig 的地方
~/host-tools/ 集中放置 host 工具的地方,可再擴充,像是 toolchain
~/host-tools/menuconfig/ standalong 的原始碼,內層不再贅述

~/host-tools/menuconfig/Makefile
原始的專案採用 cmake,因為會產生 cmake 相關的檔案,所以自己建一個簡單的 Makefile 來用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
CC ?= gcc

lxdialog := lxdialog/checklist.o
lxdialog += lxdialog/util.o
lxdialog += lxdialog/inputbox.o
lxdialog += lxdialog/textbox.o
lxdialog += lxdialog/yesno.o
lxdialog += lxdialog/menubox.o

mconf-objs := mconf.o
mconf-objs += zconf.tab.o
mconf-objs += $(lxdialog)

conf-objs := conf.o
conf-objs += zconf.tab.o

clean-files	:= mconf conf
clean-files += $(mconf-objs)
clean-files += $(conf-objs)

all: mconf conf
	
$(obj)/%.o: %.c
	$(CC) -c $< -o $@

mconf: $(mconf-objs)
	$(CC) $(mconf-objs) -o mconf -lncurses

conf: $(conf-objs)
	$(CC) $(conf-objs) -o conf

clean:
	@rm -f $(clean-files)
這個 Makefile 預設使用 gcc 進行編譯,如果需要更改,需要 make 的時候予以告知,例如 make CC=your_compiler
make 完成後會產生 mconf 和 conf 兩個執行檔

~/Makefile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ifneq ("$(wildcard .config)","")
	include .config
endif

all: preconfig

preconfig:
ifeq ("$(wildcard .config)","")
	$(error "Please run make menuconfig first.")
endif

menuconfig:
	@mkdir -p build
	@rsync -ur host-tools/menuconfig build
	@make -C build/menuconfig
	@./build/menuconfig/mconf Config.in

list-defconfigs:
	@echo 'Built-in configs:'
	@$(foreach b, $(sort $(notdir $(wildcard defconfig/*_defconfig))), \
	  printf "  %-35s - Build for %s\\n" $(b) $(b:_defconfig=);)
	@echo

%_defconfig:
	@./build/menuconfig/conf --defconfig=defconfig/$@ Config.in~
1~3: 如果已經存在 .config 就將內容 include 進來
5: all 之前要先跑過 preconfig
7~10: preconfig 會檢查 .config 是不是存在,如果不存在就顯示要求執行 menuconfig 並且報錯跳出
12~16: menuconfig 主體,make 的機制是已經編譯過且沒有更改內容,就不會重新編譯
18~22: list-defconfigs 可以列出在 ~/defconfig 裡面的所有 *_defconfig
24~25: 當執行 make xxxx_defconfig 就會依據 xxxx_defconfig 來產生 .config

使用這個 template 可以建立一個基本的 menuconfig 功能,通常會根據不同的 target board 或是個別的客製化來製作 xxxx_defconfig,要編譯的時候就可以直接 make xxxx_defconfig 然後再 make all。

一般來說,build 放置的是 target 的編譯空間,砍掉 build 就會非常乾淨,但是 host-tools 也得重編,所以如果確定 host-tools 跟 target 無依存關係,也可以另外開 host-build 來用。

2018/08/09

執行時期控制 linux kernel 印出的訊息

(based on linux kernel version 3.10.104)

在 embedded linux 開發過程中,常常會為了對 kernel space 進行追蹤而使用 printk,但是每次編譯重燒是很耗費時間的,所以直接在執行時期控制 printk 的訊息要不要顯示出來,會是追蹤的一門重要技巧。

參考

printk 提供了一個在執行時期的控制介面,/proc/sys/kernel/printk

#cat /proc/sys/kernel/printk
7 4 1 7

第一個數字代表要印出來的最低等級,也就是等級高於或等於7 (KERN_DEBUG) 都會被印出來
第二個數字代表 printk 沒有指定等級的預設等級 4 (KERN_WARNING)

因為 KERN_WARNING 等級高於 KERN_DEBUG,所以目前不指定等級的 printk() 都會被印出來。

如果只想看到嚴重等級以上的訊息,可以直接

#echo 2 > /proc/sys/kernel/printk
#cat /proc/sys/kernel/printk
2 4 1 7

這樣未指定等級的訊息就不會顯示出來,甚至等級為 KERN_ERR 的訊息也都忍住不噴出了。

以下列出各等級資料:

Name String Meaning alias function
KERN_EMERG "0" Emergency messages, system is about to crash or is unstable pr_emerg
KERN_ALERT "1" Something bad happened and action must be taken immediately pr_alert
KERN_CRIT "2" A critical condition occurred like a serious hardware/software failure pr_crit
KERN_ERR "3" An error condition, often used by drivers to indicate difficulties with the hardware pr_err
KERN_WARNING "4" A warning, meaning nothing serious by itself but might indicate problems pr_warning
KERN_NOTICE "5" Nothing serious, but notably nevertheless. Often used to report security events. pr_notice
KERN_INFO "6" Informational message e.g. startup information at driver initialization pr_info
KERN_DEBUG "7" Debug messages pr_debug, pr_devel if DEBUG is defined
KERN_DEFAULT "d" The default kernel loglevel
KERN_CONT "" "continued" line of log printout (only done after a line that had no enclosing \n) [1] pr_cont

2018/07/20

[C] 如何反查 function 被誰呼叫

除錯時常常需要逆向追蹤程式流程,如果被呼叫的地方很少,可以直接在呼叫前 printf,但是當很多地方呼叫的時候,一個一個放 printf 似乎不是ㄧ個高效率的作法。

#define FuncName(a, b, c) \
do { \
    printf("[%s %d] called FuncName\n",__func__, __LINE__); \
    FuncNameReal (a, b, c); \
} while (0)

例如原本有個 function:
int max(int aaa, int bbb) {...}

因為不想改變呼叫的地方,所以要先把 function 名稱改成 _max

然後在 header file 裡面追加

#define max(a, b) printf("[%s %d] called max"); _max(a, b)

這樣呼叫 max 的程式就會自動報上自己是哪個 func,而且同一 func 有多的地方呼叫的話,是在哪一行呼叫也會報出來。

帶回傳值的時候
#define FuncName(a, b, c) ({ \
        int retval; \
        printf("[%s %d] called FuncName\n",__func__, __LINE__); \
        retval = FuncNameReal (a, b, c); \
        retval;})

參考來源:

2018/04/08

買書同時在 mooink 跟 kindle paperwhite 上閱讀 (進度同步就別想了)

雖然 Kindle 有家庭共享機制,但是不容易買到正體中文書。而在讀墨上面買的書只能在 mooink 閱讀,無法下載轉到 kindle 上閱讀。最終只能在 Kobo 上面買書,檔案下載回來,再經過幾道程序,就能同時在 kindle 和 mooink 上面閱讀。

所需工具:



處理過程:


上 Kobo 買書,購買時可以留意電子書詳細資料裡面的下載選項,如果是 EPUB 3 (Adobe DRM) 就要經過解鎖。

將書籍下載。Adobe DRM 的書籍下載回來是一個描述檔,副檔名是acsm (在 Google 圖書購買的也是這個格式)。

使用 Adobe Digital Editions 打開 *.acsm,就會自動下載該書籍。

執行 Epubor Ultimate,點選 Adobe 頁籤,就可以看到 ADE 管理的書籍清單,依照畫面指示,將書籍拖曳到右邊,看到已解密就完成了。

執行 calibre
-> 點選偏好設定
-> 點選外掛
-> 勾選址顯示使用者已安裝的外掛 
-> 展開檔案類型外掛 
-> 雙擊 DeDRM
-> 點擊 Adobe Digital Editions ebooks

-> 點擊 Import Existing Keyfiles
-> 開啟 user/.Epubor_Keys,選取要匯入的檔案 *.der,然後按下開啟
這時已經匯入所需的DRM金鑰,退回 calibre 主畫面
回到 ADE,在要處理的書籍典籍滑鼠右鍵,點選項目資訊

點擊位置右邊的箭頭(以檔案總管顯示)
從檔案總管將書籍拖曳到 calibre 主畫面,由於 DeDRM 已經匯入相對應的 Key,所以可以開始轉換至所需的格式。要注意的是放進去的書籍是有 DRM 的,無法直接從 mooink 讀取,所以仍然需要從 EPUB 轉 EPUB。