FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
Migrating to FhSim 3.0

This guide covers all breaking changes when upgrading from FhSim 2.x (main branch) to FhSim 3.0 (new_structure branch). Most downstream consumers are SimObject plugin libraries — the guide is structured with this audience first.

An automated migration script is available: see Using the migration script below.

v3 API stability. FhSim 3.0 is the current major version. The v3 XML input schema and the SimObject C++ API documented here are the stable target you should build against — the churn described in this guide is the one-time 2.x→3.0 break, not an ongoing state. Any future breaking change will be recorded in this guide with a Before/After mapping (per the project's deprecation policy) and announced on the issue tracker; retired names and attributes are also enforced by the documentation checks. There is no separate deprecation schedule beyond that.


Table of Contents

  1. Overview of changes
  2. For SimObject plugin authors *(most common case)*
  3. For engine embedders
  4. XML input file changes
  5. Dependency changes
  6. Using the migration script

Overview of changes

FhSim 3.0 introduces:

  • Target split: The monolithic FhSim::fhsim CMake target is split into purpose-built components. SimObject plugin authors now link the lighter FhSim::simobject target instead of the full engine.
  • Class renames: The Hungarian C prefix is removed from core utility classes (e.g., CPrintDuringExecPrintDuringExec).
  • Header renames: Matching the class renames (e.g., CPrintDuringExec.hPrintDuringExec.h).
  • XML schema update: <INTEGRATION> is renamed to <SIMULATION> (backward compatible with deprecation warning). The <Engine> and <Sundials> child elements are replaced by a new unified <Integrator Method="..."> element with structured sub-elements.
  • Dependency modernization: TinyXML replaced by libxml2, Sundials upgraded from 5.4 to 7.5, Eigen 5 added.
  • SimObject ODE callback update: OdeFcn is now const and no longer takes isMajorTimeStep. Once-per-accepted-step side effects should move to AcceptedStep(double T, const double* X).

For SimObject plugin authors

This section covers the typical consumer: a downstream library that defines SimObject subclasses and is compiled as a shared plugin (MODULE).

Step 1: Update CMake target linkage

Replace FhSim::fhsim with FhSim::simobject in your CMakeLists.txt:

Before (v2):

find_package(FhSim CONFIG REQUIRED)
target_link_libraries(my_simobjects PRIVATE FhSim::fhsim)

After (v3):

find_package(FhSim CONFIG REQUIRED)
target_link_libraries(my_simobjects PRIVATE FhSim::simobject)

The FhSim::simobject target provides everything a SimObject plugin needs: the SimObject base class, port definitions, ISimObjectCreator, utilities, and transitive dependencies (FhLib, libxml2, Eigen, and optionally Ogre/OIS).

Step 2: Update Conan requirements

In your conanfile.py or conanfile.txt, bump the FhSim version:

Before:

self.requires("fhsim/2.x.x@sintef/stable")
# or version-range form:
self.requires("fhsim/[^2.12.0]@sintef/stable")

After:

self.requires("fhsim/[^3.1.0]@sintef/stable")

Note: the first release on the 3.x line is 3.1.0, not 3.0.0 — fhsim_base/3.0.0 is an already-released reference on the 2.x line. Use the caret range [^3.1.0] rather than an exact pin.

Ensure your Conan profile has compiler.cppstd=20.

Step 3: Rename header includes

The following headers have been renamed (the C prefix is removed):

Old #include New #include
#include "CPrintDuringExec.h" #include <fhsim/PrintDuringExec.h>
#include "CFhSimMgr.h" #include <fhsim/FhSimMgr.h>
#include "CExceptions.h" #include <fhsim/Exceptions.h>
#include "CAttributePath.h" #include <fhsim/AttributePath.h>
#include "CInputReader.h" #include <fhsim/InputReader.h>

Headers that are unchanged (no action needed): SimObjectInclude.h, SimObject.h, ISimObjectCreator.h, NFhSim.h, ISimObjectLogger.h, ICommonComputation.h, ISignalPort.h, IStateUpdater.h, KalmanObject.h, ExternalLink.h, PortDefs.h, PortStructDefs.h.

Note: dllLib.h was renamed to DllLib.h. If your SimObject DLL entry point file includes it, update to #include <fhsim/DllLib.h>.

Step 4: Rename class usages

Apply these find-and-replace operations across your C++ source files:

Old class name New class name
CPrintDuringExec PrintDuringExec
CFhSimMgr FhSimMgr
CExceptions Exceptions
CAttributePath AttributePath
CInputReader InputReader

Classes that are unchanged (no action needed): SimObject, ExternalLink, KalmanObject, ISimObjectCreator, ICommonComputation, ISignalPort, IStateUpdater, SerialCommonComputation.

Step 5a: Rename m_SimObjectName member (if accessed directly)

The protected member variable that stores the object's registered name was renamed in the SimObject base class:

Old New
m_SimObjectName m_simObjectName

This only affects code that accesses this member directly by name. Most code uses the public GetName() accessor, which is unchanged.

Step 5b: Update headers that use unqualified string

v3 removed the using std::string; declaration that v2 had at file scope in ISimObjectCreator.h. Any of your own headers that relied on this transitive using declaration will now fail to compile with ‘'string’ was not declared`.

Fix your headers by qualifying the type explicitly:

// Old (relied on ISimObjectCreator.h injecting 'using std::string;')
MyObject(string name, ISimObjectCreator* creator);
// New
MyObject(std::string name, ISimObjectCreator* creator);

Fix your **.cpp implementation files** by adding a using declaration after your includes, or by qualifying at usage sites:

#include "MyObject.h"
using std::string; // add this

Test stubs and mock ISimObjectCreator classes hit this most often — local Creator subclasses defined inside _Test.cpp files often override GetStringParam, GetDoubleParamArray, AddInport, AddOutportIndexed with bare string parameters. Find all occurrences with:

grep -rnP '(?<!::)\bstring\b' src/ tests/ --include='*.h' --include='*.cpp'

Then qualify each one as std::string.

Step 6: Update test target linkage (if applicable)

If you use FhSim's test utilities:

Before:

target_link_libraries(my_tests PRIVATE FhSim::fhsim-testtools)

After:

target_link_libraries(my_tests PRIVATE FhSim::fhsim_test)

Note the change from hyphen (-) to underscore (_).

Step 7: Link FhSim::fhsim_vis and update visualization includes (if applicable)

If your library compiles source files that include visualization headers (FhCamera.h, FhVisualization.h, etc.), you must explicitly link the FhSim::fhsim_vis component, which provides these headers in v3.

In the CMakeLists.txt that builds your SimObject library:

if(FHSIM_FH_VISUALIZATION)
target_link_libraries(${TARGET} PUBLIC FhSim::fhsim_vis)
endif()

FHSIM_FH_VISUALIZATION is a CMake cache variable set by fhsim-variables.cmake (included automatically when find_package(FhSim) is called) when the fhsim package was built with with_visualization=True.

Include form for visualization headers:

The FhSim::fhsim_vis component registers include/ as its include root. Headers must therefore be included with the full fhsim/ prefix:

// CORRECT — include with the fhsim/ prefix:
#include <fhsim/visual/renderer/FhCamera.h> // ✓

Visualization class and shared-resource renames:

Old New
#include <CFhCamera.h> #include <fhsim/visual/renderer/FhCamera.h>
CFhCamera* cam FhCamera* cam
(CFhCamera*)creator->GetSharedResource("CFhCamera") (FhCamera*)creator->GetSharedResource("FhCamera")

Complete before/after example

Before (v2 SimObject source):

#include "CPrintDuringExec.h"
#include "CExceptions.h"
#include "SimObjectInclude.h"
class MyObject : public SimObject {
public:
MyObject(std::string name, ISimObjectCreator* creator);
void OdeFcn(const double t, const double* x,
double* xdot, const bool isMajor) override;
};

After (v3 SimObject source):

#include <fhsim/PrintDuringExec.h>
#include <fhsim/Exceptions.h>
#include <fhsim/simobject/SimObjectInclude.h>
class MyObject : public SimObject {
public:
MyObject(std::string name, ISimObjectCreator* creator);
void OdeFcn(const double t, const double* x,
double* xdot) const override;
void AcceptedStep(const double t, const double* x) override;
};

Additional SimObject API migration notes

  • Logic previously guarded by if (isMajorTimeStep) inside OdeFcn(...) should move to AcceptedStep(double T, const double* X).
  • PreOdeFcn(T, X, updater) remains the pre-step hook for discrete updates.
  • ICommonComputation::ComputeFunction(...) is now const. If your implementation updates cached internals, use mutable members.
  • The CommonComputation callback typedef now expects a const SimObject member function.

The "IntegratorOptions" shared resource is gone

IntegratorOptionsCommon and the kSimMgrKeyIntegratorOptions ("IntegratorOptions") registry key were removed with the unified IntegratorConfig. A SimObject that asked the simulation manager for the integrator options now reads fhsim::IntegratorSetup under fhsim::kSimMgrKeyIntegratorSetup:

#include <fhsim/FhSimMgr.h>
#include <fhsim/IntegratorSetup.h>
#include <fhsim/NFhSim.h>
void MySimObject::FinalSetup(double, const double* const, ISimObjectCreator* const creator)
{
auto* mgr = static_cast<FhSimMgr*>(creator->GetSharedResource("FhSimMgr"));
auto* setup = static_cast<fhsim::IntegratorSetup*>(
mgr->GetPtr(fhsim::kSimMgrKeyIntegratorSetup));
const double tEnd = setup->tEnd;
if (setup->method == "Euler_i") { /* … */ }
}
Removed (IntegratorOptionsCommon) Replacement (fhsim::IntegratorSetup)
GetStartTime() tStart
GetEndTime() tEnd
GetStepSize() step (the requested fixed step; 0 when the method steps adaptively)
GetMethod() method

method is the canonical v3 method name, so a comparison against a v2 name has to be updated too — "Euler1" becomes "Euler_i" and "Heun" becomes "Heun_i". See the method-name table under `<Engine>` / `<Sundials>` → `<Integrator Method="...">`.

Do not reach for kSimMgrKeyIntegrator in a setup hook. The integrator is built from the finished model, so it is registered only after every SimObject's Init(), FinalSetup() and InitialConditionSetup() have run; the pointer is null in all three and dereferencing it crashes. IFhIntegrator (now public, <fhsim/engine/IFhIntegrator.h>) is for reading the running integrator — current time, step size, diagnostics — from OdeFcn/AcceptedStep onwards.

Migration checklist:

  • [ ] All OdeFcn overrides updated to new signature (const, no isMajorTimeStep)
  • [ ] Major-step side effects moved to AcceptedStep(...)
  • [ ] ICommonComputation callbacks updated to const
  • [ ] "IntegratorOptions" lookups replaced by fhsim::kSimMgrKeyIntegratorSetup
  • [ ] Build and tests pass

For engine embedders

If your project embeds the full simulation engine (constructing FhSim objects directly), you still link FhSim::fhsim:

find_package(FhSim CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE FhSim::fhsim)

The FhSim::fhsim target now depends on FhSim::simobject, so you get everything. Additional steps for engine embedders:

Additional class renames

Old class name New class name
CFhSim FhSim
CFhRtSim *(no replacement class — see CFhRtSim is gone: real time is now a pacing mode)*
CFhSimLicenceManager FhSimLicenceManager
CFhIntegrator CFhIntegrator *(unchanged — engine-internal)*

Additional header renames

Old #include New #include
#include "CFhSim.h" #include <fhsim/FhSim.h>
#include "CFhRtSim.h" *(remove — see CFhRtSim is gone: real time is now a pacing mode)*

CFhRtSim is gone: real time is now a pacing mode

There is no real-time class in v3, and no header to include. A v2 project that constructed a CFhRtSim to get a wall-clock-paced run does not get a renamed class — real time became a property of the run instead.

Two things replaced it:

  • In a scenario, set the simulationSpeed attribute on the <SIMULATION> element (1.0 = real time, 2.0 = twice real time, 0 = as fast as possible). This is the only route for a headless FhSim run. On the command line, FhVis accepts -s / --simulation-speed and FhSimUI accepts --rtf / --rt; FhSim has no pacing flag. See Real-time pacing.
  • In embedding code, the pacing lives in a decorator around the state provider rather than in the engine facade: fhsim::RealTimeStateProvider (src/engine/io/RealTimeStateProvider.h) wraps any IStateProvider and sleeps the remaining wall time after each step. If the model cannot keep up it warns and does not sleep — the same behaviour CFhRtSim::Simulate() had. Build it the way SimulationManagerFactory does and hand it to a fhsim::SimulationManager.

Note that this is a behavioural move as well as a rename: pacing is applied around the step loop, so it composes with any provider (live integration, <Replay>, <Network>) instead of being a separate simulator subclass.

Removed FhSim lifecycle and result methods

fhsim::SimulationManager (src/engine/io/SimulationManager.h) is now the one owner of the simulation lifecycle, and the loop methods that duplicated it on the engine facade are gone. FhSim::Step() remains: it advances exactly one integrator step.

Removed Replacement
FhSim::Integrate() Build a SimulationManager over an IntegratorStateProvider and call Run() (see src/apps/fhExe/main.cpp), or loop FhSim::Step() while it returns simRes_Success.
FhSim::StepToTFinal() Same as above.
FhSim::GetOutput(XOut, TOut) Register an observer (FileOutputObserver, or fhsim::test::CapturingObserver in tests) — the integrator no longer accumulates a state history.
FhSim::GetNumOutput() Same as above.
FhSim::PrintStateValues() The <Diagnostics><Settings><LogStates/></Settings></Diagnostics> diagnostic.
FhVisSDL::IntegrateVis() SimulationManager::Run() with a visualization observer registered (see src/apps/fhSimUI/FhSimUIMain.cpp).

IFhIntegrator lost the matching virtuals — StepToTFinal(), GetOutputCopy(), GetNumOutput() and PrintStateValues(). Custom integrators must drop those overrides; Step(), the time-span accessors, the state accessors, LogConfiguration() and GetDiagnostics() are unchanged.

New visualization target

If your application uses the FhSim visualization layer (SDL/Ogre rendering), link the new FhSim::fhsim_vis target:

target_link_libraries(my_vis_app PRIVATE FhSim::fhsim FhSim::fhsim_vis)

XML input file changes

<INTEGRATION> → <SIMULATION>

The <INTEGRATION> XML element has been renamed to <SIMULATION>. The old name is still accepted with a deprecation warning but will be removed in a future release.

<Engine> / <Sundials> → <Integrator Method="...">

The <Engine> and <Sundials> child elements inside <SIMULATION> are removed and replaced by a single unified <Integrator Method="..."> element. <Replay> and <Network> are unchanged.

Method names

Old (<Engine IntegratorMethod="N">) New (<Integrator Method="...">)
IntegratorMethod="0" (Euler1) Method="Euler_i"
IntegratorMethod="1" (StableSolver) Method="StableSolver_i"
IntegratorMethod="2" (RKCK45) Method="RK45_i"
IntegratorMethod="3" (RKDOPRI54) Method="DOPRI54_i"
IntegratorMethod="4" (Heun) Method="Heun_i"
IntegratorMethod="5" (RKF45) Method="RKF45_i"
IntegratorMethod="6" (BS23) Method="BS23_i"
IntegratorMethod="12" (Euler1imp) Method="BackwardEuler_i"
Sundials BDF (cvode_method="BDF") Method="BDF"
Sundials Adams (cvode_method="Adams") Method="Adams"
ARKode DIRK Method="DIRK"
ARKode ERK Method="ERK"

Legacy Engine method names (RKCK45, Euler1imp, Euler1) are accepted as aliases with a deprecation warning. Use the canonical _i-suffixed names for Engine methods and plain names for Sundials methods.

Timing

Simulation start and end times move to a <Timing> sibling element:

<SIMULATION>
<Timing TStart="0.0" TEnd="100.0"/>
<Integrator Method="RK45_i">
<StepControl Step="0.01"/>
</Integrator>
</SIMULATION>

Step control and tolerances

Step size and tolerance settings move to a <StepControl> child of <Integrator>:

Old attribute (on <Engine> or <Sundials>) New (<StepControl> attribute)
dt / stepsize / Dt Step
abstol / AbsTol AbsTol
reltol / RelTol RelTol
HMax StepMax
HMin StepMin
(Sundials) initial step Step0
(Sundials) max steps MaxSteps

Linear solver and Jacobian

Old attribute New element
lin_type="SPGMR" <LinearSolver Type="SPGMR"/>
jac_type="dense" / jtype="dense" <Jacobian Type="dense"/>
<SundialsExtra linear_solver="component"/> (early v3) <LinearSolver Type="SPGMR" Preconditioner="component"/>
<SundialsExtra jacobian_policy="hybrid"/> (early v3) <Jacobian Policy="hybrid"/>
<LinearSolver Type="component" GsSweeps="N" GsSymmetric="true"/> (early v3) <LinearSolver Type="component"/> — the two attributes tuned a fallback no model could reach and are now rejected

The two <SundialsExtra> pseudo-keys selected model-side settings rather than SUNDIALS API calls; they are now rejected with an error that names the replacement attribute.

Sundials-specific passthrough (<SundialsExtra>)

For advanced Sundials settings not covered by the schema, add a <SundialsExtra> child element with arbitrary attribute-value pairs that are forwarded to the Sundials API:

<Integrator Method="DIRK">
<StepControl AbsTol="1e-8" RelTol="1e-6"/>
<LinearSolver Type="DENSE"/>
<Jacobian Type="dense"/>
<SundialsExtra ARKodeSetTableNum="BACKWARD_EULER_1_1" ARKodeSetFixedStep="0.005"/>
</Integrator>

Complete before/after example

Before (v2 Engine):

<INTEGRATION>
<Engine IntegratorMethod="2" t_start="0" t_end="100"
stepsize="0.01" HMax="0.05"/>
</INTEGRATION>

After (v3):

<SIMULATION>
<Timing TStart="0.0" TEnd="100.0"/>
<Integrator Method="RK45_i">
<StepControl Step="0.01" StepMax="0.05"/>
</Integrator>
</SIMULATION>

Before (v2 Sundials BDF):

<INTEGRATION>
<Sundials t_start="0" t_end="100" dt="0.1"
reltol="1e-6" abstol="1e-6"
sundials_method="cvodes" cvode_method="BDF"
jtype="dense" lin_type="SPGMR"/>
</INTEGRATION>

After (v3):

<SIMULATION>
<Timing TStart="0.0" TEnd="100.0"/>
<Integrator Method="BDF">
<StepControl Step="0.1" AbsTol="1e-6" RelTol="1e-6"/>
<LinearSolver Type="SPGMR"/>
<Jacobian Type="dense"/>
</Integrator>
</SIMULATION>

New <OBSERVERS> section

FhSim 3.0 introduces an observer/provider pipeline. Observers can be configured via a new optional <OBSERVERS> XML section:

<OBSERVERS>
<FileOutput outputFile="results.csv"/>
<ConsoleLog/>
</OBSERVERS>

See OBSERVERS section for full documentation.

Validation rules and migration pitfalls

Condition Behaviour
Only <SIMULATION> present ✅ Preferred — no warning
Only <INTEGRATION> present ⚠️ Accepted with deprecation warning
Both <INTEGRATION> and <SIMULATION> present ❌ Fatal error
Neither present ❌ Fatal error
<Integrator Method="..."> missing for Engine/Sundials simulations ❌ Fatal error
Unknown Method value ❌ Fatal error
Legacy method alias (RKCK45, Euler1imp, Euler1) ⚠️ Accepted with deprecation warning

Additional strict validation:

  • <Engine> and <Sundials> inside <SIMULATION> are rejected with a message pointing to <Integrator Method="...">; they are no longer parsed into anything.
  • <Integrator MaxOrder> is rejected: the attribute lives on <StepControl MaxOrder>.
  • <Integrator TOutput> is rejected: the output schedule lives on <OBSERVERS><FileOutput TOutput="..."/></OBSERVERS>. Without an <OBSERVERS> block the -o output file receives every step.
  • Unknown child elements inside <SIMULATION> fail fast.
  • Unknown child elements inside <OBSERVERS> fail fast.

FMU note:

  • FMU workflows should use full <SIMULATION> + <Integrator> when possible. If you hit migration issues in FMU export/import, contact the FhSim team.

Dependency changes

For SimObject authors

Most SimObject plugins use the InputReader / XmlDoc abstraction layer for XML access. The interface of these classes is unchanged — you do not need to modify your XML-reading code even though the underlying implementation switched from TinyXML to libxml2.

If your SimObject used TinyXML API directly (e.g., TiXmlElement*, TiXmlDocument), you must switch to the libxml2 API or (preferably) use the InputReader / XmlDoc wrappers instead.

TinyXML → libxml2 API mapping

The libxml2 API uses C-style allocation — always free strings returned by xmlGetProp / xmlNodeListGetString with xmlFree().

TinyXML (v2) libxml2 (v3)
#include <tinyxml.h> #include <libxml/parser.h> + #include <libxml/tree.h>
TiXmlDocument doc(path); doc.LoadFile() xmlDocPtr doc = xmlReadFile(path, nullptr, XML_PARSE_NONET);
doc.ErrorDesc() No direct equivalent; libxml2 writes to stderr by default
doc.RootElement() xmlDocGetRootElement(doc)
elem->Value() reinterpret_cast<const char*>(node->name)
elem->Attribute("x") xmlChar* v = xmlGetProp(node, BAD_CAST "x"); xmlFree(v);
elem->FirstChildElement("tag") Iterate node->children, skip node->type != XML_ELEMENT_NODE
child->NextSiblingElement() Iterate node->next, skip non-element nodes
attr->Name() reinterpret_cast<const char*>(attr->name)
attr->Value() xmlChar* v = xmlNodeListGetString(doc, attr->children, 1); xmlFree(v);
(no explicit free needed) xmlFreeDoc(doc) after all nodes are done

Also remove tinyxml::tinyxml from any target_link_libraries() call in your CMakeLists.txt — the migration script (--only cmake) does this automatically.

Conan dependency summary

Old (v2) New (v3) Impact on consumers
tinyxml/2.6.2 libxml2/[~2.13] Transitive; no action unless you used TinyXML API directly
sundials/5.4.0 sundials/7.5.0 Transitive; only affects engine embedders using Sundials API directly
eigen/[~5.0.0] New transitive dependency on simobject target
sdl/2.32.10 Only with with_visualization=True
imgui/[<1.92] Only with with_visualization=True
zeromq/4.3.5 Internal to fhsim; not visible to consumers
miniz/[~3.0.2] Internal to fhsim; not visible to consumers

Conan profile requirements

Ensure your Conan profile specifies:

[settings]
compiler.cppstd=20

Using the migration script

An automated migration script is provided at scripts/migrate_to_v3.py. It performs header renames, class renames, CMake target updates, and XML element renames across your project.

Usage

# Dry-run (preview changes without modifying files):
python scripts/migrate_to_v3.py /path/to/your/project
# Apply changes:
python scripts/migrate_to_v3.py /path/to/your/project --apply
# Process only specific file types:
python scripts/migrate_to_v3.py /path/to/your/project --apply --only cpp
python scripts/migrate_to_v3.py /path/to/your/project --apply --only cmake
python scripts/migrate_to_v3.py /path/to/your/project --apply --only xml

What the script does

  1. C++ files (.cpp, .h, .hpp):
    • Renames #include directives (e.g., "CPrintDuringExec.h""PrintDuringExec.h")
    • Renames class identifiers (e.g., CPrintDuringExecPrintDuringExec)
  2. CMake files (CMakeLists.txt, *.cmake):
    • Replaces FhSim::fhsim with FhSim::simobject (SimObject target migration)
    • Replaces FhSim::fhsim-testtools and FhSim::fhsim_testtools with FhSim::fhsim_test
  3. XML files (.xml):
    • Replaces <INTEGRATION> / </INTEGRATION> with <SIMULATION> / </SIMULATION>
  4. Conan files (conanfile.py, conanfile.txt):
    • Updates fhsim version requirement pattern

What the script does NOT handle (manual steps required)

The following changes cannot be automated safely and must be done by hand after running the script:

  1. **stringstd::string in headers** — the regex for word-boundary replacement would produce too many false positives. See Step 5b: Update headers that use unqualified string above.
  2. **<Engine> / <Sundials><Integrator Method="..."> migration** — the script cannot safely automate this transformation. Timing, step-size, tolerance, linear-solver, and Jacobian attributes are restructured into sub-elements, and Engine IntegratorMethod integer codes must be translated to canonical method names. See the XML input file changes section above for the mapping tables and before/after examples.
  3. **GetSharedResource("CFhCamera") string literal** — string literal content is not renamed by the class-rename pass. Search manually:
    grep -rn 'GetSharedResource.*CFhCamera\|SetPtr.*CFhCamera' src/
  1. **FhSim::fhsim_vis CMake link guard** — the script does not add new target_link_libraries calls. See Step 7: Link FhSim::fhsim_vis and update visualization includes (if applicable).
  2. Conan version-range syntax — the script handles common patterns but always verify the conanfile after running it.

Important notes

  • Always run in dry-run mode first to review proposed changes.
  • The CMake target replacement (FhSim::fhsimFhSim::simobject) handles both the mixed-case form (FhSim::fhsim) and the all-lowercase Conan CMakeDeps alias form (fhsim::fhsim). If you embed the engine rather than authoring a plugin, skip the CMake pass or restore FhSim::fhsim linkage manually where needed.
  • Back up your project or ensure clean git state before running with --apply.
  • The script does not modify files in .git/, build/, or node_modules/ directories.