UNPKG

32.8 kBMarkdownView Raw
1# node-pre-gyp
2
3#### node-pre-gyp makes it easy to publish and install Node.js C++ addons from binaries
4
5[![Build Status](https://travis-ci.com/mapbox/node-pre-gyp.svg?branch=master)](https://travis-ci.com/mapbox/node-pre-gyp)
6[![Build status](https://ci.appveyor.com/api/projects/status/3nxewb425y83c0gv)](https://ci.appveyor.com/project/Mapbox/node-pre-gyp)
7
8`node-pre-gyp` stands between [npm](https://github.com/npm/npm) and [node-gyp](https://github.com/Tootallnate/node-gyp) and offers a cross-platform method of binary deployment.
9
10### Features
11
12 - A command line tool called `node-pre-gyp` that can install your package's C++ module from a binary.
13 - A variety of developer targeted commands for packaging, testing, and publishing binaries.
14 - A JavaScript module that can dynamically require your installed binary: `require('node-pre-gyp').find`
15
16For a hello world example of a module packaged with `node-pre-gyp` see <https://github.com/springmeyer/node-addon-example> and [the wiki ](https://github.com/mapbox/node-pre-gyp/wiki/Modules-using-node-pre-gyp) for real world examples.
17
18## Credits
19
20 - The module is modeled after [node-gyp](https://github.com/Tootallnate/node-gyp) by [@Tootallnate](https://github.com/Tootallnate)
21 - Motivation for initial development came from [@ErisDS](https://github.com/ErisDS) and the [Ghost Project](https://github.com/TryGhost/Ghost).
22 - Development is sponsored by [Mapbox](https://www.mapbox.com/)
23
24## FAQ
25
26See the [Frequently Ask Questions](https://github.com/mapbox/node-pre-gyp/wiki/FAQ).
27
28## Depends
29
30 - Node.js >= node v6.x
31
32## Install
33
34`node-pre-gyp` is designed to be installed as a local dependency of your Node.js C++ addon and accessed like:
35
36 ./node_modules/.bin/node-pre-gyp --help
37
38But you can also install it globally:
39
40 npm install node-pre-gyp -g
41
42## Usage
43
44### Commands
45
46View all possible commands:
47
48 node-pre-gyp --help
49
50- clean - Remove the entire folder containing the compiled .node module
51- install - Install pre-built binary for module
52- reinstall - Run "clean" and "install" at once
53- build - Compile the module by dispatching to node-gyp or nw-gyp
54- rebuild - Run "clean" and "build" at once
55- package - Pack binary into tarball
56- testpackage - Test that the staged package is valid
57- publish - Publish pre-built binary
58- unpublish - Unpublish pre-built binary
59- info - Fetch info on published binaries
60
61You can also chain commands:
62
63 node-pre-gyp clean build unpublish publish info
64
65### Options
66
67Options include:
68
69 - `-C/--directory`: run the command in this directory
70 - `--build-from-source`: build from source instead of using pre-built binary
71 - `--update-binary`: reinstall by replacing previously installed local binary with remote binary
72 - `--runtime=node-webkit`: customize the runtime: `node`, `electron` and `node-webkit` are the valid options
73 - `--fallback-to-build`: fallback to building from source if pre-built binary is not available
74 - `--target=0.4.0`: Pass the target node or node-webkit version to compile against
75 - `--target_arch=ia32`: Pass the target arch and override the host `arch`. Valid values are 'ia32','x64', or `arm`.
76 - `--target_platform=win32`: Pass the target platform and override the host `platform`. Valid values are `linux`, `darwin`, `win32`, `sunos`, `freebsd`, `openbsd`, and `aix`.
77
78Both `--build-from-source` and `--fallback-to-build` can be passed alone or they can provide values. You can pass `--fallback-to-build=false` to override the option as declared in package.json. In addition to being able to pass `--build-from-source` you can also pass `--build-from-source=myapp` where `myapp` is the name of your module.
79
80For example: `npm install --build-from-source=myapp`. This is useful if:
81
82 - `myapp` is referenced in the package.json of a larger app and therefore `myapp` is being installed as a dependency with `npm install`.
83 - The larger app also depends on other modules installed with `node-pre-gyp`
84 - You only want to trigger a source compile for `myapp` and the other modules.
85
86### Configuring
87
88This is a guide to configuring your module to use node-pre-gyp.
89
90#### 1) Add new entries to your `package.json`
91
92 - Add `node-pre-gyp` to `dependencies`
93 - Add `aws-sdk` as a `devDependency`
94 - Add a custom `install` script
95 - Declare a `binary` object
96
97This looks like:
98
99```js
100 "dependencies" : {
101 "node-pre-gyp": "0.6.x"
102 },
103 "devDependencies": {
104 "aws-sdk": "2.x"
105 }
106 "scripts": {
107 "install": "node-pre-gyp install --fallback-to-build"
108 },
109 "binary": {
110 "module_name": "your_module",
111 "module_path": "./lib/binding/",
112 "host": "https://your_module.s3-us-west-1.amazonaws.com"
113 }
114```
115
116For a full example see [node-addon-examples's package.json](https://github.com/springmeyer/node-addon-example/blob/master/package.json).
117
118Let's break this down:
119
120 - Dependencies need to list `node-pre-gyp`
121 - Your devDependencies should list `aws-sdk` so that you can run `node-pre-gyp publish` locally or a CI system. We recommend using `devDependencies` only since `aws-sdk` is large and not needed for `node-pre-gyp install` since it only uses http to fetch binaries
122 - Your `scripts` section should override the `install` target with `"install": "node-pre-gyp install --fallback-to-build"`. This allows node-pre-gyp to be used instead of the default npm behavior of always source compiling with `node-gyp` directly.
123 - Your package.json should contain a `binary` section describing key properties you provide to allow node-pre-gyp to package optimally. They are detailed below.
124
125Note: in the past we recommended putting `node-pre-gyp` in the `bundledDependencies`, but we no longer recommend this. In the past there were npm bugs (with node versions 0.10.x) that could lead to node-pre-gyp not being available at the right time during install (unless we bundled). This should no longer be the case. Also, for a time we recommended using `"preinstall": "npm install node-pre-gyp"` as an alternative method to avoid needing to bundle. But this did not behave predictably across all npm versions - see https://github.com/mapbox/node-pre-gyp/issues/260 for the details. So we do not recommend using `preinstall` to install `node-pre-gyp`. More history on this at https://github.com/strongloop/fsevents/issues/157#issuecomment-265545908.
126
127##### The `binary` object has three required properties
128
129###### module_name
130
131The name of your native node module. This value must:
132
133 - Match the name passed to [the NODE_MODULE macro](http://nodejs.org/api/addons.html#addons_hello_world)
134 - Must be a valid C variable name (e.g. it cannot contain `-`)
135 - Should not include the `.node` extension.
136
137###### module_path
138
139The location your native module is placed after a build. This should be an empty directory without other Javascript files. This entire directory will be packaged in the binary tarball. When installing from a remote package this directory will be overwritten with the contents of the tarball.
140
141Note: This property supports variables based on [Versioning](#versioning).
142
143###### host
144
145A url to the remote location where you've published tarball binaries (must be `https` not `http`).
146
147It is highly recommended that you use Amazon S3. The reasons are:
148
149 - Various node-pre-gyp commands like `publish` and `info` only work with an S3 host.
150 - S3 is a very solid hosting platform for distributing large files.
151 - We provide detail documentation for using [S3 hosting](#s3-hosting) with node-pre-gyp.
152
153Why then not require S3? Because while some applications using node-pre-gyp need to distribute binaries as large as 20-30 MB, others might have very small binaries and might wish to store them in a GitHub repo. This is not recommended, but if an author really wants to host in a non-S3 location then it should be possible.
154
155It should also be mentioned that there is an optional and entirely separate npm module called [node-pre-gyp-github](https://github.com/bchr02/node-pre-gyp-github) which is intended to complement node-pre-gyp and be installed along with it. It provides the ability to store and publish your binaries within your repositories GitHub Releases if you would rather not use S3 directly. Installation and usage instructions can be found [here](https://github.com/bchr02/node-pre-gyp-github), but the basic premise is that instead of using the ```node-pre-gyp publish``` command you would use ```node-pre-gyp-github publish```.
156
157##### The `binary` object has two optional properties
158
159###### remote_path
160
161It **is recommended** that you customize this property. This is an extra path to use for publishing and finding remote tarballs. The default value for `remote_path` is `""` meaning that if you do not provide it then all packages will be published at the base of the `host`. It is recommended to provide a value like `./{name}/v{version}` to help organize remote packages in the case that you choose to publish multiple node addons to the same `host`.
162
163Note: This property supports variables based on [Versioning](#versioning).
164
165###### package_name
166
167It is **not recommended** to override this property unless you are also overriding the `remote_path`. This is the versioned name of the remote tarball containing the binary `.node` module and any supporting files you've placed inside the `module_path` directory. Unless you specify `package_name` in your `package.json` then it defaults to `{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz` which allows your binary to work across node versions, platforms, and architectures. If you are using `remote_path` that is also versioned by `./{module_name}/v{version}` then you could remove these variables from the `package_name` and just use: `{node_abi}-{platform}-{arch}.tar.gz`. Then your remote tarball will be looked up at, for example, `https://example.com/your-module/v0.1.0/node-v11-linux-x64.tar.gz`.
168
169Avoiding the version of your module in the `package_name` and instead only embedding in a directory name can be useful when you want to make a quick tag of your module that does not change any C++ code. In this case you can just copy binaries to the new version behind the scenes like:
170
171```sh
172aws s3 sync --acl public-read s3://mapbox-node-binary/sqlite3/v3.0.3/ s3://mapbox-node-binary/sqlite3/v3.0.4/
173```
174
175Note: This property supports variables based on [Versioning](#versioning).
176
177#### 2) Add a new target to binding.gyp
178
179`node-pre-gyp` calls out to `node-gyp` to compile the module and passes variables along like [module_name](#module_name) and [module_path](#module_path).
180
181A new target must be added to `binding.gyp` that moves the compiled `.node` module from `./build/Release/module_name.node` into the directory specified by `module_path`.
182
183Add a target like this at the end of your `targets` list:
184
185```js
186 {
187 "target_name": "action_after_build",
188 "type": "none",
189 "dependencies": [ "<(module_name)" ],
190 "copies": [
191 {
192 "files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
193 "destination": "<(module_path)"
194 }
195 ]
196 }
197```
198
199For a full example see [node-addon-example's binding.gyp](https://github.com/springmeyer/node-addon-example/blob/2ff60a8ded7f042864ad21db00c3a5a06cf47075/binding.gyp).
200
201#### 3) Dynamically require your `.node`
202
203Inside the main js file that requires your addon module you are likely currently doing:
204
205```js
206var binding = require('../build/Release/binding.node');
207```
208
209or:
210
211```js
212var bindings = require('./bindings')
213```
214
215Change those lines to:
216
217```js
218var binary = require('node-pre-gyp');
219var path = require('path');
220var binding_path = binary.find(path.resolve(path.join(__dirname,'./package.json')));
221var binding = require(binding_path);
222```
223
224For a full example see [node-addon-example's index.js](https://github.com/springmeyer/node-addon-example/blob/2ff60a8ded7f042864ad21db00c3a5a06cf47075/index.js#L1-L4)
225
226#### 4) Build and package your app
227
228Now build your module from source:
229
230 npm install --build-from-source
231
232The `--build-from-source` tells `node-pre-gyp` to not look for a remote package and instead dispatch to node-gyp to build.
233
234Now `node-pre-gyp` should now also be installed as a local dependency so the command line tool it offers can be found at `./node_modules/.bin/node-pre-gyp`.
235
236#### 5) Test
237
238Now `npm test` should work just as it did before.
239
240#### 6) Publish the tarball
241
242Then package your app:
243
244 ./node_modules/.bin/node-pre-gyp package
245
246Once packaged, now you can publish:
247
248 ./node_modules/.bin/node-pre-gyp publish
249
250Currently the `publish` command pushes your binary to S3. This requires:
251
252 - You have installed `aws-sdk` with `npm install aws-sdk`
253 - You have created a bucket already.
254 - The `host` points to an S3 http or https endpoint.
255 - You have configured node-pre-gyp to read your S3 credentials (see [S3 hosting](#s3-hosting) for details).
256
257You can also host your binaries elsewhere. To do this requires:
258
259 - You manually publish the binary created by the `package` command to an `https` endpoint
260 - Ensure that the `host` value points to your custom `https` endpoint.
261
262#### 7) Automate builds
263
264Now you need to publish builds for all the platforms and node versions you wish to support. This is best automated.
265
266 - See [Appveyor Automation](#appveyor-automation) for how to auto-publish builds on Windows.
267 - See [Travis Automation](#travis-automation) for how to auto-publish builds on OS X and Linux.
268
269#### 8) You're done!
270
271Now publish your module to the npm registry. Users will now be able to install your module from a binary.
272
273What will happen is this:
274
2751. `npm install <your package>` will pull from the npm registry
2762. npm will run the `install` script which will call out to `node-pre-gyp`
2773. `node-pre-gyp` will fetch the binary `.node` module and unpack in the right place
2784. Assuming that all worked, you are done
279
280If a a binary was not available for a given platform and `--fallback-to-build` was used then `node-gyp rebuild` will be called to try to source compile the module.
281
282## N-API Considerations
283
284[N-API](https://nodejs.org/api/n-api.html#n_api_n_api) is an ABI-stable alternative to previous technologies such as [nan](https://github.com/nodejs/nan) which are tied to a specific Node runtime engine. N-API is Node runtime engine agnostic and guarantees modules created today will continue to run, without changes, into the future.
285
286Using `node-pre-gyp` with N-API projects requires a handful of additional configuration values and imposes some additional requirements.
287
288The most significant difference is that an N-API module can be coded to target multiple N-API versions. Therefore, an N-API module must declare in its `package.json` file which N-API versions the module is designed to run against. In addition, since multiple builds may be required for a single module, path and file names must be specified in way that avoids naming conflicts.
289
290### The `napi_versions` array property
291
292An N-API modules must declare in its `package.json` file, the N-API versions the module is intended to support. This is accomplished by including an `napi-versions` array property in the `binary` object. For example:
293
294```js
295"binary": {
296 "module_name": "your_module",
297 "module_path": "your_module_path",
298 "host": "https://your_bucket.s3-us-west-1.amazonaws.com",
299 "napi_versions": [1,3]
300 }
301```
302
303If the `napi_versions` array property is *not* present, `node-pre-gyp` operates as it always has. Including the `napi_versions` array property instructs `node-pre-gyp` that this is a N-API module build.
304
305When the `napi_versions` array property is present, `node-pre-gyp` fires off multiple operations, one for each of the N-API versions in the array. In the example above, two operations are initiated, one for N-API version 1 and second for N-API version 3. How this version number is communicated is described next.
306
307### The `napi_build_version` value
308
309For each of the N-API module operations `node-pre-gyp` initiates, it ensures that the `napi_build_version` is set appropriately.
310
311This value is of importance in two areas:
312
3131. The C/C++ code which needs to know against which N-API version it should compile.
3142. `node-pre-gyp` itself which must assign appropriate path and file names to avoid collisions.
315
316### Defining `NAPI_VERSION` for the C/C++ code
317
318The `napi_build_version` value is communicated to the C/C++ code by adding this code to the `binding.gyp` file:
319
320```
321"defines": [
322 "NAPI_VERSION=<(napi_build_version)",
323]
324```
325
326This ensures that `NAPI_VERSION`, an integer value, is declared appropriately to the C/C++ code for each build.
327
328> Note that earlier versions of this document recommended defining the symbol `NAPI_BUILD_VERSION`. `NAPI_VERSION` is prefered because it used by the N-API C/C++ headers to configure the specific N-API veriosn being requested.
329
330### Path and file naming requirements in `package.json`
331
332Since `node-pre-gyp` fires off multiple operations for each request, it is essential that path and file names be created in such a way as to avoid collisions. This is accomplished by imposing additional path and file naming requirements.
333
334Specifically, when performing N-API builds, the `{napi_build_version}` text configuration value *must* be present in the `module_path` property. In addition, the `{napi_build_version}` text configuration value *must* be present in either the `remote_path` or `package_name` property. (No problem if it's in both.)
335
336Here's an example:
337
338```js
339"binary": {
340 "module_name": "your_module",
341 "module_path": "./lib/binding/napi-v{napi_build_version}",
342 "remote_path": "./{module_name}/v{version}/{configuration}/",
343 "package_name": "{platform}-{arch}-napi-v{napi_build_version}.tar.gz",
344 "host": "https://your_bucket.s3-us-west-1.amazonaws.com",
345 "napi_versions": [1,3]
346 }
347```
348
349## Supporting both N-API and NAN builds
350
351You may have a legacy native add-on that you wish to continue supporting for those versions of Node that do not support N-API, as you add N-API support for later Node versions. This can be accomplished by specifying the `node_napi_label` configuration value in the package.json `binary.package_name` property.
352
353Placing the configuration value `node_napi_label` in the package.json `binary.package_name` property instructs `node-pre-gyp` to build all viable N-API binaries supported by the current Node instance. If the current Node instance does not support N-API, `node-pre-gyp` will request a traditional, non-N-API build.
354
355The configuration value `node_napi_label` is set by `node-pre-gyp` to the type of build created, `napi` or `node`, and the version number. For N-API builds, the string contains the N-API version nad has values like `napi-v3`. For traditional, non-N-API builds, the string contains the ABI version with values like `node-v46`.
356
357Here's how the `binary` configuration above might be changed to support both N-API and NAN builds:
358
359```js
360"binary": {
361 "module_name": "your_module",
362 "module_path": "./lib/binding/{node_napi_label}",
363 "remote_path": "./{module_name}/v{version}/{configuration}/",
364 "package_name": "{platform}-{arch}-{node_napi_label}.tar.gz",
365 "host": "https://your_bucket.s3-us-west-1.amazonaws.com",
366 "napi_versions": [1,3]
367 }
368```
369
370The C/C++ symbol `NAPI_VERSION` can be used to distinguish N-API and non-N-API builds. The value of `NAPI_VERSION` is set to the integer N-API version for N-API builds and is set to `0` for non-N-API builds.
371
372For example:
373
374```C
375#if NAPI_VERSION
376// N-API code goes here
377#else
378// NAN code goes here
379#endif
380```
381
382### Two additional configuration values
383
384The following two configuration values, which were implemented in previous versions of `node-pre-gyp`, continue to exist, but have been replaced by the `node_napi_label` configuration value described above.
385
3861. `napi_version` If N-API is supported by the currently executing Node instance, this value is the N-API version number supported by Node. If N-API is not supported, this value is an empty string.
387
3882. `node_abi_napi` If the value returned for `napi_version` is non empty, this value is `'napi'`. If the value returned for `napi_version` is empty, this value is the value returned for `node_abi`.
389
390These values are present for use in the `binding.gyp` file and may be used as `{napi_version}` and `{node_abi_napi}` for text substituion in the `binary` properties of the `package.json` file.
391
392## S3 Hosting
393
394You can host wherever you choose but S3 is cheap, `node-pre-gyp publish` expects it, and S3 can be integrated well with [Travis.ci](http://travis-ci.org) to automate builds for OS X and Ubuntu, and with [Appveyor](http://appveyor.com) to automate builds for Windows. Here is an approach to do this:
395
396First, get setup locally and test the workflow:
397
398#### 1) Create an S3 bucket
399
400And have your **key** and **secret key** ready for writing to the bucket.
401
402It is recommended to create a IAM user with a policy that only gives permissions to the specific bucket you plan to publish to. This can be done in the [IAM console](https://console.aws.amazon.com/iam/) by: 1) adding a new user, 2) choosing `Attach User Policy`, 3) Using the `Policy Generator`, 4) selecting `Amazon S3` for the service, 5) adding the actions: `DeleteObject`, `GetObject`, `GetObjectAcl`, `ListBucket`, `PutObject`, `PutObjectAcl`, 6) adding an ARN of `arn:aws:s3:::bucket/*` (replacing `bucket` with your bucket name), and finally 7) clicking `Add Statement` and saving the policy. It should generate a policy like:
403
404```js
405{
406 "Version": "2012-10-17",
407 "Statement": [
408 {
409 "Sid": "Stmt1394587197000",
410 "Effect": "Allow",
411 "Action": [
412 "s3:DeleteObject",
413 "s3:GetObject",
414 "s3:GetObjectAcl",
415 "s3:ListBucket",
416 "s3:PutObject",
417 "s3:PutObjectAcl"
418 ],
419 "Resource": [
420 "arn:aws:s3:::node-pre-gyp-tests/*"
421 ]
422 }
423 ]
424}
425```
426
427#### 2) Install node-pre-gyp
428
429Either install it globally:
430
431 npm install node-pre-gyp -g
432
433Or put the local version on your PATH
434
435 export PATH=`pwd`/node_modules/.bin/:$PATH
436
437#### 3) Configure AWS credentials
438
439There are several ways to do this.
440
441You can use any of the methods described at http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html.
442
443Or you can create a `~/.node_pre_gyprc`
444
445Or pass options in any way supported by [RC](https://github.com/dominictarr/rc#standards)
446
447A `~/.node_pre_gyprc` looks like:
448
449```js
450{
451 "accessKeyId": "xxx",
452 "secretAccessKey": "xxx"
453}
454```
455
456Another way is to use your environment:
457
458 export node_pre_gyp_accessKeyId=xxx
459 export node_pre_gyp_secretAccessKey=xxx
460
461You may also need to specify the `region` if it is not explicit in the `host` value you use. The `bucket` can also be specified but it is optional because `node-pre-gyp` will detect it from the `host` value.
462
463#### 4) Package and publish your build
464
465Install the `aws-sdk`:
466
467 npm install aws-sdk
468
469Then publish:
470
471 node-pre-gyp package publish
472
473Note: if you hit an error like `Hostname/IP doesn't match certificate's altnames` it may mean that you need to provide the `region` option in your config.
474
475## Appveyor Automation
476
477[Appveyor](http://www.appveyor.com/) can build binaries and publish the results per commit and supports:
478
479 - Windows Visual Studio 2013 and related compilers
480 - Both 64 bit (x64) and 32 bit (x86) build configurations
481 - Multiple Node.js versions
482
483For an example of doing this see [node-sqlite3's appveyor.yml](https://github.com/mapbox/node-sqlite3/blob/master/appveyor.yml).
484
485Below is a guide to getting set up:
486
487#### 1) Create a free Appveyor account
488
489Go to https://ci.appveyor.com/signup/free and sign in with your GitHub account.
490
491#### 2) Create a new project
492
493Go to https://ci.appveyor.com/projects/new and select the GitHub repo for your module
494
495#### 3) Add appveyor.yml and push it
496
497Once you have committed an `appveyor.yml` ([appveyor.yml reference](http://www.appveyor.com/docs/appveyor-yml)) to your GitHub repo and pushed it AppVeyor should automatically start building your project.
498
499#### 4) Create secure variables
500
501Encrypt your S3 AWS keys by going to <https://ci.appveyor.com/tools/encrypt> and hitting the `encrypt` button.
502
503Then paste the result into your `appveyor.yml`
504
505```yml
506environment:
507 node_pre_gyp_accessKeyId:
508 secure: Dn9HKdLNYvDgPdQOzRq/DqZ/MPhjknRHB1o+/lVU8MA=
509 node_pre_gyp_secretAccessKey:
510 secure: W1rwNoSnOku1r+28gnoufO8UA8iWADmL1LiiwH9IOkIVhDTNGdGPJqAlLjNqwLnL
511```
512
513NOTE: keys are per account but not per repo (this is difference than Travis where keys are per repo but not related to the account used to encrypt them).
514
515#### 5) Hook up publishing
516
517Just put `node-pre-gyp package publish` in your `appveyor.yml` after `npm install`.
518
519#### 6) Publish when you want
520
521You might wish to publish binaries only on a specific commit. To do this you could borrow from the [Travis CI idea of commit keywords](http://about.travis-ci.org/docs/user/how-to-skip-a-build/) and add special handling for commit messages with `[publish binary]`:
522
523 SET CM=%APPVEYOR_REPO_COMMIT_MESSAGE%
524 if not "%CM%" == "%CM:[publish binary]=%" node-pre-gyp --msvs_version=2013 publish
525
526If your commit message contains special characters (e.g. `&`) this method might fail. An alternative is to use PowerShell, which gives you additional possibilities, like ignoring case by using `ToLower()`:
527
528 ps: if($env:APPVEYOR_REPO_COMMIT_MESSAGE.ToLower().Contains('[publish binary]')) { node-pre-gyp --msvs_version=2013 publish }
529
530Remember this publishing is not the same as `npm publish`. We're just talking about the binary module here and not your entire npm package.
531
532## Travis Automation
533
534[Travis](https://travis-ci.org/) can push to S3 after a successful build and supports both:
535
536 - Ubuntu Precise and OS X (64 bit)
537 - Multiple Node.js versions
538
539For an example of doing this see [node-add-example's .travis.yml](https://github.com/springmeyer/node-addon-example/blob/2ff60a8ded7f042864ad21db00c3a5a06cf47075/.travis.yml).
540
541Note: if you need 32 bit binaries, this can be done from a 64 bit Travis machine. See [the node-sqlite3 scripts for an example of doing this](https://github.com/mapbox/node-sqlite3/blob/bae122aa6a2b8a45f6b717fab24e207740e32b5d/scripts/build_against_node.sh#L54-L74).
542
543Below is a guide to getting set up:
544
545#### 1) Install the Travis gem
546
547 gem install travis
548
549#### 2) Create secure variables
550
551Make sure you run this command from within the directory of your module.
552
553Use `travis-encrypt` like:
554
555 travis encrypt node_pre_gyp_accessKeyId=${node_pre_gyp_accessKeyId}
556 travis encrypt node_pre_gyp_secretAccessKey=${node_pre_gyp_secretAccessKey}
557
558Then put those values in your `.travis.yml` like:
559
560```yaml
561env:
562 global:
563 - secure: F+sEL/v56CzHqmCSSES4pEyC9NeQlkoR0Gs/ZuZxX1ytrj8SKtp3MKqBj7zhIclSdXBz4Ev966Da5ctmcTd410p0b240MV6BVOkLUtkjZJyErMBOkeb8n8yVfSoeMx8RiIhBmIvEn+rlQq+bSFis61/JkE9rxsjkGRZi14hHr4M=
564 - secure: o2nkUQIiABD139XS6L8pxq3XO5gch27hvm/gOdV+dzNKc/s2KomVPWcOyXNxtJGhtecAkABzaW8KHDDi5QL1kNEFx6BxFVMLO8rjFPsMVaBG9Ks6JiDQkkmrGNcnVdxI/6EKTLHTH5WLsz8+J7caDBzvKbEfTux5EamEhxIWgrI=
565```
566
567More details on Travis encryption at http://about.travis-ci.org/docs/user/encryption-keys/.
568
569#### 3) Hook up publishing
570
571Just put `node-pre-gyp package publish` in your `.travis.yml` after `npm install`.
572
573##### OS X publishing
574
575If you want binaries for OS X in addition to linux you can enable [multi-os for Travis](http://docs.travis-ci.com/user/multi-os/#Setting-.travis.yml)
576
577Use a configuration like:
578
579```yml
580
581language: cpp
582
583os:
584- linux
585- osx
586
587env:
588 matrix:
589 - NODE_VERSION="4"
590 - NODE_VERSION="6"
591
592before_install:
593- rm -rf ~/.nvm/ && git clone --depth 1 https://github.com/creationix/nvm.git ~/.nvm
594- source ~/.nvm/nvm.sh
595- nvm install $NODE_VERSION
596- nvm use $NODE_VERSION
597```
598
599See [Travis OS X Gotchas](#travis-os-x-gotchas) for why we replace `language: node_js` and `node_js:` sections with `language: cpp` and a custom matrix.
600
601Also create platform specific sections for any deps that need install. For example if you need libpng:
602
603```yml
604- if [ $(uname -s) == 'Linux' ]; then apt-get install libpng-dev; fi;
605- if [ $(uname -s) == 'Darwin' ]; then brew install libpng; fi;
606```
607
608For detailed multi-OS examples see [node-mapnik](https://github.com/mapnik/node-mapnik/blob/master/.travis.yml) and [node-sqlite3](https://github.com/mapbox/node-sqlite3/blob/master/.travis.yml).
609
610##### Travis OS X Gotchas
611
612First, unlike the Travis Linux machines, the OS X machines do not put `node-pre-gyp` on PATH by default. To do so you will need to:
613
614```sh
615export PATH=$(pwd)/node_modules/.bin:${PATH}
616```
617
618Second, the OS X machines do not support using a matrix for installing different Node.js versions. So you need to bootstrap the installation of Node.js in a cross platform way.
619
620By doing:
621
622```yml
623env:
624 matrix:
625 - NODE_VERSION="4"
626 - NODE_VERSION="6"
627
628before_install:
629 - rm -rf ~/.nvm/ && git clone --depth 1 https://github.com/creationix/nvm.git ~/.nvm
630 - source ~/.nvm/nvm.sh
631 - nvm install $NODE_VERSION
632 - nvm use $NODE_VERSION
633```
634
635You can easily recreate the previous behavior of this matrix:
636
637```yml
638node_js:
639 - "4"
640 - "6"
641```
642
643#### 4) Publish when you want
644
645You might wish to publish binaries only on a specific commit. To do this you could borrow from the [Travis CI idea of commit keywords](http://about.travis-ci.org/docs/user/how-to-skip-a-build/) and add special handling for commit messages with `[publish binary]`:
646
647 COMMIT_MESSAGE=$(git log --format=%B --no-merges -n 1 | tr -d '\n')
648 if [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then node-pre-gyp publish; fi;
649
650Then you can trigger new binaries to be built like:
651
652 git commit -a -m "[publish binary]"
653
654Or, if you don't have any changes to make simply run:
655
656 git commit --allow-empty -m "[publish binary]"
657
658WARNING: if you are working in a pull request and publishing binaries from there then you will want to avoid double publishing when Travis CI builds both the `push` and `pr`. You only want to run the publish on the `push` commit. See https://github.com/Project-OSRM/node-osrm/blob/8eb837abe2e2e30e595093d16e5354bc5c573575/scripts/is_pr_merge.sh which is called from https://github.com/Project-OSRM/node-osrm/blob/8eb837abe2e2e30e595093d16e5354bc5c573575/scripts/publish.sh for an example of how to do this.
659
660Remember this publishing is not the same as `npm publish`. We're just talking about the binary module here and not your entire npm package. To automate the publishing of your entire package to npm on Travis see http://about.travis-ci.org/docs/user/deployment/npm/
661
662# Versioning
663
664The `binary` properties of `module_path`, `remote_path`, and `package_name` support variable substitution. The strings are evaluated by `node-pre-gyp` depending on your system and any custom build flags you passed.
665
666 - `node_abi`: The node C++ `ABI` number. This value is available in Javascript as `process.versions.modules` as of [`>= v0.10.4 >= v0.11.7`](https://github.com/joyent/node/commit/ccabd4a6fa8a6eb79d29bc3bbe9fe2b6531c2d8e) and in C++ as the `NODE_MODULE_VERSION` define much earlier. For versions of Node before this was available we fallback to the V8 major and minor version.
667 - `platform` matches node's `process.platform` like `linux`, `darwin`, and `win32` unless the user passed the `--target_platform` option to override.
668 - `arch` matches node's `process.arch` like `x64` or `ia32` unless the user passes the `--target_arch` option to override.
669 - `libc` matches `require('detect-libc').family` like `glibc` or `musl` unless the user passes the `--target_libc` option to override.
670 - `configuration` - Either 'Release' or 'Debug' depending on if `--debug` is passed during the build.
671 - `module_name` - the `binary.module_name` attribute from `package.json`.
672 - `version` - the semver `version` value for your module from `package.json` (NOTE: ignores the `semver.build` property).
673 - `major`, `minor`, `patch`, and `prelease` match the individual semver values for your module's `version`
674 - `build` - the sevmer `build` value. For example it would be `this.that` if your package.json `version` was `v1.0.0+this.that`
675 - `prerelease` - the semver `prerelease` value. For example it would be `alpha.beta` if your package.json `version` was `v1.0.0-alpha.beta`
676
677
678The options are visible in the code at <https://github.com/mapbox/node-pre-gyp/blob/612b7bca2604508d881e1187614870ba19a7f0c5/lib/util/versioning.js#L114-L127>
679
680# Download binary files from a mirror
681
682S3 is broken in China for the well known reason.
683
684Using the `npm` config argument: `--{module_name}_binary_host_mirror` can download binary files through a mirror.
685
686e.g.: Install [v8-profiler](https://www.npmjs.com/package/v8-profiler) from `npm`.
687
688```bash
689$ npm install v8-profiler --profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/
690```