Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/instructions/forward-declarations.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
applyTo: "src/**/*.h"
description: "When performing a code review on C++ headers, check that heavy headers like Vehicle.h and QGCMAVLink.h are not included when a lightweight alternative or forward declaration suffices."
---

# Forward Declaration Rules for Headers

Prefer forward declarations and lightweight type headers over including full class definitions.

## Vehicle.h

`Vehicle.h` is one of the heaviest headers in the codebase. Most headers that reference `Vehicle` only need:
- A pointer/reference to Vehicle → `class Vehicle;` forward declaration
- Vehicle type aliases → `#include "VehicleTypes.h"`

Only include `Vehicle.h` if the header calls Vehicle methods, accesses Vehicle members, or inherits from Vehicle.

## QGCMAVLink.h

`QGCMAVLink.h` combines MAVLink enums, message types, and QGC-specific type aliases. Most headers only need one of these. Use the specific lightweight header instead:
- `MAVLinkEnums.h` for enum constants
- `MAVLinkMessageType.h` for `mavlink_message_t`
- `QGCMAVLinkTypes.h` for `FirmwareClass_t`, `VehicleClass_t`
35 changes: 35 additions & 0 deletions .github/instructions/mavlink-includes.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
applyTo: "src/**/*.h"
description: "When performing a code review on C++ headers, enforce the MAVLink lightweight include hierarchy to keep moc parse times fast."
---

# MAVLink Include Rules for Headers

C++ header files must use the **lightest possible** MAVLink include. Heavy includes in headers slow Qt moc parsing dramatically (~2.5s vs ~8ms per header).

## Include Hierarchy (lightest to heaviest)

| Header | Provides | Preprocessed Lines |
|--------|----------|--------------------|
| `MAVLinkEnums.h` | All 253 MAVLink enum typedefs (MAV_CMD, MAV_TYPE, MAV_RESULT, etc.) | ~5,500 |
| `MAVLinkMessageType.h` | `mavlink_message_t`, `mavlink_channel_t`, base types | ~2,700 |
| `QGCMAVLinkTypes.h` | `FirmwareClass_t`, `VehicleClass_t`, `maxRcChannels` | ~50 |
| `VehicleTypes.h` | `MavCmdResultFailureCode_t`, `RequestMessageResultHandlerFailureCode_t` | ~30 |
| `QGCMAVLink.h` | All of the above combined | ~8,300 |
| `MAVLinkLib.h` | Full MAVLink with all 387 message pack/unpack headers | ~180,000 |

## Rules

1. **Never include `MAVLinkLib.h` in a `.h` file** unless the header uses specific MAVLink message struct types in its declarations (e.g., `mavlink_command_long_t`, `mavlink_command_ack_t`). Move message struct usage to `.cc` files when possible.

2. **Never include `Vehicle.h` just for type aliases.** Use `VehicleTypes.h` + `class Vehicle;` forward declaration instead, when only `MavCmdResultFailureCode_t` or `RequestMessageResultHandlerFailureCode_t` are needed.

3. **Pick the lightest include that satisfies the header's needs:**
- Only enum constants? → `MAVLinkEnums.h`
- `mavlink_message_t` in signatures? → `MAVLinkMessageType.h`
- Both enums and message type? → `MAVLinkEnums.h` + `MAVLinkMessageType.h` (still lighter than `QGCMAVLink.h`)
- `FirmwareClass_t` / `VehicleClass_t`? → `QGCMAVLinkTypes.h`

4. **Headers must be self-contained.** Every type used in a header's declarations must be provided by an explicit `#include`, not by the precompiled header (PCH). The PCH provides `MAVLinkLib.h` for `.cc` files, but moc processes headers independently.

5. **`MAVLinkLib.h` is fine in `.cc` files** — it's provided by the PCH anyway. Only header includes affect moc parse time.
116 changes: 116 additions & 0 deletions cmake/GenerateMAVLinkEnums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""Extract enum definitions from MAVLink dialect headers into a standalone header.

Usage: python3 GenerateMAVLinkEnums.py <mavlink_include_dir> <output_file>

Example:
python3 GenerateMAVLinkEnums.py build/_deps/mavlink-build/include/mavlink build/MAVLinkEnums.h
"""
import os
import sys

def extract_enums(dialect_header_path):
"""Extract text between '// ENUM DEFINITIONS' and '// MESSAGE DEFINITIONS' markers."""
try:
with open(dialect_header_path, 'r') as f:
lines = f.readlines()
except FileNotFoundError:
return ""

in_enums = False
enum_lines = []
for line in lines:
if '// ENUM DEFINITIONS' in line:
in_enums = True
continue
if '// MESSAGE DEFINITIONS' in line:
break
if in_enums:
enum_lines.append(line)
return ''.join(enum_lines)


def find_dialects(mavlink_dir):
"""Find all dialect directories that contain a dialect header."""
dialects = []
for entry in sorted(os.listdir(mavlink_dir)):
dialect_dir = os.path.join(mavlink_dir, entry)
dialect_header = os.path.join(dialect_dir, f"{entry}.h")
if os.path.isdir(dialect_dir) and os.path.isfile(dialect_header):
dialects.append((entry, dialect_header))
return dialects


def main():
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <mavlink_include_dir> <output_file>", file=sys.stderr)
sys.exit(1)

mavlink_dir = sys.argv[1]
output_file = sys.argv[2]

if not os.path.isdir(mavlink_dir):
print(f"Error: {mavlink_dir} is not a directory", file=sys.stderr)
sys.exit(1)

dialects = find_dialects(mavlink_dir)
if not dialects:
print(f"Error: no dialect headers found in {mavlink_dir}", file=sys.stderr)
sys.exit(1)

# Build output
parts = []
parts.append("""\
#pragma once

/// @file MAVLinkEnums.h
/// @brief MAVLink enum definitions only - no message pack/unpack code.
///
/// AUTO-GENERATED from MAVLink dialect headers during the build.
/// Do not edit manually. Regenerate via cmake/GenerateMAVLinkEnums.py.
///
/// This header provides all MAVLink enum typedefs (~3,700 lines) without
/// the ~177,000 lines of message pack/encode/decode functions.
/// Use this in headers that need MAVLink enum types (MAV_CMD, MAV_TYPE, etc.)
/// but don't need message struct definitions.

#ifdef __cplusplus
extern "C" {
#endif
""")

for name, path in dialects:
enums = extract_enums(path)
if enums.strip():
parts.append(f"\n// ---- enums from {name}/{name}.h ----\n")
parts.append(enums)

parts.append("""
#ifdef __cplusplus
}
#endif
""")

output = ''.join(parts)

# Ensure output directory exists
os.makedirs(os.path.dirname(os.path.abspath(output_file)), exist_ok=True)

# Only write if content changed (avoid unnecessary rebuilds)
if os.path.isfile(output_file):
with open(output_file, 'r') as f:
if f.read() == output:
print(f"MAVLinkEnums.h is up to date ({output_file})")
return

with open(output_file, 'w') as f:
f.write(output)

# Count enums
enum_count = output.count('typedef enum')
line_count = output.count('\n')
print(f"Generated {output_file}: {line_count} lines, {enum_count} enums from {len(dialects)} dialects")


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion src/ADSB/ADSB.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"

#include <QtCore/QMetaType>
#include <QtPositioning/QGeoCoordinate>
Expand Down
1 change: 1 addition & 0 deletions src/ADSB/ADSBVehicleManager.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "ADSBVehicleManager.h"
#include "MAVLinkLib.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "ADSBVehicleManagerSettings.h"
Expand Down
2 changes: 1 addition & 1 deletion src/ADSB/ADSBVehicleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <QtCore/QObject>

#include "ADSB.h"
#include "MAVLinkLib.h"
#include "MAVLinkMessageType.h"

Q_DECLARE_LOGGING_CATEGORY(ADSBVehicleManagerLog)

Expand Down
1 change: 1 addition & 0 deletions src/API/QGCCorePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "AppSettings.h"
#include "MavlinkSettings.h"
#include "FactMetaData.h"
#include "QGCMAVLink.h"
#ifdef QGC_GST_STREAMING
#include "GStreamer.h"
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtCore/QString>
#include <QtQmlIntegration/QtQmlIntegration>

#include "MAVLinkLib.h"
#include "MAVLinkMessageType.h"

Q_DECLARE_LOGGING_CATEGORY(MAVLinkInspectorControllerLog)

Expand Down
1 change: 1 addition & 0 deletions src/AnalyzeView/MAVLinkInspector/MAVLinkMessage.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "MAVLinkMessage.h"
#include "MAVLinkLib.h"
#include "MAVLinkMessageField.h"
#include "QGCLoggingCategory.h"
#include "QmlObjectListModel.h"
Expand Down
2 changes: 1 addition & 1 deletion src/AnalyzeView/MAVLinkInspector/MAVLinkMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtCore/QLoggingCategory>
#include <QtQmlIntegration/QtQmlIntegration>

#include "MAVLinkLib.h"
#include "MAVLinkMessageType.h"

class QmlObjectListModel;

Expand Down
4 changes: 2 additions & 2 deletions src/AutoPilotPlugins/APM/APMFlightModesComponentController.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtQmlIntegration/QtQmlIntegration>

#include "FactPanelController.h"
#include "QGCMAVLink.h"
#include "QGCMAVLinkTypes.h"

/// MVC Controller for FlightModesComponent.qml.
class APMFlightModesComponentController : public FactPanelController
Expand Down Expand Up @@ -57,7 +57,7 @@ private slots:
Fact *_superSimpleModeFact = nullptr;
const bool _simpleModesSupported = false;
int _activeFlightMode = 0;
int _channelCount = QGCMAVLink::maxRcChannels;
int _channelCount = QGCMAVLinkTypes::maxRcChannels;
int _simpleMode = SimpleModeStandard;
QString _modeChannelParam;
QString _modeParamPrefix;
Expand Down
2 changes: 1 addition & 1 deletion src/AutoPilotPlugins/Common/ESP8266ComponentController.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtQmlIntegration/QtQmlIntegration>

#include "FactPanelController.h"
#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"

Q_DECLARE_LOGGING_CATEGORY(ESP8266ComponentControllerLog)

Expand Down
1 change: 1 addition & 0 deletions src/AutoPilotPlugins/PX4/ActuatorComponent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "QGCApplication.h"
#include "GeometryImage.h"
#include "Actuators/Actuators.h"
#include "Vehicle.h"

#include <QtQml/QQmlApplicationEngine>

Expand Down
1 change: 0 additions & 1 deletion src/AutoPilotPlugins/PX4/PX4SimpleFlightModesController.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <QtQmlIntegration/QtQmlIntegration>

#include "FactPanelController.h"
#include "QGCMAVLink.h"

/// MVC Controller for PX4SimpleFlightModes.qml
class PX4SimpleFlightModesController : public FactPanelController
Expand Down
2 changes: 2 additions & 0 deletions src/Camera/QGCCameraManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
#include "FirmwarePlugin.h"
#include "Joystick.h"
#include "JoystickManager.h"
#include "MAVLinkLib.h"
#include "MavlinkCameraControlInterface.h"
#include "MultiVehicleManager.h"
#include "QGCLoggingCategory.h"
#include "QGCVideoStreamInfo.h"
#include "SimulatedCameraControl.h"
#include "Vehicle.h"

#include <cmath>
#include "GimbalControllerSettings.h"
Expand Down
9 changes: 5 additions & 4 deletions src/Camera/QGCCameraManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
#include <QtCore/QVariantList>
#include <QtQmlIntegration/QtQmlIntegration>

#include "MAVLinkLib.h"
#include "MAVLinkMessageType.h"
#include "QmlObjectListModel.h"
#include "Vehicle.h"

class Vehicle;

Q_DECLARE_LOGGING_CATEGORY(CameraManagerLog)

Expand Down Expand Up @@ -54,7 +55,7 @@ class QGCCameraManager : public QObject
int retryCount = 0;
QElapsedTimer lastHeartbeat;
QTimer backoffTimer;
QPointer<Vehicle> vehicle;
Vehicle* vehicle; ///< Raw pointer is safe: CameraStruct is owned by QGCCameraManager which is a child of Vehicle
QPointer<QGCCameraManager> manager;

private:
Expand Down Expand Up @@ -128,7 +129,7 @@ private slots:
void _addCameraControlToLists(MavlinkCameraControlInterface* cameraControl);
void _handleCameraFovStatus(const mavlink_message_t& message);

QPointer<Vehicle> _vehicle;
Vehicle* _vehicle; ///< Raw pointer is safe: QGCCameraManager is a QObject child of Vehicle, so Vehicle always outlives us
QPointer<SimulatedCameraControl> _simulatedCameraControl;
QPointer<Joystick> _activeJoystick;
bool _vehicleReadyState = false;
Expand Down
3 changes: 2 additions & 1 deletion src/Comms/MAVLinkProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#include <QtCore/QString>

#include "LinkInterface.h"
#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"
#include "MAVLinkMessageType.h"

class QFile;

Expand Down
2 changes: 1 addition & 1 deletion src/Comms/MockLink/MockConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "LinkConfiguration.h"

#include <QtCore/QLoggingCategory>
#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"

Q_DECLARE_LOGGING_CATEGORY(MockConfigurationLog)

Expand Down
2 changes: 1 addition & 1 deletion src/FactSystem/FactGroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <QtQmlIntegration/QtQmlIntegration>

#include "Fact.h"
#include "MAVLinkLib.h"
#include "MAVLinkMessageType.h"

class Vehicle;

Expand Down
2 changes: 1 addition & 1 deletion src/FactSystem/FactGroupListModel.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "QmlObjectListModel.h"
#include "QGCMAVLink.h"
#include "MAVLinkMessageType.h"
#include "FactGroupWithId.h"

#include <QList>
Expand Down
3 changes: 2 additions & 1 deletion src/FactSystem/ParameterManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

#include "Fact.h"
#include "FactMetaData.h"
#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"
#include "MAVLinkMessageType.h"

Q_DECLARE_LOGGING_CATEGORY(ParameterManagerLog)
Q_DECLARE_LOGGING_CATEGORY(ParameterManagerVerbose1Log)
Expand Down
2 changes: 1 addition & 1 deletion src/FirmwarePlugin/APM/APMParameterMetaData.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtCore/QObject>
#include <QtCore/QXmlStreamReader>

#include "MAVLinkLib.h"
#include "MAVLinkEnums.h"
#include "FactMetaData.h"

Q_DECLARE_LOGGING_CATEGORY(APMParameterMetaDataLog)
Expand Down
1 change: 1 addition & 0 deletions src/FirmwarePlugin/FirmwarePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "QGCCameraManager.h"
#include "QGCFileDownload.h"
#include "QGCLoggingCategory.h"
#include "Vehicle.h"
#include "VehicleCameraControl.h"
#include "VehicleComponent.h"

Expand Down
Loading
Loading