-
-
Notifications
You must be signed in to change notification settings - Fork 0
Compiler And Toolchain Configuration
This document explains how CppLab IDE manages MinGW toolchains and compiler configuration.
CppLab IDE bundles two complete MinGW toolchains:
| Toolchain | Bits | Purpose | Compiler | Libraries |
|---|---|---|---|---|
| mingw32 | 32-bit | Graphics (graphics.h) | GCC 8.1.0+ | WinBGIm, GDI32 |
| mingw64 | 64-bit | OpenMP, Modern C++ | GCC 8.1.0+ | libgomp, pthread |
compilers/
├── mingw32/ # 32-bit toolchain
│ ├── bin/
│ │ ├── gcc.exe # C compiler
│ │ ├── g++.exe # C++ compiler
│ │ ├── gdb.exe # Debugger (future)
│ │ └── *.dll # Runtime libraries
│ ├── include/
│ │ ├── graphics.h # WinBGIm header
│ │ ├── winbgim.h
│ │ └── ... # Standard headers
│ ├── lib/
│ │ ├── libbgi.a # WinBGIm library
│ │ ├── libgdi32.a # Windows GDI
│ │ └── ...
│ └── libexec/
│ └── gcc/
│ └── ... # GCC internals
│
└── mingw64/ # 64-bit toolchain
├── bin/
│ ├── gcc.exe
│ ├── g++.exe
│ └── ...
├── include/
│ ├── omp.h # OpenMP header
│ └── ...
├── lib/
│ ├── libgomp.a # OpenMP library
│ ├── libpthread.a
│ └── ...
└── libexec/
└── ...
File: src/cpplab/core/toolchains.py
def get_toolchains() -> dict:
"""Discover and return available MinGW toolchains."""
app_root = get_app_root()
compilers_dir = app_root / "compilers"
toolchains = {}
# Check mingw32
mingw32_path = compilers_dir / "mingw32"
if mingw32_path.exists():
gcc_path = mingw32_path / "bin" / "gcc.exe"
gpp_path = mingw32_path / "bin" / "g++.exe"
if gcc_path.exists() and gpp_path.exists():
toolchains["mingw32"] = Toolchain(
name="mingw32",
root=mingw32_path,
gcc=gcc_path,
gpp=gpp_path,
bits=32
)
# Check mingw64
mingw64_path = compilers_dir / "mingw64"
if mingw64_path.exists():
gcc_path = mingw64_path / "bin" / "gcc.exe"
gpp_path = mingw64_path / "bin" / "g++.exe"
if gcc_path.exists() and gpp_path.exists():
toolchains["mingw64"] = Toolchain(
name="mingw64",
root=mingw64_path,
gcc=gcc_path,
gpp=gpp_path,
bits=64
)
return toolchains@dataclass
class Toolchain:
name: str # "mingw32" or "mingw64"
root: Path # C:/path/to/CppLabIDE/compilers/mingw32
gcc: Path # Path to gcc.exe
gpp: Path # Path to g++.exe
bits: int # 32 or 64
def is_available(self) -> bool:
return self.gcc.exists() and self.gpp.exists()┌─────────────────────────────────────┐
│ Project/File Configuration │
└─────────────┬───────────────────────┘
│
↓
┌─────────────────┐
│ graphics=true? │
└────┬────────────┘
│
YES │ NO
│
┌────↓────┐ ┌──────────────┐
│ mingw32 │ │ openmp=true? │
└─────────┘ └──────┬───────┘
│
YES │ NO
│
┌────↓────┐ ┌──────────┐
│ mingw64 │ │ mingw64 │
└─────────┘ └──────────┘
(default)
File: src/cpplab/core/toolchains.py
def select_toolchain(config: ProjectConfig, toolchains: dict) -> Toolchain:
"""Select appropriate toolchain based on project features."""
# User override takes precedence
if config.toolchain_preference != "auto":
return toolchains.get(config.toolchain_preference)
# Graphics requires 32-bit
if config.features.get("graphics", False):
return toolchains["mingw32"]
# OpenMP prefers 64-bit
if config.features.get("openmp", False):
return toolchains["mingw64"]
# Default to 64-bit
return toolchains["mingw64"]- Graphics → 32-bit: WinBGIm library is 32-bit only
- OpenMP → 64-bit: Better performance, more memory
- Default → 64-bit: Modern systems, better performance
C_STANDARDS = {
"c99": "-std=c99",
"c11": "-std=c11",
"c17": "-std=c17",
"c18": "-std=c18", # Alias for c17
"c23": "-std=c23", # Experimental
}CPP_STANDARDS = {
"c++11": "-std=c++11",
"c++14": "-std=c++14",
"c++17": "-std=c++17",
"c++20": "-std=c++20",
"c++23": "-std=c++23", # Experimental
}-Wall # Enable all warnings
-Wextra # Extra warnings
-o <output_file> # Output fileGraphics.h Projects (32-bit):
-lbgi # WinBGIm library
-lgdi32 # Windows GDI
-lcomdlg32 # Windows dialogs
-luuid # Windows UUID
-lole32 # Windows OLE
-loleaut32 # Windows OLE AutomationOpenMP Projects (64-bit):
-fopenmp # Enable OpenMPDebug Mode (future):
-g # Include debug symbols
-O0 # No optimizationRelease Mode (future):
-O2 # Optimize for speed
-DNDEBUG # Disable assertionsInput:
ProjectConfig(
name="CircleDemo",
language="cpp",
standard="c++17",
features={"graphics": True, "openmp": False},
files=["src/main.cpp"],
main_file="src/main.cpp"
)Output Command:
C:/CppLabIDE/compilers/mingw32/bin/g++.exe \
src/main.cpp \
-std=c++17 \
-Wall \
-Wextra \
-o build/CircleDemo.exe \
-lbgi \
-lgdi32 \
-lcomdlg32 \
-luuid \
-lole32 \
-loleaut32Input:
ProjectConfig(
name="ParallelSum",
language="cpp",
standard="c++20",
features={"graphics": False, "openmp": True},
files=["src/main.cpp"],
main_file="src/main.cpp"
)Output Command:
C:/CppLabIDE/compilers/mingw64/bin/g++.exe \
src/main.cpp \
-std=c++20 \
-Wall \
-Wextra \
-fopenmp \
-o build/ParallelSum.exeInput:
ProjectConfig(
name="HelloWorld",
language="c",
standard="c17",
features={"graphics": False, "openmp": False},
files=["src/main.c"],
main_file="src/main.c"
)Output Command:
C:/CppLabIDE/compilers/mingw64/bin/gcc.exe \
src/main.c \
-std=c17 \
-Wall \
-Wextra \
-o build/HelloWorld.exeFile: src/cpplab/core/builder.py
def detect_features_from_source(source_path: Path) -> dict:
"""Detect graphics.h and OpenMP usage by scanning source code."""
features = {"graphics": False, "openmp": False}
try:
with open(source_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Check for graphics.h
if '#include' in content and 'graphics.h' in content:
features["graphics"] = True
# Check for OpenMP
if '#pragma' in content and 'omp' in content:
features["openmp"] = True
except Exception:
pass
return features1. User opens: test.cpp
2. User presses F7 (Build)
3. detect_features_from_source(test.cpp)
→ Scans for #include <graphics.h>
→ Scans for #pragma omp
4. Select toolchain based on features
5. Build with appropriate flags
Location: src/cpplab/app.py → _check_toolchains()
def _check_toolchains(self):
"""Check if toolchains are available and show warning if not."""
self.toolchains = get_toolchains()
mingw32 = self.toolchains.get("mingw32")
mingw64 = self.toolchains.get("mingw64")
missing = []
if not mingw32 or not mingw32.is_available():
missing.append("mingw32 (32-bit, required for graphics.h)")
if not mingw64 or not mingw64.is_available():
missing.append("mingw64 (64-bit, required for OpenMP)")
if missing:
msg = (
"<h3>Toolchains Not Found</h3>"
"<p>The following MinGW toolchains are missing:</p>"
"<ul>"
)
for item in missing:
msg += f"<li>{item}</li>"
msg += (
"</ul>"
"<p>Expected location: <code>compilers/</code> directory</p>"
"<p>Building will not work until toolchains are installed.</p>"
)
QMessageBox.warning(self, "Toolchains Missing", msg)If toolchains are missing:
┌─────────────────────────────────────────┐
│ ⚠ Toolchains Not Found │
├─────────────────────────────────────────┤
│ The following MinGW toolchains are │
│ missing: │
│ │
│ • mingw32 (32-bit, required for │
│ graphics.h) │
│ • mingw64 (64-bit, required for │
│ OpenMP) │
│ │
│ Expected location: compilers/ directory │
│ │
│ Building will not work until toolchains │
│ are installed. │
└─────────────────────────────────────────┘
-
Development:
compilers/relative to source code -
Frozen:
compilers/relative to .exe
def get_app_root() -> Path:
"""Get application root directory (works in dev and frozen modes)."""
if getattr(sys, 'frozen', False):
# Running as PyInstaller bundle
return Path(sys._MEIPASS).parent
else:
# Running from source
return Path(__file__).parent.parent.parentUsage:
app_root = get_app_root()
# Dev: C:/Users/Dev/CppLabEngine
# Frozen: C:/Program Files/CppLabIDE
compilers_dir = app_root / "compilers"
# Dev: C:/Users/Dev/CppLabEngine/compilers
# Frozen: C:/Program Files/CppLabIDE/compilersLocation: src/cpplab/app.py → _setup_combo_boxes()
self.toolchainComboBox = QComboBox()
self.toolchainComboBox.addItem("Auto", "auto")
self.toolchainComboBox.addItem("64-bit (mingw64)", "mingw64")
self.toolchainComboBox.addItem("32-bit (mingw32)", "mingw32")Behavior:
- Auto: Selects based on project features (default)
- 64-bit: Forces mingw64 (even for graphics - may fail)
- 32-bit: Forces mingw32 (even for OpenMP - slower)
Users can override toolchain selection:
def on_toolchain_changed(self, index: int):
"""Handle toolchain combo box selection change."""
toolchain_map = {0: "auto", 1: "mingw64", 2: "mingw32"}
value = toolchain_map.get(index, "auto")
if self.current_project:
self.current_project.toolchain_preference = value
self.current_project.save() # Persist to JSON
else:
self.standalone_toolchain_preference = valueSymptom: Warning on startup "Toolchains Not Found"
Causes:
- Missing
compilers/directory - Missing
mingw32/ormingw64/subdirectories - Missing
bin/gcc.exeorbin/g++.exe
Solution:
- Check directory structure matches expected layout
- Verify compiler executables exist and are not corrupted
- Re-extract toolchains from release package
Symptom: Build error: gcc.exe: error: CreateProcess: No such file or directory
Cause: Toolchain path contains spaces or special characters
Solution: Install CppLabIDE to path without spaces (e.g., C:\CppLabIDE)
Symptom: Linker error: cannot find -lbgi
Cause: Graphics project trying to use mingw64 (64-bit)
Solution:
- Check project configuration:
"features": {"graphics": true} - Set toolchain to "Auto" or "32-bit" explicitly
- Rebuild project
Toolchains discovered once at startup:
# MainWindow.__init__
self.toolchains = get_toolchains() # Cached for sessionBenefit: No repeated filesystem checks during builds
Absolute paths used throughout:
# Bad: Relative path (requires working directory)
cmd = ["gcc", "main.c"]
# Good: Absolute path (works from any directory)
cmd = [str(toolchain.gcc), "main.c"]Benefit: Builds work regardless of current directory
Next: Language Standards Support
Previous: Asynchronous Build System
💡 Found this wiki useful?
⭐ Star the repo
·
💖 Sponsor this project
·
📦 Latest release
·
🐞 Report an issue