1 | Node CMake
|
2 | ==========
|
3 |
|
4 | A CMake-based build system for node.js native modules, for CMake >= v3.1.
|
5 |
|
6 | ## Motivation
|
7 |
|
8 | The current build system for node native modules is
|
9 | [node-gyp](https://github.com/nodejs/node-gyp), which is based on the google
|
10 | project gyp. While this does provide a consistent build environment in
|
11 | line with the node build system, it has its own share of problems:
|
12 |
|
13 | 1. Cross platform library integration. As most node native modules are
|
14 | designed to expose some system-level interface to an existing library or
|
15 | framework, its very common to need to include other libraries and headers
|
16 | as dependencies of the module. Under gyp, these must be specified manually
|
17 | for each platform and architecture.
|
18 |
|
19 | 2. Integration with other build systems. Gyp is very much its own system
|
20 | and doesn't play nice with existing builds. Common practice is to manually
|
21 | convert the existing build to gyp, adding developer overhead and complexity.
|
22 | While gyp is designed to generate build files, outside visual studio its
|
23 | support is limited in the IDE space.
|
24 |
|
25 | 3. Turing completeness. Gyp is a strictly declarative build system. Any
|
26 | conditional building is done through supported declarative syntax. For
|
27 | complicated builds, this adds a lot of complexity and overhead for something
|
28 | as simple as handing build conditions outside of architecture and platform (
|
29 | Optional libraries, plugin based builds, nested conditions, etc.)
|
30 |
|
31 | 4. Depdencies. Gyp requires python to run, which is non-trival under windows,
|
32 | and is a constant source of frustration and configuration issues for those
|
33 | users.
|
34 |
|
35 | And probably the most important of all:
|
36 |
|
37 | 4. Future stability. Google has rapidly been migrating v8 to
|
38 | [gn](https://chromium.googlesource.com/chromium/src/tools/gn/), leaving the
|
39 | future of gyp and its supportability questionable. Its clear that if gyp is
|
40 | to remain, node will likely have to take ownership of the project, as all of
|
41 | google's resources have been diverted to improving gn. Its also been made
|
42 | clear that gn isn't really intended to be used outside of chromium and isn't
|
43 | being exposed. Throw [bazel](http://bazel.io/) in the mix, and even gn's
|
44 | future is unstable.
|
45 |
|
46 | node-cmake addresses these concerns by providing a node module build system
|
47 | built on top of [CMake](https://cmake.org). CMake, like gyp, is a meta-build
|
48 | system, generating build files for the actual build tools and
|
49 | IDEs on each platform. It does this by using its own platform agnostic and
|
50 | turing complete syntax for describing the build process in general terms,
|
51 | and converting that syntax to the correct build instructions.
|
52 |
|
53 | CMake has long been a counter-argument and
|
54 | [competitor](https://gyp.gsrc.io/docs/GypVsCMake.md)
|
55 | to gyp. While the arguments outlined there are well reasoned, there are many
|
56 | arguments as to why CMake is good build system for cross platform builds:
|
57 |
|
58 | 1. No dependencies. All that is required to use CMake is to install it, and
|
59 | whatever build environment is necessary for your platform (typically,
|
60 | visual studio / xcode / gcc).
|
61 |
|
62 | 2. Library search. CMake provides a cross-platform and standardized way to
|
63 | find and link against external libraries, both those built with CMake and
|
64 | those built with other systems. It provides sensible defaults and looks in
|
65 | standard, correct places on each platform, and can be tuned for specific
|
66 | edge cases. If a library builds with CMake, their builds can be combined
|
67 | to build dependencies along with the main code.
|
68 |
|
69 | 3. Stability and Integration. CMake has been in development far longer than
|
70 | gyp, and strives to maintain backwards compability across releases. Its an
|
71 | independent project that is used by a large number of big name projects
|
72 | and will be supported for a long time. It receives regular updates that
|
73 | improve and add functionality to make building more consistent, and to
|
74 | address changes to platform specific variations and complexity. It also
|
75 | nicely integrates with visual studio, xcode and especially IDEs like
|
76 | Jetbrain's CLion IDE and KDevelop, which use CMake as their native build
|
77 | environment.
|
78 |
|
79 | This project is similar in goals to
|
80 | [cmake-js](https://www.npmjs.com/package/cmake-js), with one major difference.
|
81 | Where that project has a node-centric focus, node-cmake relies strictly on
|
82 | CMake to download and configure node for building native extensions. This
|
83 | is done to support capabilites that are hard or impossible to integrate with
|
84 | `cmake-js`, namely toolchain support for cross-platform builds, and integration
|
85 | with other cmake projects and build environments (like catkin for ROS), which
|
86 | don't know about or potentially need a node interpreter to build.
|
87 |
|
88 | node-cmake is designed to provide full parity with `node-gyp` outside of
|
89 | the names and arguments of binaries; modules will still need to be updated to
|
90 | use it, but all of `node-gyp`'s capabilities are supported.
|
91 |
|
92 | ## Usage
|
93 |
|
94 | To use this package, add the module `node-cmake` to your package.json
|
95 | as a development dependency:
|
96 |
|
97 | npm install --save-dev node-cmake
|
98 |
|
99 | Then add a `CMakeLists.txt` file to the root of your module that contains
|
100 | the following at a minimum (\<REPLACE\> with your own definitions):
|
101 |
|
102 | ```CMake
|
103 | cmake_minimum_required(VERSION 3.1)
|
104 |
|
105 | project(<NAME OF MODULE>)
|
106 |
|
107 | list(APPEND CMAKE_MODULE_PATH
|
108 | ${CMAKE_CURRENT_SOURCE_DIR}/node_modules/node-cmake
|
109 | )
|
110 |
|
111 | find_package(NodeJS)
|
112 |
|
113 | add_nodejs_module(${PROJECT_NAME} <SOURCE AND HEADER FILES GO HERE>)
|
114 | ```
|
115 |
|
116 | The `CMakeLists.txt` file is the main build script for CMake, and has the
|
117 | same purpose as the `binding.gyp` file in `node-gyp`.
|
118 |
|
119 | The `list(APPEND ...)` command tells CMake how to find the FindNodeJS.cmake
|
120 | script and must point to the directory containing this file. As written
|
121 | the variable `${CMAKE_CURRENT_SOURCE_DIR}` is a CMake variable referring to
|
122 | the directory that contains the `CMakeLists.txt` file being processed, or in
|
123 | this case, the root directory of your module. Since npm will install the
|
124 | `node-cmake` dependency underneath the `node_modules` directory, this tells
|
125 | CMake to look in the directory of this module for other scripts.
|
126 |
|
127 | The `find_package` command tells CMake that we want to find node as a
|
128 | dependency of our project. This command optionally takes arguments which
|
129 | are specified below. Typically, these arguments shouldn't be used unless
|
130 | necessary, to provide maximum flexibility for version and variant builds.
|
131 |
|
132 | Due to the complexity of creating a node module, and the strict requirements
|
133 | about the naming and placement of the shared library, node-cmake provides
|
134 | a CMake function for creating a node module, `add_nodejs_module`, similar to
|
135 | the `add_executable` and `add_library` commands native to CMake. This command
|
136 | ensures that the built shared library uses the correct build settings and
|
137 | flags on each platform. It creates a shared library `target`, specified by the
|
138 | first argument, that can be used identically to any other CMake `target`. In
|
139 | the example above, the target will be called '\<NAME OF MODULE\>'
|
140 |
|
141 | CMake has extensive documentation online, which can be
|
142 | found [here](https://cmake.org/documentation) for various versions of CMake.
|
143 | node-cmake REQUIRES CMake >= 3.1, but any newer version is also supported.
|
144 |
|
145 | ## Nan Support
|
146 |
|
147 | To simplify building of cross-version node modules,
|
148 | [Nan](https://github.com/nodejs/nan) is always included as a project
|
149 | dependency. In your module native sources, just
|
150 |
|
151 | ```C++
|
152 | #include <nan.h>
|
153 | ```
|
154 |
|
155 | At the top of any header/source file that requires this functionality.
|
156 | The version included with node-cmake will always be the newest available
|
157 | version of Nan. To use your own version, specify it as a dependency of your
|
158 | module:
|
159 |
|
160 | npm install --save-dev nan
|
161 |
|
162 | This version will be used instead of the dependency specified by node-cmake.
|
163 |
|
164 | ## Building
|
165 |
|
166 | node-cmake can be built by invoking CMake with its usual syntax, optimally
|
167 | using an out-of-source build folder. This involves creating a folder,
|
168 | navigating to that directory, and then running the `cmake` executable, with
|
169 | an arugument to the folder containing the root `CMakeLists.txt`:
|
170 |
|
171 | mkdir build
|
172 | cd build
|
173 | cmake ..
|
174 |
|
175 | To simplify integration with npm, this module provides an executable script
|
176 | called 'ncmake' that automates this process. Adding the following section:
|
177 |
|
178 | ```JSON
|
179 | "scripts": {
|
180 | "install": "ncmake --build"
|
181 | }
|
182 | ```
|
183 |
|
184 | to your `package.json` is typically all that is required to build. Additonal
|
185 | flags and options that can be passed to ncmake are outlined below. If you
|
186 | add additional non-optional arguments to this command, you MUST specify the
|
187 | build directory as the last argument (typically `out`).
|
188 |
|
189 | Once you've added this to your module, just run `npm install` to build.
|
190 |
|
191 | ## Running
|
192 |
|
193 | node-cmake also provides a simple javascript module to simplify the
|
194 | finding and loading of the built native module in your own scripts. It exposes
|
195 | a single function similar to `require` with the same effects. Calling
|
196 |
|
197 | ```JavaScript
|
198 | require('node-cmake')('<NAME OF MODULE>')
|
199 | ```
|
200 |
|
201 | will return the native module to you if it can be found in the standard
|
202 | locations used by this module for building. This function handles loading
|
203 | the correct module for your platform and architecture, and searches both
|
204 | multiple build paths and mulitple configuration paths to find the
|
205 | native library. Additional options can be passed to this function to control
|
206 | these search parameters; see the `index.js` file in this directory for
|
207 | more information.
|
208 |
|
209 | ## Variants
|
210 |
|
211 | node-cmake supports the concept of variants to allow building modules for
|
212 | alternate node environments, such as
|
213 |
|
214 | * [IO.js](https://iojs.org) - Now merged back into node (legacy support)
|
215 | * [NW.js](http://nwjs.io)
|
216 | * [Electron](http://electron.atom.io)
|
217 |
|
218 | These variants can be specified using their short names to `ncmake` using the
|
219 | `-s` flag. If a variant is specified, a version MUST also be specified using
|
220 | the `-v` flag.
|
221 |
|
222 | * Electron = electron
|
223 | * IOJS = iojs
|
224 | * NW.js = nw
|
225 | * Node = node
|
226 |
|
227 | Variants are stored in the `variants` folder and can be easily added or
|
228 | updated. If you are an owner of a variant and would like to request
|
229 | modifications or removal, or would like to add your own, please issue a
|
230 | pull request or feature request to that effect.
|
231 |
|
232 | ## Versions
|
233 |
|
234 | Each variant maintains their own version range, which is handled properly
|
235 | by the variant. Versions are specified without the leading 'v' prefix, and
|
236 | must specify all three components:
|
237 |
|
238 | [MAJOR].[MINOR].[PATCH]
|
239 |
|
240 | Two additional version 'shortcuts' are supported, which
|
241 | have logical effects:
|
242 |
|
243 | * latest - Use the latest version for a variant. Requires downloading an
|
244 | additional file to determine this at runtime.
|
245 | * installed - Only applies to the default 'node' variant; uses the
|
246 | version of the running node interpreter.
|
247 |
|
248 | ## Example
|
249 |
|
250 | An example project is provided in the `example` folder. Follow the directions
|
251 | in its README.md to build it correctly.
|
252 |
|
253 | ## NCMake Manual
|
254 |
|
255 | ncmake [options] [build_directory]
|
256 |
|
257 | Create a build directory for CMake, run the CMake configuration, and
|
258 | optionally build the project.
|
259 |
|
260 | This command can non-option arguments. If no non-option arguments are
|
261 | specified, the default build directory is assumed (out). If any
|
262 | non-option arguments are specified, the build directory relative to the
|
263 | current working directory MUST be specified as the last argument.
|
264 |
|
265 | Options (All case insensitive):
|
266 |
|
267 | --config Set the build configuration. Can be one of 'MinSizeRel',
|
268 | 'RelWithDebInfo', 'Release' or 'Debug'; or a custom
|
269 | CMake build type. See the CMake documentation for more
|
270 | information.
|
271 |
|
272 | Default: MinSizeRel
|
273 |
|
274 | --build Build the project in addition to configuration
|
275 |
|
276 | --clean-first Clean the project before building
|
277 |
|
278 | --target Build the specified target. Used for building specific
|
279 | modules, components and libraries. See the CMake
|
280 | documentation for more information.
|
281 |
|
282 | -C <STD> Set the C++ standard to <STD> level. Can be one of
|
283 | (98, 11, 14).
|
284 |
|
285 | Default: Unset, which uses the default level defined by CMake
|
286 | or the version required by the variant/version being built.
|
287 |
|
288 | -Z/-NZ Force the node sources required for building the module to
|
289 | be / not be downloaded. Useful if you want to use downloaded
|
290 | sources instead of the ones included on your platform. On
|
291 | some platforms/variants, sources must always be downloaded.
|
292 |
|
293 | -G <NAME> Set the CMake generator name. See the CMake documentation for
|
294 | more information. Used primarily on windows to specify the
|
295 | version of visual studio to build with (if not the default)
|
296 |
|
297 | Default: Unset
|
298 |
|
299 | -T <NAME> Set the toolset name for the generator. Used by some
|
300 | generators to configure the compiler used to build the
|
301 | sources.
|
302 |
|
303 | Default: Unset
|
304 |
|
305 | -S <VARIANT> Set the variant to build the module for. Used when
|
306 | building the module for variants other than Node.js
|
307 |
|
308 | Default: node
|
309 |
|
310 | -V <VERSION> Set the version of the variant to build against. Must
|
311 | be specified when the variant is specified. Can also
|
312 | be the special versions 'installed' and 'latest' when
|
313 | appropriate.
|
314 |
|
315 | Default: installed
|
316 |
|
317 | Advanced Options (All case insensitive):
|
318 |
|
319 | -A <ARCH> Set the target architecture for the node module. Useful
|
320 | when cross-compiling. Can be any valid output from
|
321 | 'process.arch'
|
322 |
|
323 | Default: process.arch
|
324 |
|
325 | -P <PLATFORM> Set the target platform for the node module. Useful when
|
326 | cross-compiling. Can be any valid output from
|
327 | 'process.platform'
|
328 |
|
329 | Default: process.platform
|
330 |
|
331 | ## find_package Manual
|
332 |
|
333 | This is an advanced configuration and is primarily supported for exotic
|
334 | builds strictly in CMake. Generally, this functionality should not be used,
|
335 | relying on `ncmake` to build via npm.
|
336 |
|
337 | The NodeJS find_package command uses the VERSION and COMPONENTS arguments
|
338 | to support build-defined versions and variants.
|
339 |
|
340 | Specify the version immediately after `NodeJS` to hard-code a version
|
341 | requirement:
|
342 |
|
343 | ```CMake
|
344 | find_package(NodeJS 0.12.7)
|
345 | ```
|
346 |
|
347 | To specify a variant, use ONE of the variant keywords above in all caps:
|
348 |
|
349 | ```CMake
|
350 | find_package(NodeJS 0.12.3 COMPONENTS NWJS)
|
351 | ```
|
352 |
|
353 | The version must always be specified when using a component.
|
354 | |
\ | No newline at end of file |