改寫Python-Solvespace的Makefile運作方式。

前言 :

閱讀GNU-Make的手冊之後,已經了解Makefile基本的運作方式,所以試圖解決Python-Solvespace編譯程序中出現的問題。

手冊連結:https://www.gnu.org/software/make/manual/make.pdf

利用Interface來轉換Whitequark的新版Solvespace應該是不太可行的方式了,何況Python-Solvespace也未使用全部的功能,我們需要的是解題的函式就好。

而另一方面Solid-python現在已經完全支援Python 3,若之後要調用其功能,應該也不會有太大的障礙。

所以決定把Python-Solvespace的Makefile重新寫好,將Python-Solvespace的資料庫建構完成。


Netbeans的支援 :

其實Netbeans與$GNU開發者工具包$周邊的軟體都有良好的相依性,因此在撰寫Makefile時方便不少。

在編寫完Makefile時,可以在個別的Makefile上點擊右鍵,選擇需要的命令讓make執行,諸如all、clean等等的功能可以選擇。

Makefile中可以撰寫功能讓工程師執行,連基本的clean功能也可以自訂要刪除哪些檔案。

當然利用這點,Makefile中也可以利用Echo做help的功能,Whitequark的Solvespace就有支援。


編寫Makefile :

原本Python-Solvespace的Makefile是將檔案分類,再一類類用一樣的式子做轉換,而且語法冗長還有許多錯誤。若有新增檔案,就必須填入參數的名單中登記。

一個小型程式專案的Makefile事實上只需要下列的式子就能轉換:

$(ADIR)/%.obj: $(BDIR)/%.cpp $(HEADERS)
    $(CXX) $(FLAGS) -c -o $@ $<

意思是ADIR中的obj檔都與BDIR的cpp檔、標頭檔有關聯,而每個obj檔是由每個cpp檔透過$(CXX)命令式產生的。

$後面的$@表示每個目標項(包括其位置)$;同理,$$<亦代表每個參照項$,不過$<是只包含第一個條件的參照項,所以後面的多個標頭檔就不會帶入$(CXX)命令中。

若要在命令式中使用所有條件的參照項,要使用$+,但是更好的選擇是使用$^,會自動排除重複名稱的參照項。

這樣寫固然簡單,但是每個檔案都在不同的資料夾中,要如何讓make搜尋?

所以必須加上VPath這個參數,讓尋找參照檔案時可以搜尋到所有符合的項目。

make在找檔案時最大的特性就是$按邏輯去找$。

也因為這點,不用顧慮產生檔案的順序問題。只要"填寫"檔案是如何產生的,make就會根據需要的檔案來做順序調整。

make會先忽略還沒產生的參照檔案,尋找已經備齊參照檔案的項目先做,指令亦可使用外部程式來執行。


編譯瓶頸 :

經過重新整理的Makefile,應該是沒有問題了,都將指令分配完整沒有衝突。

但是仍然遇到Makefile以外的一些問題。

已解決

Stdint.h

這個原先是C語言的額外函式庫,幫助統一化使用的格式,但是如果沒裝,就會選擇作者寫的指令。

不過這個地方應該是寫錯了,會一直認為這些是未定義的格式。

其實導入"stdint.h"的地方也只有上圖的前半段,所以最快的解決方法就是讓solvespace.h擁有stdint.h一部份的能力。

在上面這張Netbeans的比較圖中,直接把前半段的功能插進來用了,並成功解決問題。

Min & Max Functions

下列solvespace.h的函式出了問題。

#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#ifndef max
#define max(x, y) ((x) > (y) ? (x) : (y))
#endif

上網搜尋了一下,找到基本款的用法:

#define min(x, y) (((x)<(y)) ? (x):(y))
#define max(x, y) (((x)>(y)) ? (x):(y))

加上括弧其實非必要,因為三元運算子的優先度本身就比大於小於還低。

不過這個判斷式使用上怪怪的,移除後直接define就沒這個問題了。

Object-oriented problem

在surface.h中有一段是這樣描述的:

class STrimBy {
...
    static STrimBy STrimBy::EntireCurve(SShell *shell, hSCurve hsc, bool bkwds);
...
};

到stackoverflow.com的論壇尋找後,有相似的問題。

是物件導向的從屬錯誤,不應該重複稱呼,但是編譯器通常不會抓這種錯誤,解決方法是刪掉前面的父項名稱。

最後變成:

class STrimBy {
...
    static EntireCurve(SShell *shell, hSCurve hsc, bool bkwds);
...
};

也是成功解決。

未解決

Icons

首先是圖示(icon)的問題。

Python-Solvespace的作者使用另一個語言$Perl$的程式來做出"icons.h"這個檔案。

Perl是一個高階語言,特點就是除了自己的寫法,還可以安裝大量模組來改變撰寫方式,甚至還繼承許多C語言的標準式。

安裝方式跟Python相同,複製檔案跟設定環境變數就能使用了。

作者用了"GD"這個模組來導出"icons.h"。

Netbeans雖然也有Perl的附加元件,但是功能比SciTE還陽春,就沒使用它了。

Perl的副檔名是pl,專案中有"png2c.pl"和"pngchar2c.pl",應該就是將PNG檔導入C語言中的意思,Makefile中是要執行"png2c.pl"並產生出"icons.h"和"icons-proto.h"的樣子,不過"icons-proto.h"不會用到。

在Netbeans中似乎無法呼叫外部程式,會顯示無法找到Perl指令的訊息。

可是到CMD中執行時又會發生無法回應的情況,接著make就會因為找不到"icons.h"而無法編譯。

ld.exe does not find libraries

在exposed資料的Makefile中,g++的參數中需要導入資料庫"-lslvs"。

而在上一個步驟中,"libslvs.so"確定已經產生,但是找不到的狀況。

網路上普遍都是需要資料連結和打錯名稱,但是好像沒這種狀況,莫非是"libslvs.so"產生失敗,或是並非"slvs"這個名稱?

Python-Solvespace的作者有特別指名不要使用DLL做副檔名。


這次學到了編譯程式重要的一環,雖然make的過程中很煩人,也要一直注意是否出錯,但是最後成功時滿有成就感的。

有些錯誤當下想不出來,不過換一種想法後就能克服許多障礙,訓練眼光放遠也是一件重要的事情。


Comments

comments powered by Disqus