On `os-4.0-dev`, adding `epmodel` alongside `model` pushes the single `openstudiolib.dll` to ~123.8k unique exported symbols. MSVC's import library (and DLL export ordinal table) has a hard 16-bit limit of 65,535 → `LNK1189`.
Removing `model` isn't enough (`epmodel` alone is 60.4k; the pre-epmodel total was already 63.4k).
The only fix is splitting into multiple DLLs — **on Windows/MSVC only**; Linux/macOS keep the single `openstudiolib` unchanged.
Symbol budget per group (from my dumpbin analysis):
| DLL | contents | exported symbols | % of 65,535 |
|---|---|---|---|
| `openstudioutilitieslib` | utilities | ~6.4k | 10% |
| `openstudiomodellib` | model + energyplus | ~53.5k | 82% |
| `openstudioepmodellib` | epmodel | ~60.4k | **92%** |
| `openstudiolib` (keeps name) | airflow, gbxml, sdd, radiance, gltf, epjson, isomodel, osversion, alfalfa, modelica, measure | ~5.5k | 8% |
Rationale for this grouping:
- `epmodel` will eventually replace `model` + `energyplus`; `openstudiomodellib` then gets deleted wholesale — no boundary redesign later.
- `measure` depends on **both** `model` and `epmodel`, so it (and the auxiliaries) must sit above both — it lives in the top-level `openstudiolib`, which keeps its name so **no consumer changes** (CLI, rubyengine, pythonengine, csharp, workflow, all test targets keep linking `openstudiolib`).
- Dependency DAG verified clean (no cycles): `utilities ← {model+energyplus, epmodel} ← auxiliaries/measure`. energyplus is used by epjson/gbxml/sdd (all in the top DLL). epmodel is used only by measure/workflow/cli. Link order is not an issue for DLLs.
- ⚠️ `openstudioepmodellib` is born at 92% of the limit and epmodel grows with each E+ release. Not solved here; future mitigation = trim exports (e.g. detail impls) or split epmodel internally.
## Design
**Components stay OBJECT libraries on all platforms** — no changes to any `src/<component>/CMakeLists.txt` library type. The split is done purely at the composition layer in `src/lib/CMakeLists.txt`: on MSVC, create 4 `SHARED` libs each folding its OBJECT libs `PRIVATE` (same `empty.cpp` pattern as today); on other platforms, keep the current single target.
The existing per-component export macros (`UTILITIES_API`, `MODEL_API`, `EPMODEL_API`, … defined via `openstudio_<name>_EXPORTS` set PRIVATE per OBJECT lib) already produce correct dllexport/dllimport across DLL boundaries, since each OBJECT lib lands in exactly one DLL.
Pull request overview
Pull Request Author
src/model/test)src/energyplus/Test)src/osversion/VersionTranslator.cpp)Labels:
IDDChangeAPIChangePull Request - Ready for CIso that CI builds your PRReview Checklist
This will not be exhaustively relevant to every PR.