小巧。快速。可靠。
任選三項。
如何編譯 SQLite
如何編譯 SQLite

概觀

SQLite 是 ANSI-C 原始碼。在它變得實用之前,它必須編譯成機器碼。本文是編譯 SQLite 的各種方法的指南。

本文不包含編譯 SQLite 的逐步食譜。由於每個開發情況都不同,這將很困難。相反,本文描述並說明了 SQLite 編譯背後的原理。提供典型的編譯命令作為範例,預期應用程式開發人員可以使用這些範例作為開發他們自己的自訂編譯程序的指南。換句話說,本文提供的是想法和見解,而不是交鑰匙解決方案。

1. 混合檔案與個別原始檔

SQLite 是由超過一百個 C 程式碼和腳本檔案建置而成,分佈在多個目錄中。SQLite 的實作是純 ANSI-C,但在納入完成的 SQLite 函式庫之前,許多 C 語言原始碼檔案都是由輔助 C 程式和 AWK、SED 和 TCL 腳本產生或轉換的。建置必要的 C 程式並轉換和/或建立 SQLite 的 C 語言原始碼是一個複雜的過程。

為了簡化問題,SQLite 也以預先封裝的 合併 原始碼檔案提供:sqlite3.c。合併是一個單一的 ANSI-C 程式碼檔案,用於實作整個 SQLite 函式庫。合併更容易處理。所有內容都包含在單一的程式碼檔案中,因此很容易放入較大的 C 或 C++ 程式的原始碼樹中。所有程式碼產生和轉換步驟都已執行完畢,因此沒有輔助 C 程式需要設定和編譯,也沒有需要執行的指令碼。而且,由於整個函式庫都包含在單一的轉譯單元中,編譯器能夠執行更進階的最佳化,進而提升 5% 到 10% 的效能。基於這些原因,建議所有應用程式使用合併原始碼檔案(「sqlite3.c」)。

建議所有應用程式使用 合併

直接從個別原始碼檔案建置 SQLite 當然可行,但並不建議這麼做。對於某些特殊應用程式,可能需要以無法僅使用從網站下載的預先建置合併原始碼檔案的方式修改建置流程。對於這些情況,建議建置自訂合併(如下所述 說明),並加以使用。換句話說,即使專案需要從個別原始碼檔案開始建置 SQLite,仍建議將合併原始碼檔案用作中間步驟。

2. 編譯命令列介面

命令列介面 的建置需要三個原始碼檔案

以上三個原始碼檔案都包含在 合併 tarball 中,可於 下載頁面 取得。

若要建置 CLI,只需將這三個檔案放在同一個目錄中,然後將它們編譯在一起。使用 MSVC

cl shell.c sqlite3.c -Fesqlite3.exe

在 Unix 系統(或在 Windows 上使用 cygwin 或 mingw+msys)中,指令通常類似於以下內容

gcc shell.c sqlite3.c -lpthread -ldl -lm -o sqlite3

需要 pthreads 函式庫才能讓 SQLite 具備執行緒安全性。但由於 CLI 是單一執行緒的,因此我們可以指示 SQLite 以非執行緒安全模式建置,從而略過 pthreads 函式庫

gcc -DSQLITE_THREADSAFE=0 shell.c sqlite3.c -ldl -lm -o sqlite3

需要 -ldl 函式庫來支援動態載入、sqlite3_load_extension() 介面和 load_extension() SQL 函式。如果不需要這些功能,則可以使用 SQLITE_OMIT_LOAD_EXTENSION 編譯時間選項來略過它們

gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -o sqlite3

您可能想要提供其他 編譯時間選項,例如

若要查看 EXPLAIN 清單中的額外註解,請加入 -DSQLITE_ENABLE_EXPLAIN_COMMENTS 選項。加入 -DHAVE_READLINE 和 -lreadline 及 -lncurses 函式庫以取得命令列編輯支援。您可能也想指定一些編譯器最佳化切換。(可從 SQLite 網站下載的預編譯 CLI 使用「-Os」。)這裡有數不清的可能變化。編譯完整功能 shell 的命令可能類似這樣

gcc -Os -I. -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS4 \
   -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_JSON1 \
   -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
   -DHAVE_READLINE \
   shell.c sqlite3.c -ldl -lm -lreadline -lncurses -o sqlite3

重點是:建立 CLI 包括編譯兩個 C 語言檔案。shell.c 檔案包含進入點和使用者輸入迴圈的定義,而 SQLite 彙編 sqlite3.c 包含 SQLite 函式庫的完整實作。

3. 編譯 TCL 介面

SQLite 的 TCL 介面是一個加入常規彙編的小模組。結果是一個新的彙編原始檔,稱為「tclsqlite3.c」。這個單一原始檔是產生共用函式庫所需的一切,該函式庫可以使用 TCL 載入命令 載入標準 tclshwish,或產生內建 SQLite 的獨立 tclsh。tcl 彙編的副本包含在 下載頁面TEA tarball 中的一個檔案。

若要在 Linux 上產生 SQLite 的 TCL 可載入函式庫,下列命令就夠了

gcc -o libtclsqlite3.so -shared tclsqlite3.c -lpthread -ldl -ltcl

很遺憾,建立 Mac OS X 和 Windows 的共用函式庫並不容易。對於那些平台,最好使用 TEA tarball 中包含的組態指令碼和 makefile。

若要產生靜態連結 SQLite 的獨立 tclsh,請使用這個編譯器呼叫

gcc -DTCLSH=1 tclsqlite3.c -ltcl -lpthread -ldl -lz -lm

這裡的訣竅在於 -DTCLSH=1 選項。SQLite 的 TCL 介面模組包含一個 main() 程序,當使用 -DTCLSH=1 編譯時,它會初始化一個 TCL 解譯器並進入一個命令列迴圈。上述命令在 Linux 和 Mac OS X 上都能執行,不過可能需要根據平台和連結的 TCL 版本調整函式庫選項。

4. 建置合併

通常,下載頁面 上提供的 SQLite 合併版本就足夠應付大多數使用者的需求。不過,有些專案可能想要或需要建置自己的合併。建置自訂合併的常見原因是為了使用某些 編譯時期選項 來自訂 SQLite 函式庫。請記住,SQLite 合併包含許多由輔助程式和指令碼產生的 C 程式碼。許多編譯時期選項會影響這個產生的程式碼,而且必須在組建合併之前提供給程式碼產生器。必須傳遞給程式碼產生器的編譯時期選項組可能會隨著 SQLite 的不同版本而有所不同,但在撰寫本文時(約為 SQLite 3.6.20,2009-11-04),程式碼產生器必須知道的選項組包括

若要建立自訂合併,請先將原始個別原始檔下載到類 Unix 或 Unix 開發平台。請務必取得原始原始檔,而不是「預處理原始檔」。可以從 下載頁面 或直接從 組態管理系統 取得完整的原始原始檔組。

假設 SQLite 原始碼樹儲存在名為「sqlite」的目錄中。計畫在平行目錄(例如「bld」)中建立合併。首先,透過執行 SQLite 原始碼樹頂端的組態指令碼,或複製原始碼樹頂端的其中一個範本 Makefiles,來建立適當的 Makefile。然後手動編輯此 Makefile,以包含所需的編譯時期選項。最後執行

make sqlite3.c

或在 Windows 上使用 MSVC

nmake /f Makefile.msc sqlite3.c

「sqlite3.c」make 目標會自動建立常規「sqlite3.c」合併原始檔來源、其標頭檔「sqlite3.h」以及包含 TCL 介面的「tclsqlite3.c」合併原始檔來源。之後,可以將需要的檔案複製到專案目錄,並根據上述程序進行編譯。

5. 建立 Windows DLL

若要建立 SQLite DLL 以在 Windows 中使用,請先取得適當的合併原始碼檔案 sqlite3.c 和 sqlite3.h。這些檔案可以從 SQLite 網站 下載,或如上所示從來源自訂產生。

在工作目錄中使用原始碼檔案時,可以使用 MSVC 透過下列指令產生 DLL

cl sqlite3.c -link -dll -out:sqlite3.dll

上述指令應從 MSVC 原生工具命令提示字元執行。如果您在電腦上安裝了 MSVC,您可能有多個此命令提示字元,用於 x86 和 x64 的原生建置,也可能用於交叉編譯至 ARM。請根據所需的 DLL 使用適當的命令提示字元。

如果使用 MinGW 編譯器,命令列如下

gcc -shared sqlite3.c -o sqlite3.dll

請注意,MinGW 僅產生 32 位元 DLL。有一個獨立的 MinGW64 專案可產生 64 位元 DLL。假設指令列語法類似。另請注意,最近版本的 MSVC 產生的 DLL 在 WinXP 和較早版本的 Windows 上無法執行。因此,建議使用 MinGW 以確保產生的 DLL 具有最大的相容性。一個不錯的經驗法則是用 MinGW 產生 32 位元 DLL,用 MSVC 產生 64 位元 DLL。

在大部分情況下,您會想補充上述基本指令,使用 編譯時期選項,以符合您的應用程式。常用的編譯時期選項包括

此頁面最後修改於 2023-10-10 17:29:48 UTC