`libmemcached` 是 C 語言的 Memcached 客戶端庫,官方主要支援類 Unix 系統。在 Windows 上使用 MinGW 編譯需解決:缺少 Unix 標頭檔、`configure` 腳本強制檢測 `memcached` 二進位、yacc/lex 產生的符號衝突、測試代碼依賴 POSIX API 等問題。本文記錄完整修補流程。
`configure` 由 `autoconf` 產生,包含一段檢測 `--with-memcached` 的邏輯,找不到二進位會直接報錯退出。由於 Windows 上通常不編譯 `memcached`,需**註釋整段檢測邏輯**。
# Check whether --with-memcached was given.
if test "${with_memcached+set}" = set; then :
withval=$with_memcached; ac_cv_with_memcached="$withval"
else
ac_cv_with_memcached=memcached
fi
... # 後續一長串路徑搜尋、MEMC_BINARY 設定、錯誤處理
# 結尾定義宏
cat >>confdefs.h <<_ACEOF
#define MEMCACHED_BINARY "$MEMC_BINARY"
_ACEOF
# 1. 將上述整段 if-else 檢測邏輯以 # 註釋
# 2. 在 confdefs.h 追加區塊前,手動寫入預設值(或留空)
cat >>confdefs.h <<_ACEOF
#define MEMCACHED_BINARY ""
_ACEOF
或更簡單:在 `configure.ac` 修改後重新 `autoreconf -fiv`(需安裝 autotools)。直接改 `configure` 較快但不可維護。
搜尋 `MEMCACHED_BINARY`,主要在 `libtest/server.c`:
// 原代碼
snprintf(buffer, sizeof(buffer), "%s -d -P %s -t 1 -p %u -U %u -m 128",
MEMCACHED_BINARY, construct->pid_file[x], construct->port[x], construct->port[x]);
// 修正:移除 %s 與 MEMCACHED_BINARY
snprintf(buffer, sizeof(buffer), "-d -P %s -t 1 -p %u -U %u -m 128",
construct->pid_file[x], construct->port[x], construct->port[x]);
同理修正 `else` 分支。這樣測試啟動命令不再依賴外部 `memcached` 路徑。
`libmemcached/options/` 下 `parser.h`、`parser.cc`、`scanner.cc` 由 Bison/Flex 產生,枚舉值 `ERROR`、`TRUE`、`FALSE`、`FLOAT` 與 Windows 標頭檔(`wingdi.h`、`windef.h` 等)巨集衝突。
// parser.h / parser.cc
enum yytokentype {
COMMENT = 258, END = 259,
ERROR1 = 260, // ERROR → ERROR1
...
TRUE1 = 315, // TRUE → TRUE1
FALSE1 = 316, // FALSE → FALSE1
FLOAT1 = 317, // FLOAT → FLOAT1
...
};
// parser.cc 字串表同步修改
static const char *const yytname[] = {
"$end", "error", "$undefined", "COMMENT", "END", "ERROR1",
...
"TRUE1", "FALSE1", "','", "'='", "FLOAT1", ..., 0
};
// scanner.cc 規則動作同步
case 44: ... { return ERROR1; }
case 45: ... { return TRUE1; }
case 46: ... { return FALSE1; }
...
注意:大小寫敏感,需全域替換所有出現處。
`libtest/server.c` 使用 `timespec`、`kill()`、`fork()`、`access()` 等。用 `#ifndef WIN32` 包裹:
#ifndef WIN32
static struct timespec global_sleep_value = {0, 50000};
#endif
static void kill_file(const char *file_buffer) {
#ifndef WIN32
// 原 POSIX 實作
#endif
}
void server_startup(server_startup_st *construct) {
#ifndef WIN32
// 原 POSIX 實作
#endif
}
**關鍵**:不能整個檔案註釋,因其他測試檔需連結其中的函式聲明(如 `server_startup`)。保留空實現或存根即可。
test_return_t memcached_create_with_options_with_filename(memcached_st*) {
#ifndef WIN32
if (access(SUPPORT_EXAMPLE_CNF, R_OK)) return TEST_SKIPPED;
// ... 原邏輯
#endif
return TEST_SUCCESS;
}
// 同理處理 libmemcached_check_configuration_with_filename_test、test_include_keyword
# 在 MSYS2/MinGW Shell 中
./configure --prefix=/mingw64 --disable-sasl # 禁用 SASL 簡化依賴
make -j$(nproc)
make install
產出:`libmemcached.dll`、`libmemcached.a`、標頭檔至 `--prefix` 目錄。
| 錯誤訊息 | 原因 | 解決 |
|---|---|---|
| `arpa/inet.h: No such file` | Unix socket 標頭 | 註釋或改 `#include |
| `'ERROR' redefined` | yacc 符號衝突 | 重命名為 `ERROR1` 等 |
| `memcached binary not found` | configure 強制檢測 | 註釋 configure 檢測段,手動定義宏 |
| `sys/mman.h not found` | POSIX mmap | 註釋 memslap.c 包含 |
| `access undefined` | 測試代碼用 POSIX access | `#ifndef WIN32` 包裹 |
| 連結錯誤 `server_startup` | 測試檔需此符號 | 保留函式簽名,實現留空 |
# 編譯簡單測試程式
gcc test_memc.c -o test_memc -I/mingw64/include -L/mingw64/lib -lmemcached
./test_memc
Windows 編譯 `libmemcached` 核心在於:**屏蔽測試代碼的 POSIX 依賴**、**解決 yacc/lex 符號污染**、**繞過 configure 的運行時依賴檢測**。建議將修補封裝為 `patch` 檔案(`git diff > win32-fixes.patch`),納入專案版本控制,實現可重現構建。若專案僅需客戶端功能,亦可考慮使用更輕量、純 C99 實現的替代庫(如 `libmemcached-awesome` fork),減少移植成本。