Dlang 與 C 語言互動(二)

2023-06-25 21:00:27

Dlang 與 C 語言互動(二)

隨著需求不斷增加,發現好像需要更多的東西了。在官網上找不到資料,四處拼湊才有了本文的分享。

上一文(DLang 與 C 語言互動(一) - jeefy - 部落格園)中說了非常簡單了例子。本文試著向更高階的方法拓展。

文章連結(防止機器搬運):https://www.cnblogs.com/jeefy/p/17503853.html

連結庫

對,還是它,只是這次給出更多的解決思路。

Writing Shared Libraries With D On Linux - D Programming Language 中我看到了這個命令:dmd -oflibdll.so dll.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is

其中 -L... 後面跟的東西叫做 linkflag,會在連結的時候使用。

於是對於一個程式,我們可以通過:

dmd somefiles.d -L-lsomelib -L-rpath=/additional/path/to/search/for/lib

來設定連結庫。

其中 -rpath=... 的意思可以參考:GCC 中 -L、-rpath和-rpath-link的區別 - lsgxeva - 部落格園

於是在我的專案 Jeefy / jimg · GitLab 中,最終的編譯命令為:

dmd ./src/main.d -of=./build/main -I./src -L-L./build -L-rpath=./build -L-ljimg

編譯前在 build 目錄下有一個 libjimg.so 檔案。

我通過此命令連結到這個庫。

那麼接下來的問題在於轉化為我如何將多個 dlang 檔案編譯成一個 .so 檔案。


這裡設 OBJS 表示所有預編譯後的檔案(.o)。

有如下命令(採用的是 Makefile 的語法表達):

dmd $(OBJS) -shared -fPIC -of=libtest.so -L-lsomelib

我成功的獲得了一個可以使用的庫。

利用 ldd libtest.so 檢視依賴,可以發現所有的 -l... 的依賴都被加入其中。

也就是說我可以把一個模組以及其依賴打包成一個 shared library 然後通過 -L-l... 來連結它。


這是唯一的方法嗎?並不是的。

事實上採用 gcc/g++ 也可以。與上面類似:

gcc $(OBJS) -shared -fPIC -o libtest.so -lsomelib -DSOME_MACRO

可以得到一樣的結果,並且我還可以定義一些宏傳入其中。也就是說實際 gcc 可能功能更齊全。但是如果其中包含了沒有預編譯過.d 檔案,就只能使用 dmd 達到這種效果了。


GDB

需要偵錯?不知道用什麼偵錯?利用專門寫給 dlang 的工具偵錯發現對 C 的支援不好?

於是轉身向 gdb 走去。

想要開啟偵錯功能,則需要在編譯的時候加入 -g 引數。

無論是dmd還是gcc都要。之後通過 gdb 偵錯即可。

命令,斷點什麼的和一般的偵錯是一模一樣的。不多說了。


動態載入連結庫

Writing Shared Libraries With D On Linux - D Programming Language 中有眾多講解,這裡提兩句。

在 dlang 中載入連結庫需要用到 core.sys.posix.dlfcn,這相當於 #include <dlfcn.h>。也就是說,dlang 中載入動態庫的程式碼與 C 中幾乎一模一樣。

這裡不妨以 dlang 載入 dlang 的庫為例。

lib.d 編譯為連結庫,main.d 中載入。

dmd -c lib.d -fPIC
dmd -oflibtest.so lib.o -shared -defaultlib=libphobos2.so

dmd -c main.d
dmd main.o -L-ltest -L-L. -defaultlib=libphobos2.so -map

-defaultlib=libphobos2.so 是否是必要的取決於連結的物件。

加上它之後的區別在於 libtest.so, main 會新增動態的對於 libphobos2.so 的依賴。可以通過 ldd 檢視。也就是是靜態連結和動態連結的區別。

如果是在 dlang 中載入 dlang 的庫,那麼是必要的,否則,會有多個 dlang 的範例在執行,產生衝突。(Otherwise, the result will be multiple instances of the D runtime conflicting with each other.

反正只要不是多個 dlang 庫間呼叫,那麼就要用 -defaultlib=libphobos2.so。反之則不用。

這裡面 -map 指生成連結中的 .map 檔案。具體作用請讀者自行探究。

還有幾個點說一下:

  • 在呼叫 dlopendlclose 時,會分別呼叫的 static this() { ... } 以及 static ~this() { ... }

  • 如果是 C 中呼叫 dlang,此時 libphobos2自動被開啟,不需要再手動載入一次。檔案原文 Note that libphobos2.so gets automatically dynamically loaded as well.

  • ....


作者有話說

有一段時間我瘋狂吐槽 dlang,僅僅是因為我當時認為其對 C/C++ 的支援很爛(在嘗試寫 jgui 的時候),如此接近 C 系列的語言竟然這樣!然後我就沒有如何看 dlang 這個東西。

後來我機緣巧合之下,看到了 quandim 專案。於是我就想實現類似的功能,於是開始寫 Jeefy / jimg · GitLab 接著就探索到了本文中的內容。確實機緣巧合令人驚歎。

接著發現一點中文檔案都沒有……全是英文。幸虧我英語不錯,看這些檔案還是沒有問題。所以才有了這些文章。

哎,幸虧是高中生,不然真可能直接擺爛,然後放棄 dlang。

說實話,dlang 還是非常好的一種語言,雖然其 class 的記憶體分配是真的弱智……就不能同時 new 多個物件,一起分配空間嗎 QwQ