It is common practice for function libraries to initialize and store data in the SE_SERVICES object for retrieval by their wrapper functions. However, the SE_SERVICES object is per-context. If you create and store information in that object, it will only be accessable from the context that created it. If the libraries are to be made read-shared, they cannot use this object to store data that should be accessable from any context using it.
Libraries that want to be able to be shared must use the SE_SHARED_SERVICES object to store any data that needs to be accessable from any context using the code. This object functions similarly to SE_SERVICES, you create members using a name that will not conflict with other applications and retrieve those members as needed.
The SE_SHARED_SERVICES object is a read-shared object and thus cannot be modified. The only time you can write to it is in the sePrepareContextFunc callback of the first context. Therefore, you want to ensure any initialization code that may write to this object, such as seAddLibTable calls, are put into the prepare context callback for your first context.
Take care when designing your applications and carefully consider the purpose of the data you are storing in the SE_SERVICES object. You may want that data to be per-context. In other cases, the data should be identical between contexts, and that is when you use the SE_SHARED_SERVICES object.
The SE_SHARED_SERVICES object is a synonym for SE_SERVICES if you do not have the read-only shared objects enabled. Thus, you can write your code to properly function when shared and use it unchanged in a non-shared build (determined by the options in your jseopt.h file) by using SE_SHARED_SERVICES when appropriate.