0

Update component build documentation

Recommends base/component_export.h and deprecates the old pattern.

Bug: None
Change-Id: I8bb5d5fbdbafbb9310638d7ce50c8acb5194dce7
Reviewed-on: https://chromium-review.googlesource.com/887624
Reviewed-by: Ken Rockot <rockot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531986}
This commit is contained in:
Ken Rockot
2018-01-25 22:36:31 +00:00
parent 3eba0517c8
commit ca112b210e

@ -69,7 +69,36 @@ a component. For example, unit tests will often require implementation details
to be exported. Export symbols to make the build link the way you need it, and
use GNs public headers and visibility restrictions to define your public API.
### Chromes pattern for exports
Component library headers can use the `COMPONENT_EXPORT()` macro defined in
`base/component_export.h` to annotate symbols which should be exported by
the component. This macro takes a globally unique component name as an
argument:
```c++
#include "base/component_export.h"
class COMPONENT_EXPORT(YOUR_COMPONENT) YourClass { ... };
COMPONENT_EXPORT(YOUR_COMPONENT) void SomeFunction();
```
When defining the target for your component, set:
```python
defines = [ "IS_YOUR_COMPONENT_IMPL" ]
```
This ensures that the corresponding `COMPONENT_EXPORT(YOUR_COMPONENT)`
invocations result in symbols being marked for export when compiling the
component target. All other targets which include the component's headers
will not have defined `IS_YOUR_COMPONENT_IMPL`, so they will have the same
symbols marked for import instead.
## Chromes deprecated pattern for exports
**NOTE**: This section is included for posterity, as many components in the tree
still use this pattern for exports. New components should use
`base/component_export.h` as described above.
Write a header with the name `<component_name>_export.h`. Copy an [existing
one](https://cs.chromium.org/chromium/src/ipc/ipc_export.h)
@ -185,18 +214,18 @@ group("browser") {
source_set("browser_impl") {
visibility = [ ":*" ] # Prevent accidental dependencies.
defines = [ "MYCOMPONENT_IMPLEMENTATION" ]
defines = [ "IS_MYCOMPONENT_IMPL" ]
sources = [ ... ]
}
```
## Common mistakes
### Forgetting to mark a symbol with `*_EXPORT`
### Forgetting or misspelling `COMPONENT_EXPORT(*)`
If a function is not marked with your `*_EXPORT` annotation, other components
wont see the symbol when linking and youll get undefined symbols during
linking:
If a function is not marked with your `COMPONENT_EXPORT(FOO)` annotation or the
component name (`FOO`) is misspelled, other components wont see the symbol when
linking and youll get undefined symbols during linking:
some_file.obj : error LNK2001: unresolved external symbol <some definition>
@ -204,7 +233,7 @@ This will only happen on Windows component builds, which makes the error more
difficult to debug. However, if you see such an error only for Windows
component builds, you know its this problem.
### Not defining `*_IMPLEMENTATION` for code in your component
### Not defining `IS_*_IMPL` for code in your component
When code is compiled that sees a symbol marked with `__declspec(dllimport)`,
it will expect to find that symbol in another shared library. If that symbol
@ -213,13 +242,13 @@ ends up in the same shared library, youll see the error:
some_file.obj : warning LNK4217: locally defined symbol
<horrendous mangled name> imported in function <some definition>
The solution is to make sure your `*_IMPLEMENTATION` define is set consistently
for all code in the component. If your component links in source sets or static
libraries, the `*_IMPLEMENTATION` macro must be set on those as well.
The solution is to make sure your `IS_*_IMPL` define is set consistently for all
code in the component. If your component links in source sets or static
libraries, the `IS_*_IMPL` macro must be set on those as well.
### Defining `*_IMPLEMENTATION` for code outside your component
### Defining `IS_*_IMPL` for code outside your component
If your `*_IMPLEMENTATION` macro is set for code compiled outside of the
If your `IS_*_IMPL` macro is set for code compiled outside of the
component, that code will expect the symbol to be in the current shared
library, but it wont be found. It wont even go looking in other libraries and
the result will be an undefined symbol:
@ -230,7 +259,7 @@ the result will be an undefined symbol:
If the source set or static library has any `*_EXPORT` macros and ends up both
inside and outside of the component boundary, those symbols will fall under the
cases above where `_IMPLEMENTATION` is inappropriately defined or inappropriately
cases above where `IS_*_IMPL` is inappropriately defined or inappropriately
undefined. Use GN visibility to make sure callers dont screw up.
### Putting exported symbols in static libraries