-
-
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 file
Graphics.h Projects (32-bit):
-lbgi # WinBGIm library -lgdi32 # Windows GDI -lcomdlg32 # Windows dialogs -luuid # Windows UUID -lole32 # Windows OLE -loleaut32 # Windows OLE Automation
OpenMP Projects (64-bit):
-fopenmp # Enable OpenMPDebug Mode (future):
-g # Include debug symbols -O0 # No optimization
Release Mode (future):
-O2 # Optimize for speed -DNDEBUG # Disable assertions
Input:
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 \ -loleaut32
Input:
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.exe
Input:
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.exe
File: 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 features
1. 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.parent
Usage:
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/compilers
Location: 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 = value
Symptom: 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 session
Benefit: 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