在 Windows 下打造一個輕量級 C 語言 IDE,核心需求:
1. 編譯器選用 **MinGW-GCC**(GCC Windows 移植,含 G++、GDB)。
2. 免 Makefile:直接將專案所有 `.c` 編譯為 `.o`,統一鏈接。
3. IDE 內部以隱藏視窗方式啟動 GCC,並**阻塞等待編譯完成**後再進行鏈接。
下載 mingw-get-setup.exe,安裝 `mingw32-gcc-g++`、`mingw32-gdb`。安裝目錄(如 `C:\MinGW`)加入系統 PATH。驗證:
gcc --version、g++ --version、gdb --version 均正常輸出。
| API | 優點 | 缺點 | 適用性 |
|---|---|---|---|
system() | 簡單 | 彈出黑框、無法隱藏、無法重導向 | ❌ 不適合 |
WinExec() | 可隱藏視窗(SW_HIDE) | 不支援管道/重導向(`>`、`|`) | ⚠️ 受限 |
ShellExecute() | 功能強、可隱藏 | 同樣不支援 Shell 操作符 | ⚠️ 受限 |
ShellExecuteEx() + cmd /c | 支援完整 Shell 語法、可隱藏、**可阻塞等待進程結束** | 略繁瑣 | ✅ **首選** |
直接呼叫 `ShellExecuteEx` 執行 `gcc` 仍無法使用管道/重導向。解法:
cmd /c "gcc ... 2>>stderr.log"
將完整命令字串作為 `cmd` 的參數,由 `cmd.exe` 解析執行,支援所有 Shell 特性。
`ShellExecuteEx` 預設**非阻塞**,若直接繼續執行鏈接步驟,`.o` 檔可能尚未生成完畢。
解法:使用 `SEE_MASK_NOCLOSEPROCESS` 旗標取得進程控制代碼,輪詢 GetExitCodeProcess 直到進程結束。
#include <windows.h>
#include <tchar.h>
void BlockShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile,
LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd)
{
SHELLEXECUTEINFO si = {0};
si.cbSize = sizeof(si);
si.fMask = SEE_MASK_NOCLOSEPROCESS; // 關鍵:保留進程控制代碼
si.hwnd = hwnd;
si.lpVerb = lpOperation; // "open"
si.lpFile = lpFile; // "cmd.exe"
si.lpParameters = lpParameters; // "/c gcc ... 2>>stderr.log"
si.lpDirectory = lpDirectory; // 工作目錄
si.nShow = nShowCmd; // SW_HIDE 隱藏視窗
if (!ShellExecuteEx(&si)) {
// 錯誤處理
return;
}
// 阻塞等待進程結束
DWORD dwExitCode;
do {
GetExitCodeProcess(si.hProcess, &dwExitCode);
if (dwExitCode == STILL_ACTIVE) Sleep(5);
} while (dwExitCode == STILL_ACTIVE);
CloseHandle(si.hProcess); // 釋放控制代碼
}
// 單檔編譯
gcc -c -Wall -O2 -Iinclude src/main.c -o debug/main.o
// 批次編譯所有 .c → .o
for %%f in (src\*.c) do gcc -c -Wall -O2 -Iinclude "%%f" -o "debug\%%~nf.o"
// 統一鏈接
gcc debug\*.o -o debug\app.exe -lmylib
2>> debug\stderr.logWindows 缺乏 `autoconf`/`automake` 原生移植,移植成本極高。對初學者導向的教學型 IDE,全量重編譯(專案通常 < 50 檔)耗時可接受,避免 Makefile 複雜度更利於上手。
[IDE UI] → 組裝命令列 → BlockShellExecute(cmd /c gcc ...) → 等待退出碼
↓
讀取 stderr.log → 解析錯誤 → 顯示錯誤列表
↓
全部 .o 就緒 → BlockShellExecute(cmd /c gcc *.o -o app.exe)