# MeshMC_SDK CMake Package Configuration

This page is a deep dive into the CMake package configuration files that
power the `find_package(MeshMC_SDK)` mechanism for out-of-tree plugin
development.  It covers every file installed by the SDK, the targets they
define, the variables they set, and how version compatibility works.

If you just want to build a plugin, see [out-of-tree-setup.md](out-of-tree-setup.md).
This page is for developers who want to understand or debug the SDK's CMake
integration.

---

## Table of Contents

1. [Overview](#1-overview)
2. [Installed files](#2-installed-files)
3. [MeshMCSDKConfig.cmake](#3-meshmcsdkconfigcmake)
4. [MeshMCSDKTargets.cmake](#4-meshmcsdktargetscmake)
5. [MeshMCSDKConfigVersion.cmake](#5-meshmcsdkconfigversioncmake)
6. [The MeshMC::SDK INTERFACE target](#6-the-meshmc-sdk-interface-target)
7. [Include directories](#7-include-directories)
8. [Linked libraries](#8-linked-libraries)
9. [Generator expressions: build-tree vs install-tree](#9-generator-expressions-build-tree-vs-install-tree)
10. [Install prefix and paths](#10-install-prefix-and-paths)
11. [How find_package finds the SDK](#11-how-find_package-finds-the-sdk)
12. [Debugging CMake configuration](#12-debugging-cmake-configuration)
13. [Source reference: CMakeLists.txt](#13-source-reference-cmakeliststxt)

---

## 1. Overview

The MeshMC Plugin SDK installs a standard CMake package config so that
out-of-tree plugins can discover and use the SDK with:

```cmake
find_package(MeshMC_SDK REQUIRED)
target_link_libraries(MyPlugin PRIVATE MeshMC::SDK)
```

This is implemented using CMake's
[`configure_package_config_file`](https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html)
and
[`write_basic_package_version_file`](https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:write_basic_package_version_file)
helpers, following the official CMake packaging conventions.

---

## 2. Installed Files

The SDK installs three CMake config files and the SDK headers:

```
<prefix>/
├── include/
│   └── meshmc-sdk/             # SDK headers (see README.md for full tree)
│       └── ...
└── lib/
    └── cmake/
        └── MeshMC_SDK/
            ├── MeshMCSDKConfig.cmake          # Package config entry point
            ├── MeshMCSDKConfigVersion.cmake    # Version compatibility check
            └── MeshMCSDKTargets.cmake          # Exported INTERFACE target
```

### File roles

| File | Purpose |
|------|---------|
| `MeshMCSDKConfig.cmake` | Entry point for `find_package(MeshMC_SDK)`.  Includes the targets file and runs `check_required_components`. |
| `MeshMCSDKTargets.cmake` | Defines the `MeshMC::SDK` IMPORTED INTERFACE target with its include directories and link dependencies. |
| `MeshMCSDKConfigVersion.cmake` | Implements version compatibility checking.  Generated by `write_basic_package_version_file`. |

---

## 3. MeshMCSDKConfig.cmake

This file is generated at build time from the template
`MeshMCSDKConfig.cmake.in` using `configure_package_config_file`.

### Template source

The template lives in the MeshMC source tree at:

```
meshmc/launcher/plugin/sdk/MeshMCSDKConfig.cmake.in
```

Its contents:

```cmake
@PACKAGE_INIT@

# MeshMC Plugin SDK — CMake package config
#
# Usage in out-of-tree plugin CMakeLists.txt:
#
#   cmake_minimum_required(VERSION 3.21)
#   project(MyPlugin)
#   find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
#   find_package(MeshMC_SDK REQUIRED)
#   add_library(MyPlugin MODULE src/MyPlugin.cpp)
#   target_link_libraries(MyPlugin PRIVATE MeshMC::SDK)
#   set_target_properties(MyPlugin PROPERTIES PREFIX "" SUFFIX ".mmco")

include("${CMAKE_CURRENT_LIST_DIR}/MeshMCSDKTargets.cmake")
check_required_components(MeshMC_SDK)
```

### What happens at configure time

1. CMake's `configure_package_config_file` replaces `@PACKAGE_INIT@` with
   boilerplate code that sets up `PACKAGE_PREFIX_DIR` and path-computation
   macros.

2. The generated file is written to the build directory:
   `${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfig.cmake`

3. At install time, it is placed at:
   `<prefix>/lib/cmake/MeshMC_SDK/MeshMCSDKConfig.cmake`

### What happens when a plugin calls find_package

1. CMake searches `CMAKE_PREFIX_PATH` and standard paths for
   `lib/cmake/MeshMC_SDK/MeshMCSDKConfig.cmake`.

2. The config file is loaded.  The `@PACKAGE_INIT@`-generated preamble
   computes `PACKAGE_PREFIX_DIR` (the install prefix).

3. `include("${CMAKE_CURRENT_LIST_DIR}/MeshMCSDKTargets.cmake")` loads the
   exported targets.

4. `check_required_components(MeshMC_SDK)` verifies that all requested
   components are available (the SDK has no optional components, so this is a
   no-op in practice).

---

## 4. MeshMCSDKTargets.cmake

This file is generated by CMake's `install(EXPORT ...)` command.  It defines
the `MeshMC::SDK` IMPORTED INTERFACE target.

### Generation

In the SDK `CMakeLists.txt`:

```cmake
install(TARGETS MeshMC_sdk
    EXPORT MeshMCSDKTargets
)

install(EXPORT MeshMCSDKTargets
    FILE MeshMCSDKTargets.cmake
    NAMESPACE MeshMC::
    DESTINATION "lib/cmake/MeshMC_SDK"
)
```

- `EXPORT MeshMCSDKTargets` — associates the `MeshMC_sdk` target with the
  export set named `MeshMCSDKTargets`.
- `NAMESPACE MeshMC::` — when the export file is loaded, the target is
  available as `MeshMC::SDK` (the namespace is prepended to the target's
  export name).
- The export name comes from the `ALIAS` target: `MeshMC::SDK` aliases
  `MeshMC_sdk`.

### What the file defines

The generated `MeshMCSDKTargets.cmake` creates an IMPORTED INTERFACE library
target with approximately these properties (simplified):

```cmake
add_library(MeshMC::SDK INTERFACE IMPORTED)

set_target_properties(MeshMC::SDK PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES
        "${_IMPORT_PREFIX}/include/meshmc-sdk;${_IMPORT_PREFIX}/include/meshmc-sdk/plugin/sdk"
    INTERFACE_LINK_LIBRARIES
        "Qt6::Core;Qt6::Widgets;Qt6::Gui"
)
```

The actual generated file contains additional CMake boilerplate for path
computation (`_IMPORT_PREFIX`) and guards against double-inclusion.

---

## 5. MeshMCSDKConfigVersion.cmake

This file implements version compatibility checking for `find_package` calls
that request a specific version:

```cmake
find_package(MeshMC_SDK 1.0.0 REQUIRED)
```

### Generation

```cmake
write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfigVersion.cmake"
    VERSION "${MeshMC_RELEASE_VERSION_NAME}"
    COMPATIBILITY AnyNewerVersion
)
```

- **VERSION** — set to the MeshMC release version string (e.g. `"9.2.0"`).
  This is the value of the `MeshMC_RELEASE_VERSION_NAME` CMake variable,
  defined in the top-level MeshMC `CMakeLists.txt`.

- **COMPATIBILITY `AnyNewerVersion`** — the SDK is considered compatible if
  the installed version is *equal to or newer than* the requested version.
  This is the most permissive compatibility mode.

### Version matching examples

| Installed SDK | Requested version | Result |
|---------------|------------------|--------|
| 9.2.0 | `find_package(MeshMC_SDK)` | Match (no version constraint) |
| 9.2.0 | `find_package(MeshMC_SDK 9.0.0)` | Match (9.2.0 ≥ 9.0.0) |
| 9.2.0 | `find_package(MeshMC_SDK 9.2.0)` | Match (exact) |
| 9.2.0 | `find_package(MeshMC_SDK 9.3.0)` | **No match** (9.2.0 < 9.3.0) |
| 10.0.0 | `find_package(MeshMC_SDK 9.0.0)` | Match (10.0.0 ≥ 9.0.0) |

### ABI compatibility note

The `AnyNewerVersion` compatibility policy does **not** guarantee ABI
stability across major versions.  The `MMCO_ABI_VERSION` constant in
`mmco_sdk.h` (currently `1`) is the true ABI version.  If MeshMC changes the
ABI, this constant will be incremented and the loader will reject modules
compiled against an older ABI.

The CMake version compatibility is a convenience for `find_package` — it does
not replace runtime ABI checking.

---

## 6. The MeshMC::SDK INTERFACE Target

The heart of the SDK is the `MeshMC::SDK` target — a CMake INTERFACE library
that carries no compiled code.  It only provides:

1. **Include directories** — paths to all SDK headers.
2. **Link libraries** — transitive dependencies on Qt6 modules.

### Definition (in the SDK's CMakeLists.txt)

```cmake
add_library(MeshMC_sdk INTERFACE)
add_library(MeshMC::SDK ALIAS MeshMC_sdk)
```

The `ALIAS` target name (`MeshMC::SDK`) is what consumers use.  The real
target name (`MeshMC_sdk`) is what CMake tracks internally and exports.

### Properties

| Property | Value |
|----------|-------|
| Type | INTERFACE (header-only, no compiled artefacts) |
| Alias | `MeshMC::SDK` |
| Export name | `MeshMC_sdk` (with `MeshMC::` namespace in export set) |
| Include directories | See [Section 7](#7-include-directories) |
| Link libraries | See [Section 8](#8-linked-libraries) |

### Usage in consumer CMakeLists.txt

```cmake
target_link_libraries(MyPlugin PRIVATE MeshMC::SDK)
```

This single line propagates all include directories and Qt6 link dependencies
to `MyPlugin`.

---

## 7. Include Directories

The SDK target registers include directories with generator expressions to
support both build-tree and install-tree usage.

### Build-tree (in-tree plugins)

```cmake
target_include_directories(MeshMC_sdk INTERFACE
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/launcher>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/launcher/plugin/sdk>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/libraries/optional-bare/include>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/libraries/katabasis/include>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/buildconfig>
)
```

These paths point into the MeshMC source tree and are only used when the
target is consumed from within the same CMake build (i.e. in-tree plugins).

| Path | Contains |
|------|----------|
| `${CMAKE_SOURCE_DIR}/launcher` | All launcher headers: `Application.h`, `BaseInstance.h`, `InstanceList.h`, plus `minecraft/`, `net/`, `java/`, `settings/`, `tasks/`, `ui/pages/`, `updater/` subtrees |
| `${CMAKE_SOURCE_DIR}/launcher/plugin/sdk` | `mmco_sdk.h` |
| `${CMAKE_SOURCE_DIR}/libraries/optional-bare/include` | `nonstd/optional` |
| `${CMAKE_SOURCE_DIR}/libraries/katabasis/include` | `katabasis/Bits.h` |
| `${CMAKE_SOURCE_DIR}/buildconfig` | Generated build configuration headers |

### Install-tree (out-of-tree plugins)

```cmake
target_include_directories(MeshMC_sdk INTERFACE
    $<INSTALL_INTERFACE:include/meshmc-sdk>
    $<INSTALL_INTERFACE:include/meshmc-sdk/plugin/sdk>
)
```

These paths are relative to the install prefix and are used when the target is
consumed via `find_package(MeshMC_SDK)`.

| Installed path | Contains |
|----------------|----------|
| `<prefix>/include/meshmc-sdk` | Root-level launcher headers (`Application.h`, etc.), plus all subtree directories (`minecraft/`, `net/`, `java/`, `settings/`, `tasks/`, `ui/`, `updater/`, `nonstd/`, `katabasis/`) |
| `<prefix>/include/meshmc-sdk/plugin/sdk` | `mmco_sdk.h` |

### Why two include paths?

The `mmco_sdk.h` header uses `#include "Application.h"` (without a path
prefix), which must resolve to `<root>/Application.h`.  At the same time,
a plugin's `#include "mmco_sdk.h"` must find the header itself.  The two
include paths ensure both resolve correctly:

- `include/meshmc-sdk` → makes `Application.h`, `BaseInstance.h`, etc.
  resolvable by `mmco_sdk.h`'s includes.
- `include/meshmc-sdk/plugin/sdk` → makes `mmco_sdk.h` resolvable by the
  plugin's `#include "mmco_sdk.h"`.

---

## 8. Linked Libraries

```cmake
target_link_libraries(MeshMC_sdk INTERFACE
    Qt6::Core
    Qt6::Widgets
    Qt6::Gui
)
```

These are INTERFACE link dependencies — they propagate to any target that links
`MeshMC::SDK`.

| Library | Why it's needed |
|---------|----------------|
| `Qt6::Core` | `QString`, `QStringList`, `QList`, `QDir`, `QFile`, `QFileInfo`, `QDirIterator`, `QDateTime`, `QDebug`, `QRegularExpression`, `QJsonObject` |
| `Qt6::Widgets` | `QApplication`, `QWidget`, `QLabel`, `QLineEdit`, `QPushButton`, `QTreeWidget`, `QTreeWidgetItem`, `QHeaderView`, `QHBoxLayout`, `QVBoxLayout`, `QMenu`, `QMessageBox`, `QInputDialog`, `QFileDialog` |
| `Qt6::Gui` | `QIcon` |

### For in-tree plugins

In-tree plugins also link `MeshMC_logic`, which pulls in additional Qt modules
and all MeshMC compiled code.  The Qt6 dependencies from `MeshMC::SDK` are
redundant in this case but harmless (CMake deduplicates).

### For out-of-tree plugins

Out-of-tree plugins **must** call `find_package(Qt6 REQUIRED COMPONENTS Core
Widgets Gui)` before `find_package(MeshMC_SDK)` so that the `Qt6::Core`,
`Qt6::Widgets`, and `Qt6::Gui` targets exist when the SDK's config file
references them.

If Qt6 has not been found, loading `MeshMCSDKTargets.cmake` will fail with:

```
The imported target "MeshMC::SDK" references the file "" but this file does
not exist.  [...] references Qt6::Core which is not an existing target.
```

---

## 9. Generator Expressions: Build-Tree vs Install-Tree

CMake generator expressions (`$<BUILD_INTERFACE:...>` and
`$<INSTALL_INTERFACE:...>`) ensure the correct include paths are used
depending on context:

| Context | Active expression | Include paths |
|---------|------------------|---------------|
| **Build-tree** (in-tree plugin in the same CMake build) | `$<BUILD_INTERFACE:...>` | Source-tree paths (`${CMAKE_SOURCE_DIR}/launcher`, etc.) |
| **Install-tree** (out-of-tree plugin via `find_package`) | `$<INSTALL_INTERFACE:...>` | Install-relative paths (`include/meshmc-sdk`, etc.) |

This is standard CMake practice for header-only libraries that need to work
both as part of a larger build and as an installed package.

### How it works at install time

When `install(TARGETS MeshMC_sdk EXPORT MeshMCSDKTargets)` is processed,
CMake evaluates the `$<INSTALL_INTERFACE:...>` expressions and writes the
resolved paths into `MeshMCSDKTargets.cmake`.  The `$<BUILD_INTERFACE:...>`
expressions evaluate to empty strings at install time.

When the export file is loaded by `find_package`, the paths are resolved
relative to the install prefix using the `_IMPORT_PREFIX` variable computed
in the targets file.

---

## 10. Install Prefix and Paths

### Install destination for config files

```cmake
configure_package_config_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/MeshMCSDKConfig.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfig.cmake"
    INSTALL_DESTINATION "lib/cmake/MeshMC_SDK"
)
```

The `INSTALL_DESTINATION` is `lib/cmake/MeshMC_SDK`.  This tells
`configure_package_config_file` where the config file will be installed so it
can compute the correct `PACKAGE_PREFIX_DIR`.

### Full install paths

| Component | Install path (relative to prefix) |
|-----------|----------------------------------|
| Config entry point | `lib/cmake/MeshMC_SDK/MeshMCSDKConfig.cmake` |
| Version file | `lib/cmake/MeshMC_SDK/MeshMCSDKConfigVersion.cmake` |
| Targets file | `lib/cmake/MeshMC_SDK/MeshMCSDKTargets.cmake` |
| SDK own header | `include/meshmc-sdk/plugin/sdk/mmco_sdk.h` |
| Plugin API headers | `include/meshmc-sdk/plugin/PluginAPI.h`, `PluginHooks.h`, `MMCOFormat.h` |
| Launcher headers | `include/meshmc-sdk/*.h` |
| Sub-tree headers | `include/meshmc-sdk/minecraft/`, `net/`, `java/`, etc. |
| Library headers | `include/meshmc-sdk/nonstd/optional`, `include/meshmc-sdk/katabasis/Bits.h` |

### Standard prefix values

| Platform | Typical prefix | How set |
|----------|---------------|---------|
| Linux (from source) | `/usr/local` | `cmake --install build --prefix /usr/local` |
| Linux (distro package) | `/usr` | Package manager |
| macOS (from source) | `/usr/local` | `cmake --install build --prefix /usr/local` |
| Windows | `C:/Program Files/MeshMC` | Install wizard or `cmake --install` |

---

## 11. How find_package Finds the SDK

CMake's `find_package(MeshMC_SDK)` searches the following locations (in
order):

1. Paths in `CMAKE_PREFIX_PATH` — e.g. `/usr/local` → looks for
   `/usr/local/lib/cmake/MeshMC_SDK/MeshMCSDKConfig.cmake`

2. Paths in `MeshMC_SDK_DIR` — if set, this must point directly to the
   directory containing `MeshMCSDKConfig.cmake`.

3. Standard system paths:
   - Linux: `/usr/lib/cmake/MeshMC_SDK/`, `/usr/local/lib/cmake/MeshMC_SDK/`
   - macOS: same, plus `/opt/homebrew/lib/cmake/MeshMC_SDK/`
   - Windows: `C:/Program Files/MeshMC/lib/cmake/MeshMC_SDK/` (via registry)

### Recommended approach

Set `CMAKE_PREFIX_PATH` to include the MeshMC install prefix:

```bash
cmake -B build -DCMAKE_PREFIX_PATH="/usr/local"
```

If Qt6 is in a different prefix, list both (semicolon-separated):

```bash
cmake -B build -DCMAKE_PREFIX_PATH="/usr/local;/opt/qt6"
```

### Direct path override

For non-standard setups, bypass the search entirely:

```bash
cmake -B build -DMeshMC_SDK_DIR="/custom/path/lib/cmake/MeshMC_SDK"
```

---

## 12. Debugging CMake Configuration

### Verbose find_package output

Enable `--debug-find` to see CMake's search process:

```bash
cmake -B build --debug-find -DCMAKE_PREFIX_PATH="/usr/local" 2>&1 | grep -i meshmc
```

### Print SDK properties after find

Add this to your plugin's `CMakeLists.txt` temporarily:

```cmake
find_package(MeshMC_SDK REQUIRED)

get_target_property(SDK_INCLUDES MeshMC::SDK INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(SDK_LIBS MeshMC::SDK INTERFACE_LINK_LIBRARIES)

message(STATUS "MeshMC::SDK include dirs: ${SDK_INCLUDES}")
message(STATUS "MeshMC::SDK link libs: ${SDK_LIBS}")
```

Expected output:

```
-- MeshMC::SDK include dirs: /usr/local/include/meshmc-sdk;/usr/local/include/meshmc-sdk/plugin/sdk
-- MeshMC::SDK link libs: Qt6::Core;Qt6::Widgets;Qt6::Gui
```

### Check package version

```cmake
find_package(MeshMC_SDK REQUIRED)
message(STATUS "MeshMC SDK version: ${MeshMC_SDK_VERSION}")
```

### Common issues

| Problem | Diagnosis | Fix |
|---------|-----------|-----|
| Config not found | `find_package` error message | Set `CMAKE_PREFIX_PATH` or `MeshMC_SDK_DIR` |
| Wrong version | `MeshMC_SDK_VERSION` too old | Reinstall newer MeshMC SDK |
| Qt6 targets missing | Error when loading targets file | Call `find_package(Qt6 ...)` before `find_package(MeshMC_SDK)` |
| Include paths empty | `get_target_property` returns empty | SDK headers not installed — re-run `cmake --install` |

---

## 13. Source Reference: CMakeLists.txt

Here is the complete SDK `CMakeLists.txt` with annotations keyed to the
sections above.

```cmake
# MeshMC Plugin SDK — headers and CMake config for .mmco module development
#
# This target provides:
#   - The mmco_sdk.h single-include header
#   - PluginAPI.h / PluginHooks.h / MMCOFormat.h  (C ABI definitions)
#   - All transitive MeshMC & library headers required by the SDK
#   - A CMake package config so out-of-tree plugins can:
#       find_package(MeshMC_SDK REQUIRED)
#       target_link_libraries(MyPlugin PRIVATE MeshMC::SDK)

# [Section 6] INTERFACE library — no compiled code
add_library(MeshMC_sdk INTERFACE)
add_library(MeshMC::SDK ALIAS MeshMC_sdk)

# [Section 7] Include directories with generator expressions
target_include_directories(MeshMC_sdk INTERFACE
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/launcher>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/launcher/plugin/sdk>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/libraries/optional-bare/include>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/libraries/katabasis/include>
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/buildconfig>
    $<INSTALL_INTERFACE:include/meshmc-sdk>
    $<INSTALL_INTERFACE:include/meshmc-sdk/plugin/sdk>
)

# [Section 8] Transitive Qt6 link dependencies
target_link_libraries(MeshMC_sdk INTERFACE
    Qt6::Core
    Qt6::Widgets
    Qt6::Gui
)

# ... SDK header lists and install rules omitted for brevity ...
# ... (see the full file in meshmc/launcher/plugin/sdk/CMakeLists.txt) ...

# [Section 3] CMake package config generation
include(CMakePackageConfigHelpers)

configure_package_config_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/MeshMCSDKConfig.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfig.cmake"
    INSTALL_DESTINATION "lib/cmake/MeshMC_SDK"                    # [Section 10]
)

# [Section 5] Version compatibility file
write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfigVersion.cmake"
    VERSION "${MeshMC_RELEASE_VERSION_NAME}"
    COMPATIBILITY AnyNewerVersion
)

# [Section 10] Install config files
install(FILES
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfig.cmake"
    "${CMAKE_CURRENT_BINARY_DIR}/MeshMCSDKConfigVersion.cmake"
    DESTINATION "lib/cmake/MeshMC_SDK"
)

# [Section 4] Export the target
install(TARGETS MeshMC_sdk
    EXPORT MeshMCSDKTargets
)

install(EXPORT MeshMCSDKTargets
    FILE MeshMCSDKTargets.cmake
    NAMESPACE MeshMC::
    DESTINATION "lib/cmake/MeshMC_SDK"
)
```

---

## Next Steps

- **[README.md](README.md)** — SDK overview and component list
- **[in-tree-setup.md](in-tree-setup.md)** — In-tree plugin development
- **[out-of-tree-setup.md](out-of-tree-setup.md)** — Out-of-tree plugin development
- **[../overview.md](../overview.md)** — Plugin system architecture
