-
-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Overview
This document describes the high-level architecture and design of CppLab IDE. Now, keep in mind that everything shown here is just the gist of what I did. I do plan on putting a proper diagram here once my exams are over but for now, I just wanted a pretty wiki with some basic diagram, and here it is. Now, this is mostly for documenting purposes but if you want to understand what was I thinking, making an IDE for C/C++ in Python, well, this is a good place to start.
CppLab IDE follows a layered architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ User Interface Layer │
│ (PyQt6 - MainWindow, Dialogs, Widgets) │
├─────────────────────────────────────────────────────────────┤
│ Application Logic Layer │
│ (Project Management, File Management, Settings) │
├─────────────────────────────────────────────────────────────┤
│ Build & Execution Layer │
│ (Async BuildWorker, Toolchain Management, Compiler) │
├─────────────────────────────────────────────────────────────┤
│ Data Persistence Layer │
│ (JSON Config Files, Settings Storage) │
└─────────────────────────────────────────────────────────────┘
CppLabEngine/
├── src/cpplab/ # Main application package
│ ├── __init__.py # Package init with version
│ ├── main.py # Application entry point
│ ├── app.py # MainWindow class (1000+ lines)
│ ├── dialogs.py # Project dialogs (NewProject, etc.)
│ ├── settings.py # Settings data model and persistence
│ ├── settings_dialog.py # Settings UI dialog
│ │
│ ├── ui/ # Qt Designer UI files
│ │ ├── MainWindow.ui
│ │ └── NewProjectDialog.ui
│ │
│ ├── widgets/ # Custom Qt widgets
│ │ ├── code_editor.py # Syntax-highlighted editor
│ │ ├── project_explorer.py # File tree view
│ │ └── output_panel.py # Build output display
│ │
│ └── core/ # Core business logic
│ ├── project_config.py # Project data model
│ ├── toolchains.py # Compiler configuration
│ └── builder.py # Build system (500+ lines)
│
├── compilers/ # Bundled MinGW toolchains
│ ├── mingw32/ # 32-bit (graphics.h)
│ └── mingw64/ # 64-bit (OpenMP)
│
├── docs/ # Offline documentation
├── examples/ # Sample projects
├── tests/ # Unit and integration tests
└── tools/ # Build and release scripts
└── build_release.py
Responsibilities:
- Central application controller
- UI event handling and routing
- State management (current project, open files)
- Async build coordination
Key Attributes:
self.current_project: Optional[ProjectConfig] # Active project
self.toolchains: dict # MinGW toolchains
self.open_editors: dict[str, CodeEditor] # Open file editors
self.build_in_progress: bool # Async build state
self.settings: AppSettings # User preferencesKey Methods:
-
start_build_task()- Initiate async builds -
on_build_finished()- Handle build completion -
build_current()/run_current()- Build/run workflows -
apply_settings()- Apply theme and font changes
Responsibilities:
- Execute compilation in background thread
- Emit progress signals to UI
- Handle build errors gracefully
Architecture:
class BuildWorker(QObject):
started = pyqtSignal()
finished = pyqtSignal(object) # BuildResult
error = pyqtSignal(str)
def run(self):
# Executes in QThread
# Calls builder.py functions
# Emits signals to MainWindowResponsibilities:
- Compile C/C++ source files
- Manage incremental builds
- Link with appropriate libraries
- Auto-detect features (graphics.h, OpenMP)
Key Functions:
build_project(config, toolchains, force_rebuild) -> BuildResult
build_single_file(path, toolchains, ...) -> BuildResult
check_project(config, toolchains) -> BuildResult # Syntax only
check_single_file(path, toolchains, ...) -> BuildResultBuildResult Structure:
@dataclass
class BuildResult:
success: bool
command: list[str]
stdout: str
stderr: str
exe_path: Optional[Path]
elapsed_ms: float
skipped: boolResponsibilities:
- Discover MinGW installations
- Select appropriate toolchain (32/64-bit)
- Provide compiler paths and flags
Toolchain Selection Logic:
if graphics_required:
toolchain = mingw32 # 32-bit required for WinBGIm
elif openmp_required:
toolchain = mingw64 # 64-bit recommended for OpenMP
else:
toolchain = mingw64 # Default to 64-bitResponsibilities:
- Store project metadata
- Serialize/deserialize to JSON
- Manage source file lists
Structure:
@dataclass
class ProjectConfig:
name: str
root_path: Path
language: str # "c" or "cpp"
standard: str # "c17", "c++20", etc.
project_type: str # "console" or "graphics"
features: dict # {"graphics": bool, "openmp": bool}
files: list[str]
main_file: str
toolchain_preference: str # "auto", "mingw32", "mingw64"- Syntax highlighting via QSyntaxHighlighter
- Line numbers in margin
- Modified state tracking
- File path association
- QTreeView-based file browser
- File double-click → open in editor
- Context menu (future: add/remove files)
- Build output display
- Auto-scroll to bottom
- Monospace font (Consolas)
- Clear/append operations
User Action (Fn+F5 or F5/F7)
↓
MainWindow.build_current()
↓
start_build_task()
↓
Create BuildWorker + QThread
↓
worker.run() [Background Thread]
↓
builder.build_project/build_single_file()
↓
Execute g++/gcc command
↓
BuildResult with elapsed_ms
↓
worker.finished signal
↓
MainWindow.on_build_finished()
↓
Update UI (status bar, output panel)
User: File → Open Project
↓
MainWindow.on_open_project()
↓
Load cpplab_project.json
↓
ProjectConfig.load()
↓
Update UI (tree, toolchain combo, standard combo)
↓
Open main file in editor
- All UI operations
- User input handling
- Signal/slot connections
- Widget updates
- Build operations (BuildWorker)
- File operations (future: large file loading)
- External process monitoring (future: debugger)
-
BuildWorker uses
QObject+moveToThread()pattern (PyQt6 best practice) - No direct UI updates from worker threads
- All communication via Qt signals (thread-safe)
- Worker auto-deleted after completion (
deleteLater())
# Global
current_project: Optional[ProjectConfig]
open_editors: dict[str, CodeEditor]
standalone_files: set[Path]
# Build State
build_in_progress: bool
current_build_thread: Optional[QThread]
_pending_run_after_build: bool
# Settings
settings: AppSettings # Loaded from ~/.cpplab/settings.json- Stored in
<project_root>/cpplab_project.json - Version controlled with project
- Contains all build configuration
- Stored in
~/.cpplab/settings.json - User-specific preferences
- Not version controlled
- Model: ProjectConfig, AppSettings
- View: Qt Widgets (.ui files)
- Controller: MainWindow (app.py)
- Qt Signals/Slots for event handling
- BuildWorker emits progress signals
- Widgets emit interaction signals
-
create_new_project()creates ProjectConfig - Toolchain selection based on features
-
BuildResultaccumulates build information - Command construction in builder.py
- Different build strategies (project vs standalone)
- Toolchain selection strategies
-
QMessageBoxfor user-facing errors - Non-blocking error dialogs
- Status bar for quick feedback
- Try/catch in BuildWorker.run()
- Emit
errorsignal on exception - BuildResult captures compiler errors
- Path validation before operations
- Exception handling with user feedback
- Auto-create directories as needed
Future enhancements can be added at these points:
- [] New Project Types: Add to
ProjectConfig.project_type - [] Additional Toolchains: Extend
toolchains.py - Language Support: Add syntax highlighters
- [] Build Profiles: Add Debug/Release modes
- [] Plugin System: Load external Python modules
- Lazy widget initialization
- Toolchain discovery cached
- UI loaded from .ui files (fast)
- Asynchronous compilation (no freezing)
- Incremental builds (skip unchanged)
- Syntax-only checks (fast feedback)
- Single OutputPanel shared
- Editors created on-demand
- Build threads auto-deleted
- JSON config files (small, fast)
- Minimal file watching (manual reload)
- Build artifacts in separate
build/dir
💡 Found this wiki useful?
⭐ Star the repo
·
💖 Sponsor this project
·
📦 Latest release
·
🐞 Report an issue