🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
4.7 KiB

  1. # Push EnTT across boundaries
  2. <!--
  3. @cond TURN_OFF_DOXYGEN
  4. -->
  5. # Table of Contents
  6. * [Working across boundaries](#working-across-boundaries)
  7. * [Smooth until proven otherwise](#smooth-until-proven-otherwise)
  8. * [Meta context](#meta-context)
  9. * [Memory management](#memory-management)
  10. <!--
  11. @endcond TURN_OFF_DOXYGEN
  12. -->
  13. # Working across boundaries
  14. `EnTT` has historically had a limit when used across boundaries on Windows in
  15. general and on GNU/Linux when default visibility was set to hidden. The
  16. limitation was mainly due to a custom utility used to assign unique, sequential
  17. identifiers with different types.<br/>
  18. Fortunately, nowadays using `EnTT` across boundaries is much easier.
  19. ## Smooth until proven otherwise
  20. Many classes in `EnTT` make extensive use of type erasure for their purposes.
  21. This isn't a problem on itself (in fact, it's the basis of an API so convenient
  22. to use). However, a way is needed to recognize the objects whose type has been
  23. erased on the other side of a boundary.<br/>
  24. The `type_hash` class template is how identifiers are generated and thus made
  25. available to the rest of the library. In general, this class doesn't arouse much
  26. interest. The only exception is when a conflict between identifiers occurs
  27. (definitely uncommon though) or when the default solution proposed by `EnTT`
  28. isn't suitable for the user's purposes.<br/>
  29. The section dedicated to `type_info` contains all the details to get around the
  30. issue in a concise and elegant way. Please refer to the specific documentation.
  31. When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
  32. `ENTT_API_IMPORT` can be used where there is a need to import or export symbols,
  33. so as to make everything work nicely across boundaries.<br/>
  34. On the other hand, everything should run smoothly when working with plugins or
  35. shared libraries that don't export any symbols.
  36. For anyone who needs more details, the test suite contains multiple examples
  37. covering the most common cases (see the `lib` directory for all details).<br/>
  38. It goes without saying that it's impossible to cover **all** possible cases.
  39. However, what is offered should hopefully serve as a basis for all of them.
  40. ## Meta context
  41. The runtime reflection system deserves a special mention when it comes to using
  42. it across boundaries.<br/>
  43. Since it's linked already to a static context to which the visible components
  44. are attached and different contexts don't relate to each other, they must be
  45. _shared_ to allow the use of meta types across boundaries.
  46. Sharing a context is trivial though. First of all, the local one must be
  47. acquired in the main space:
  48. ```cpp
  49. entt::meta_ctx ctx{};
  50. ```
  51. Then, it must passed to the receiving space that will set it as its global
  52. context, thus releasing the local one that remains available but is no longer
  53. referred to by the runtime reflection system:
  54. ```cpp
  55. entt::meta_ctx::bind(ctx);
  56. ```
  57. From now on, both spaces will refer to the same context and on it will be
  58. attached the new visible meta types, no matter where they are created.<br/>
  59. A context can also be reset and then associated again locally as:
  60. ```cpp
  61. entt::meta_ctx::bind(entt::meta_ctx{});
  62. ```
  63. This is allowed because local and global contexts are separated. Therefore, it's
  64. always possible to make the local context the current one again.
  65. Before to release a context, all locally registered types should be reset to
  66. avoid dangling references. Otherwise, if a type is accessed from another space
  67. by name, there could be an attempt to address its parts that are no longer
  68. available.
  69. ## Memory Management
  70. There is another subtle problem due to memory management that can lead to
  71. headaches.<br/>
  72. It can occur where there are pools of objects (such as components or events)
  73. dynamically created on demand. This is usually not a problem when working with
  74. linked libraries that rely on the same dynamic runtime. However, it can occur in
  75. the case of plugins or statically linked runtimes.
  76. As an example, imagine creating an instance of `registry` in the main executable
  77. and sharing it with a plugin. If the latter starts working with a component that
  78. is unknown to the former, a dedicated pool is created within the registry on
  79. first use.<br/>
  80. As one can guess, this pool is instantiated on a different side of the boundary
  81. from the `registry`. Therefore, the instance is now managing memory from
  82. different spaces and this can quickly lead to crashes if not properly addressed.
  83. To overcome the risk, it's recommended to use well-defined interfaces that make
  84. fundamental types pass through the boundaries, isolating the instances of the
  85. `EnTT` classes from time to time and as appropriate.<br/>
  86. Refer to the test suite for some examples, read the documentation available
  87. online about this type of issues or consult someone who has already had such
  88. experiences to avoid problems.