| 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 |