OLD | NEW |
1 # The Chrome Component Build | 1 # The Chrome Component Build |
2 | 2 |
3 ## Introduction | 3 ## Introduction |
4 | 4 |
5 Release builds are “static” builds which compile to one executable and | 5 Release builds are “static” builds which compile to one executable and |
6 zero-to-two shared libraries (depending on the platform). This is efficient at | 6 zero-to-two shared libraries (depending on the platform). This is efficient at |
7 runtime, but can take a long time to link because so much code goes into a | 7 runtime, but can take a long time to link because so much code goes into a |
8 single binary. When you set the GN build variable | 8 single binary. When you set the GN build variable |
9 | 9 |
10 ```python | 10 ```python |
11 is_component_build = true | 11 is_component_build = true |
12 ``` | 12 ``` |
13 | 13 |
14 the build will generate many smaller shared libraries. This speeds up link | 14 the build will generate many smaller shared libraries. This speeds up link |
15 times, and means that many changes only require that the local shared library | 15 times, and means that many changes only require that the local shared library |
16 be linked rather than the full executable, but at the expense of program | 16 be linked rather than the full executable, but at the expense of program |
17 load-time performance. | 17 load-time performance. |
18 | 18 |
19 ### How to make a component | 19 ### How to make a component |
20 | 20 |
21 Defining a component just means using the GN “component” template instead | 21 Defining a component just means using the GN “component” template instead |
22 of a shared library, static library, or source set. The template will | 22 of a shared library, static library, or source set. The template will |
23 generate a shared library when `is_component_build` is enabled, and a static | 23 generate a shared library when `is_component_build` is enabled, and a static |
24 library otherwise. | 24 library otherwise. |
25 | 25 |
26 ```python | 26 ```python |
27 component("browser") { | 27 component("browser") { |
28 output_name = "chrome_browser" | 28 output_name = "chrome_browser" |
29 sources = ... | 29 sources = ... |
30 ... | 30 ... |
31 } | 31 } |
32 ``` | 32 ``` |
33 | 33 |
34 Shared libraries in GN must have globally unique output names. According to GN | 34 Shared libraries in GN must have globally unique output names. According to GN |
35 style, your target should be named something simple and convenient (often | 35 style, your target should be named something simple and convenient (often |
36 matching your directory name). If this is non-unique, override it with the | 36 matching your directory name). If this is non-unique, override it with the |
37 output_name variable. | 37 `output_name` variable. |
38 | 38 |
39 ### Dependencies between targets | 39 ### Dependencies between targets |
40 | 40 |
41 When a component directly or indirectly depends on a static library or source | 41 When a component directly or indirectly depends on a static library or source |
42 set, it will be linked into this component. If other components do the same, | 42 set, it will be linked into this component. If other components do the same, |
43 the static library or source set’s code will be duplicated. | 43 the static library or source set’s code will be duplicated. |
44 | 44 |
45 In a few cases (for defining some constants) this duplication is OK, but in | 45 In a few cases (for defining some constants) this duplication is OK, but in |
46 general this is a bad idea. Globals and singletons will get duplicated which | 46 general this is a bad idea. Globals and singletons will get duplicated which |
47 will wreak havoc. Therefore, you should normally ensure that components only | 47 will wreak havoc. Therefore, you should normally ensure that components only |
(...skipping 12 matching lines...) Expand all Loading... |
60 | 60 |
61 When a shared library or executable uses a symbol from a shared library, it is | 61 When a shared library or executable uses a symbol from a shared library, it is |
62 “imported” by the user of the symbol, and “exported” from the shared library | 62 “imported” by the user of the symbol, and “exported” from the shared library |
63 that defines the symbol. Don’t confuse exported symbols with the public API of | 63 that defines the symbol. Don’t confuse exported symbols with the public API of |
64 a component. For example, unit tests will often require implementation details | 64 a component. For example, unit tests will often require implementation details |
65 to be exported. Export symbols to make the build link the way you need it, and | 65 to be exported. Export symbols to make the build link the way you need it, and |
66 use GN’s public headers and visibility restrictions to define your public API. | 66 use GN’s public headers and visibility restrictions to define your public API. |
67 | 67 |
68 ### Chrome’s pattern for exports | 68 ### Chrome’s pattern for exports |
69 | 69 |
70 Write a header with the name <component_name>_export.h. Copy an [existing | 70 Write a header with the name `<component_name>_export.h`. Copy an [existing |
71 one](https://cs.chromium.org/chromium/src/ipc/ipc_export.h) | 71 one](https://cs.chromium.org/chromium/src/ipc/ipc_export.h) |
72 and update the macro names. It will key off of two macros: | 72 and update the macro names. It will key off of two macros: |
73 | 73 |
74 * `COMPONENT_BUILD`: A globally defined preprocessor definition set when the | 74 * `COMPONENT_BUILD`: A globally defined preprocessor definition set when the |
75 component build is on. | 75 component build is on. |
76 * `<component_name>_IMPLEMENTATION`: A macro you define for code inside your | 76 * `<component_name>_IMPLEMENTATION`: A macro you define for code inside your |
77 component, and leave undefined for code outside of your component. The | 77 component, and leave undefined for code outside of your component. The |
78 naming should match your `*_export.h` header. | 78 naming should match your `*_export.h` header. |
79 | 79 |
80 It will define a macro `<component_name>_EXPORT`. This will use the | 80 It will define a macro `<component_name>_EXPORT`. This will use the |
81 `*_IMPLEMENTATION` macro to know whether code is being compiled inside or outsid
e | 81 `*_IMPLEMENTATION` macro to know whether code is being compiled inside or outsid
e |
82 of your component, and the `*_EXPORT` macro will set it to being exported or | 82 of your component, and the `*_EXPORT` macro will set it to being exported or |
83 imported, respectively. You should copy an existing file and update the | 83 imported, respectively. You should copy an existing file and update the |
84 `*_EXPORT` macro naming for your component. | 84 `*_EXPORT` macro naming for your component. |
85 | 85 |
86 When defining the target for your component, set: | 86 When defining the target for your component, set: |
87 | 87 |
88 ```python | 88 ```python |
89 defines = [ "FOO_IMPLEMENTATION" ] | 89 defines = [ "FOO_IMPLEMENTATION" ] |
90 ``` | 90 ``` |
91 | 91 |
92 In your BUILD.gn file. If you have source sets that also make up your | 92 In your BUILD.gn file. If you have source sets that also make up your |
93 component, set this on them also. A good way to share this is to put the | 93 component, set this on them also. A good way to share this is to put the |
94 definition in a GN config: | 94 definition in a GN config: |
95 | 95 |
96 ```python | 96 ```python |
97 config("foo_implementation") { | 97 config("foo_implementation") { |
98 defines = [ "FOO_IMPLEMENTATION" ] | 98 defines = [ "FOO_IMPLEMENTATION" ] |
99 } | 99 } |
100 ``` | 100 ``` |
101 | 101 |
102 and set the config on the targets that use it: | 102 and set the config on the targets that use it: |
103 | 103 |
104 ```python | 104 ```python |
105 configs += [ ":foo_implementation" ] | 105 configs += [ ":foo_implementation" ] |
106 ``` | 106 ``` |
107 | 107 |
108 The component build is only reason to use the `*_IMPLEMENTATION` macros. If | 108 The component build is only reason to use the `*_IMPLEMENTATION` macros. If |
109 your code is not being compiled into a component, don’t define such a macro | 109 your code is not being compiled into a component, don’t define such a macro |
110 (sometimes people do this by copying other targets without understanding). | 110 (sometimes people do this by copying other targets without understanding). |
111 | 111 |
112 ### Marking symbols for export | 112 ### Marking symbols for export |
113 | 113 |
114 Use the `*_EXPORT` macros on function and class declarations (don’t annotate | 114 Use the `*_EXPORT` macros on function and class declarations (don’t annotate |
115 the implementations) as follows: | 115 the implementations) as follows: |
116 | 116 |
117 ```c++ | 117 ```c++ |
118 #include "yourcomponent/yourcomponent_export.h" | 118 #include "yourcomponent/yourcomponent_export.h" |
119 | 119 |
120 class YOURCOMPONENT_EXPORT YourClass { ... }; | 120 class YOURCOMPONENT_EXPORT YourClass { ... }; |
121 | 121 |
122 YOURCOMPONENT_EXPORT void SomeFunction(); | 122 YOURCOMPONENT_EXPORT void SomeFunction(); |
123 ``` | 123 ``` |
124 | 124 |
125 Sometimes you have an internal helper class used as the base for an exported | 125 Sometimes you have an internal helper class used as the base for an exported |
126 class. Visual C++ will complain if the base class is not exported: | 126 class. Visual C++ will complain if the base class is not exported: |
127 | 127 |
128 warning C4275: non dll-interface class 'YourClass' used as base for dll-inte
rface class 'Base' | 128 warning C4275: non dll-interface class 'YourClass' used as base for dll-inte
rface class 'Base' |
129 | 129 |
130 If you don’t use the base class outside of the component, Chrome supplies the NO
N_EXPORTED_BASE macro in base/compiler_specific.h to disable the warning. For ex
ample: | 130 If you don’t use the base class outside of the component, Chrome supplies the |
| 131 `NON_EXPORTED_BASE` macro in `base/compiler_specific.h` to disable the warning. |
| 132 For example: |
131 | 133 |
132 ```c++ | 134 ```c++ |
133 class YourClass : public NON_EXPORTED_BASE(Base) { ... }; | 135 class YourClass : public NON_EXPORTED_BASE(Base) { ... }; |
134 ``` | 136 ``` |
135 | 137 |
136 ## Creating components from multiple targets | 138 ## Creating components from multiple targets |
137 | 139 |
138 ### Static library symbol export issues | 140 ### Static library symbol export issues |
139 | 141 |
140 Components can be made up of static libraries and GN source sets. A source set | 142 Components can be made up of static libraries and GN source sets. A source set |
141 results in all object files from that compilation being linked into the | 143 results in all object files from that compilation being linked into the |
142 component. But when code is in a static library, only those object files needed | 144 component. But when code is in a static library, only those object files needed |
143 to define undefined symbols will be pulled in to the link. If an object file is | 145 to define undefined symbols will be pulled in to the link. If an object file is |
144 not needed to link the component itself, it won’t be pulled into the link, even | 146 not needed to link the component itself, it won’t be pulled into the link, even |
(...skipping 22 matching lines...) Expand all Loading... |
167 | 169 |
168 In the static build the structure will be: `//external/thing` ➜ `//foo:browser` | 170 In the static build the structure will be: `//external/thing` ➜ `//foo:browser` |
169 ➜ `//foo:browser_impl` | 171 ➜ `//foo:browser_impl` |
170 | 172 |
171 In the component build the structure will be: `//external/thing` ➜ | 173 In the component build the structure will be: `//external/thing` ➜ |
172 `//foo:browser` ➜ `//foo:mycomponent` ➜ `//foo:browser_impl` | 174 `//foo:browser` ➜ `//foo:mycomponent` ➜ `//foo:browser_impl` |
173 | 175 |
174 Set GN visibility so that the targets with the code can only be depended on by | 176 Set GN visibility so that the targets with the code can only be depended on by |
175 targets inside your component. | 177 targets inside your component. |
176 | 178 |
177 ```python | 179 ```python |
178 if (is_component_build) { | 180 if (is_component_build) { |
179 component("mycomponent") { | 181 component("mycomponent") { |
180 public_deps = [ ":browser_impl", ":renderer_impl" ] | 182 public_deps = [ ":browser_impl", ":renderer_impl" ] |
181 } | 183 } |
182 } | 184 } |
183 | 185 |
184 # External targets always depend on this or the equivalent “renderer” target
. | 186 # External targets always depend on this or the equivalent “renderer” target. |
185 group("browser") { | 187 group("browser") { |
186 if (is_component_build) { | 188 if (is_component_build) { |
187 public_deps = [ ":mycomponent" ] | 189 public_deps = [ ":mycomponent" ] |
188 } else { | 190 } else { |
189 public_deps = [ ":browser_impl" ] | 191 public_deps = [ ":browser_impl" ] |
190 } | 192 } |
191 } | 193 } |
192 | 194 |
193 source_set("browser_impl") { | 195 source_set("browser_impl") { |
194 visibility = [ ":*" ] # Prevent accidental dependencies. | 196 visibility = [ ":*" ] # Prevent accidental dependencies. |
195 defines = [ "MYCOMPONENT_IMPLEMENTATION" ] | 197 defines = [ "MYCOMPONENT_IMPLEMENTATION" ] |
196 sources = [ ... ] | 198 sources = [ ... ] |
197 } | 199 } |
198 ``` | 200 ``` |
199 | 201 |
200 ## Common mistakes | 202 ## Common mistakes |
201 | 203 |
202 ### Forgetting to mark a symbol with `*_EXPORT` | 204 ### Forgetting to mark a symbol with `*_EXPORT` |
203 | 205 |
204 If a function is not marked with your `*_EXPORT` annotation, other components | 206 If a function is not marked with your `*_EXPORT` annotation, other components |
205 won’t see the symbol when linking and you’ll get undefined symbols during | 207 won’t see the symbol when linking and you’ll get undefined symbols during |
206 linking: | 208 linking: |
207 | 209 |
208 some_file.obj : error LNK2001: unresolved external symbol <some definition> | 210 some_file.obj : error LNK2001: unresolved external symbol <some definition> |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 cases above where `_IMPLEMENTATION` is inappropriately defined or inappropriatel
y | 242 cases above where `_IMPLEMENTATION` is inappropriately defined or inappropriatel
y |
241 undefined. Use GN visibility to make sure callers don’t screw up. | 243 undefined. Use GN visibility to make sure callers don’t screw up. |
242 | 244 |
243 ### Putting exported symbols in static libraries | 245 ### Putting exported symbols in static libraries |
244 | 246 |
245 As discussed above, exported symbols should not be in static libraries because | 247 As discussed above, exported symbols should not be in static libraries because |
246 the object file might not be brought into the link. Even if it is brought in | 248 the object file might not be brought into the link. Even if it is brought in |
247 today, it might not be brought in due to completely unrelated changes in the | 249 today, it might not be brought in due to completely unrelated changes in the |
248 future. The result will be undefined symbol errors from other components. Use | 250 future. The result will be undefined symbol errors from other components. Use |
249 source sets if your component is made up of more than one target. | 251 source sets if your component is made up of more than one target. |
OLD | NEW |