summaryrefslogtreecommitdiffstats
path: root/build/docs/defining-xpcom-components.rst
blob: 8e4f66c9c0fb6fe82607b7bcafa1e9dbe4074ac3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
.. _defining_xpcom_components:

=========================
Defining XPCOM Components
=========================

This document explains how to write a :code:`components.conf` file. For
documentation on the idl format see :ref:`XPIDL`. For a tutorial on writing
a new XPCOM interface, see
:ref:`writing_xpcom_interface`.

Native XPCOM components are registered at build time, and compiled into static
data structures which allow them to be accessed with little runtime overhead.
Each module which wishes to register components must provide a manifest
describing each component it implements, its type, and how it should be
constructed.

Manifest files are Python data files registered in ``moz.build`` files in a
``XPCOM_MANIFESTS`` file list:

.. code-block:: python

    XPCOM_MANIFESTS += [
      'components.conf',
    ]

The files may define any of the following special variables:

.. code-block:: python

    # Optional: A function to be called once, the first time any component
    # listed in this manifest is instantiated.
    InitFunc = 'nsInitFooModule'
    # Optional: A function to be called at shutdown if any component listed in
    # this manifest has been instantiated.
    UnloadFunc = 'nsUnloadFooModule'

    # Optional: A processing priority, to determine how early or late the
    # manifest is processed. Defaults to 50. In practice, this mainly affects
    # the order in which unload functions are called at shutdown, with higher
    # priority numbers being called later.
    Priority = 10

    # Optional: A list of header files to include before calling init or
    # unload functions, or any legacy constructor functions.
    #
    # Any header path beginning with a `/` is loaded relative to the root of
    # the source tree, and must not rely on any local includes.
    #
    # Any relative header path must be exported.
    Headers = [
        '/foo/nsFooModule.h',
        'nsFoo.h',
    ]

    # A list of component classes provided by this module.
    Classes = [
        {
            # ...
        },
        # ...
    ]

    # A list of category registrations
    Categories = {
        'category': {
            'name': 'value',
            'other-name': ('value', ProcessSelector.MAIN_PROCESS_ONLY),
            # ...
        },
        # ...
    }

Class definitions may have the following properties:

``name`` (optional)
  If present, this component will generate an entry with the given name in the
  ``mozilla::components`` namespace in ``mozilla/Components.h``, which gives
  easy access to its CID, service, and instance constructors as (e.g.,)
  ``components::Foo::CID()``, ``components::Foo::Service()``, and
  ``components::Foo::Create()``, respectively.

``cid``
  A UUID string containing this component's CID, in the form
  ``'{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'``.

``contract_ids`` (optional)
  A list of contract IDs to register for this class.

``categories`` (optional)
  A dict of category entries to register for this component's contract ID.
  Each key in the dict is the name of the category. Each value is either a
  string containing a single entry, or a list of entries.  Each entry is either
  a string name, or a dictionary of the form ``{'name': 'value', 'backgroundtasks':
  BackgroundTasksSelector.ALL_TASKS}``.  By default, category entries are registered
  for **no background tasks**: they have
  ``'backgroundtasks': BackgroundTasksSelector.NO_TASKS``.

``type`` (optional, default=``nsISupports``)
  The fully-qualified type of the class implementing this component. Defaults
  to ``nsISupports``, but **must** be provided if the ``init_method`` property
  is specified, or if neither the ``constructor`` nor ``legacy_constructor``
  properties are provided.

``headers`` (optional)
  A list of headers to include in order to call this component's constructor,
  in the same format as the global ``Headers`` property.

``init_method`` (optional)
  The name of a method to call on newly-created instances of this class before
  returning them. The method must take no arguments, and must return a
  ``nsresult``. If it returns failure, that failure is propagated to the
  ``getService`` or ``createInstance`` caller.

``constructor`` (optional)
  The fully-qualified name of a constructor function to call in order to
  create instances of this class. This function must be declared in one of the
  headers listed in the ``headers`` property, must take no arguments, and must
  return ``already_AddRefed<iface>`` where ``iface`` is the interface provided
  in the ``type`` property.

  This property is incompatible with ``legacy_constructor``.

``esModule`` (optional)
  If provided, must be the URL of a
  `JavaScript module <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`_
  which contains a JavaScript implementation of the component.
  The ``constructor`` property must contain the name of an exported
  function which can be constructed to create a new instance of the component.


``jsm`` (deprecated, optional)
  Do not use. Use ``esModule`` instead.

``legacy_constructor`` (optional)
  This property is deprecated, and should not be used in new code.

  The fully-qualified name of a constructor function to call in order to
  create instances of this class. This function must be declared in one of the
  headers listed in the ``headers`` property, and must have the signature
  ``nsresult(const nsID& aIID, void** aResult)``, and behave equivalently to
  ``nsIFactory::CreateInstance``.

  This property is incompatible with ``constructor``.

``singleton`` (optional, default=``False``)
  If true, this component's constructor is expected to return the same
  singleton for every call, and no ``mozilla::components::<name>::Create()``
  method will be generated for it.

``overridable`` (optional, default=``False``)
  If true, this component's contract ID is expected to be overridden by some
  tests, and its ``mozilla::components::<name>::Service()`` getter will
  therefore look it up by contract ID for every call. This component must,
  therefore, provide at least one contract ID in its ``contract_ids`` array.

  If false, the ``Service()`` getter will always retrieve the service based on
  its static data, and it cannot be overridden.

  Note: Enabling this option is expensive, and should not be done when it can
  be avoided, or when the getter is used by any hot code.

``external`` (optional, default=``False`` if any ``headers`` are provided, ``True`` otherwise)
  If true, a constructor for this component's ``type`` must be defined in
  another translation unit, using ``NS_IMPL_COMPONENT_FACTORY(type)``. The
  constructor must return an ``already_AddRefed<nsISupports>``, and will be
  used to construct instances of this type.

  This option should only be used in cases where the headers which define the
  component's concrete type cannot be easily included without local includes.

  Note: External constructors may not specify an ``init_method``, since the
  generated code will not have the necessary type information required to call
  it. This option is also incompatible with ``constructor`` and
  ``legacy_constructor``.

``processes`` (optional, default=``ProcessSelector.ANY_PROCESS``)
  An optional specifier restricting which types of process this component may
  be loaded in. This must be a property of ``ProcessSelector`` with the same
  name as one of the values in the ``Module::ProcessSelector`` enum.


Conditional Compilation
=======================

This manifest may run any appropriate Python code to customize the values of
the ``Classes`` array based on build configuration. To simplify this process,
the following globals are available:

``defined``
  A function which returns true if the given build config setting is defined
  and true.

``buildconfig``
  The ``buildconfig`` python module, with a ``substs`` property containing a
  dict of all available build substitutions.


Component Constructors
======================

There are several ways to define component constructors, which vary mostly
depending on how old the code that uses them is:

Class Constructors
------------------

This simplest way to define a component is to include a header defining a
concrete type, and let the component manager call that class's constructor:

.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'headers': ['mozilla/Foo.h'],

This is generally the preferred method of defining non-singleton constructors,
but may not be practicable for classes which rely on local includes for their
definitions.

Singleton Constructors
----------------------

Singleton classes are generally expected to provide their own constructor
function which caches a singleton instance the first time it is called, and
returns the same instance on subsequent calls. This requires declaring the
constructor in an included header, and implementing it in a separate source
file:

.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'headers': ['mozilla/Foo.h'],
  'constructor': 'mozilla::Foo::GetSingleton',

``Foo.h``

.. code-block:: cpp

    class Foo final : public nsISupports {
     public:
      static already_AddRefed<Foo> GetSingleton();
    };

``Foo.cpp``

.. code-block:: cpp

    already_AddRefed<Foo> Foo::GetSingleton() {
      // ...
    }

External Constructors
---------------------

For types whose headers can't easily be included, constructors can be defined
using a template specialization on an incomplete type:

.. code-block:: python

  'type': 'mozilla::foo::Foo',
  'external: True,'

``Foo.cpp``

.. code-block:: cpp

    NS_IMPL_COMPONENT_FACTORY(Foo) {
      return do_AddRef(new Foo()).downcast<nsISupports>();
    }

Legacy Constructors
-------------------

These should not be used in new code, and are left as an exercise for the
reader.


Registering Categories
======================

Classes which need define category entries with the same value as their
contract ID may do so using the following:

.. code-block:: python

    'contract_ids': ['@mozilla.org/foo;1'],
    'categories': {
        'content-policy': 'm-foo',
        'Gecko-Content-Viewers': ['image/jpeg', 'image/png'],
    },

This will define each of the following category entries:

* ``"content-policy"`` ``"m-foo",`` ``"@mozilla.org/foo;1"``
* ``"Gecko-Content-Viewers"`` ``"image/jpeg"`` ``"@mozilla.org/foo;1"``
* ``"Gecko-Content-Viewers"`` ``"image/png"`` ``"@mozilla.org/foo;1"``

Some category entries do not have a contract ID as a value. These entries can
be specified by adding to a global ``Categories`` dictionary:

.. code-block:: python

    Categories = {
        'update-timer': {
            'nsUpdateService': '@mozilla.org/updates/update-service;1,getService,background-update-timer,app.update.interval,43200,86400',
        }
    }

It is possible to limit these on a per-process basis by using a tuple as the
value:

.. code-block:: python

    Categories = {
        '@mozilla.org/streamconv;1': {
            '?from=gzip&to=uncompressed': ('', ProcessSelector.ALLOW_IN_SOCKET_PROCESS),
        }
    }