(Switch macro-scripts back to %{_prefix}/lib/rpm as after some conversation that seems to be the best place) |
(remove nodejs_fixdeps for now, until a rewritten script is present) |
||
(9 intermediate revisions by 2 users not shown) | |||
Line 32: | Line 32: | ||
|- | |- | ||
|nodejs_symlink_deps||%{_prefix}/lib/rpm/nodejs-symlink-deps||See [[#Symlinking Dependencies]] below. | |nodejs_symlink_deps||%{_prefix}/lib/rpm/nodejs-symlink-deps||See [[#Symlinking Dependencies]] below. | ||
|} | |} | ||
Line 92: | Line 90: | ||
=== Correcting Dependencies === | === Correcting Dependencies === | ||
Occasionally the dependencies listed in package.json are inaccurate. For instance, the module may work with a newer version of a dependency than the one explictly listed in the ''package.json'' file. | Occasionally the dependencies listed in package.json are inaccurate. For instance, the module may work with a newer version of a dependency than the one explictly listed in the ''package.json'' file. You can use a patch to fix this and then send the patch to upstream. | ||
{{admon/warning|Always fix ''package.json''|RPM macros like <code>%nodejs_symlink_deps</code> rely on accurate information in ''package.json'' to work properly, as does the Node.js interpreter and npm at runtime.}} | {{admon/warning|Always fix ''package.json''|RPM macros like <code>%nodejs_symlink_deps</code> rely on accurate information in ''package.json'' to work properly, as does the Node.js interpreter and npm at runtime.}} | ||
== Symlinking Dependencies == | == Symlinking Dependencies == | ||
Line 162: | Line 132: | ||
<code>node-gyp</code> creates a shared object file conventionally named <code><module name>.node</code> as part of its build process, which should be located in <code>build/Release</code>. This file may be used as the main entry point for the library, or is utilized by JavaScript wrapper code included with the module. | <code>node-gyp</code> creates a shared object file conventionally named <code><module name>.node</code> as part of its build process, which should be located in <code>build/Release</code>. This file may be used as the main entry point for the library, or is utilized by JavaScript wrapper code included with the module. | ||
{{admon/tip|Identifying whether a module contains JavaScript wrapper code|The easiest way to identify whether a module contains JavaScript wrapper code is simply to check for the existence of JavaScript (<code>.js</code>) files in the tarball that are used in a library context (i.e. make sure they aren't just used for tests or other ancillary purposes). You can also check if the main entrypoint is defined in ''package.json'' in the <code>main</code> property.}} | |||
If the shared object is used as the main entry point, it should be installed at <code>%{nodejs_sitelib}/<module name>/<module_name>.node</code>. The `require()` function will automatically load this if there is no corresponding `<module name>.js` or entry point defined in ''package.json'' to override it. For example: | If the shared object is used as the main entry point, it should be installed at <code>%{nodejs_sitelib}/<module name>/<module_name>.node</code>. The `require()` function will automatically load this if there is no corresponding `<module name>.js` or entry point defined in ''package.json'' to override it. For example: | ||
Line 194: | Line 166: | ||
The Fedora version of <code>node-gyp</code> will handle the fact that shared versions of libuv, v8, and http_parser without modification to the module, since <code>node-gyp</code> always unconditionally configures these libraries. However, some modules may rely on other libraries bundled with node, such as openssl or c-ares. These may need to be patched to use the system headers for these libraries. | The Fedora version of <code>node-gyp</code> will handle the fact that shared versions of libuv, v8, and http_parser without modification to the module, since <code>node-gyp</code> always unconditionally configures these libraries. However, some modules may rely on other libraries bundled with node, such as openssl or c-ares. These may need to be patched to use the system headers for these libraries. | ||
{{ | == Questions == | ||
* clarification (does not need vote) of the "[...]shared versions of libuv,[...]" line | |||
** Node.js upstream bundles everything, and some native modules make some assumptions about the structure of headers and such based on that. Our <code>node-gyp</code> is patched so things "just work" 95% of the time, but some special attention might be required if modules try doing something fancy. I'll clarify the wording in the section a little bit. | |||
** Thanks | |||
* http://nodejs.org/api/addons.html <= Is this still static linking or has it been fixed? | |||
** This is true with the standard upstream distribution, but not true in Fedora. Our <code>node-gyp</code> package ensures all necessary linker flags are set, so this isn't a problem though. I'll talk with upstream about clarifying that documentation, as it probably isn't true in e.g. Debian too. | |||
** Thanks | |||
* Do we really need a multilib exemption or would %{_libdir} for both module locations work? | |||
** That would be tricky. npm only looks in %{_prefix}/lib/node_modules and would need to be patched to handle this. We probably couldn't ship it as noarch if we did this, correct? | |||
*** Correct. I think that some of the FPC members wanted the package to simply declare itself to be arch-specific and use %{_libdir} instead of %{_prefix}/lib . A little rationale for using %{_prefix}/lib would probably get the votes needed (assuming that a fesco exemption is also approved). | |||
****Come to think of it, we'll have to ship ''every'' Node.js module arch-specfic if we did that, since the install destination would be different for all of them. I really don't think we want that. | |||
* "The nodejs package includes an automatic Requires and Provides generator that automatically adds versioned dependencies based on the information provided in a module's package.json file." <= Should that be in nodejs-devel instead? | |||
** That's what I thought, but when I set this up I checked repoquery/rpm all the dep generators I saw shipped in the main package. It'd be nice to have FPC guidance on the proper location. | |||
*** The *-devel package is usually what we use. sgallagh says that he can move them there. | |||
* Would like a spec template | |||
** Something like this? [http://patches.fedorapeople.org/nodejs/nodejs-template.spec] | |||
*** Looks good to me. | |||
=== RE: %nodejs fixdep === | |||
After some thought, I think it might be better to drop %nodejs_fixdep and provide a similar script that generates a patch instead. (I'll soon put together an RPM with some useful scripts for node packaging where it can live comfortably.) That way I can depend on a json library that respects the original structure so patches are upstreamable without bloating the nodejs package's deps. |
Latest revision as of 17:25, 30 January 2013
Original Author: T.C. Hollingsworth
Based on the guidelines of other interpreted languages like Ruby and Python.
Naming Guidelines
- The name of a Node.js extension/library package must start with nodejs- then the upstream name or name used in the npm registry. For example: nodejs-foomodule. While it is uncommon for a package's name to contain node, if it does, you should still add the nodejs prefix. For instance, the npm registry contains a uuid and a node-uuid module, which would need to be named nodejs-uuid and nodejs-node-uuid, repsectively.
- Application packages that mainly provide tools (as opposed to libraries) that happen to be written for Node.js must follow the general naming guidelines instead.
BuildRequires
To build a package containing pure JavaScript node modules, you need to have:
BuildRequires: nodejs-devel
Additional BuildRequires may be necessary for native modules. See #Building native modules with node-gyp for more information.
Macros
In Fedora 18 and later, as well as EPEL 6, the following macros are defined for you:
Macro | Normal Definition | Notes |
---|---|---|
__nodejs | %{_bindir}/node | The Node.js interpreter |
nodejs_version | e.g. 0.9.5 | The currently installed version of Node.js. |
nodejs_sitelib | %{_prefix}/lib/node_modules | Where Node.js modules written purely in JavaScript are installed |
nodejs_sitearch | %{_prefix}/lib/node_modules | Where native C++ Node.js modules are installed |
nodejs_symlink_deps | %{_prefix}/lib/rpm/nodejs-symlink-deps | See #Symlinking Dependencies below. |
These macros are provided by the nodejs package.
During %install
or when listing %files
you can use the %nodejs_sitelib
or %nodejs_sitearch
macro to specify where the installed modules are to be found. For instance:
%files # A pure JavaScript node module %{nodejs_sitelib}/foomodule/ # A native node module %{nodejs_sitearch}/barmodule/
Using this macro instead of hardcoding the directory in the specfile ensures your spec remains compatible with the installed Node.js version even if the directory structure changes radically (for instance, if %nodejs_sitelib
moves into %{_datadir}
).
Using tarballs from the npm registry
The canonical method for shipping most node modules is tarballs from the npm registry. The Source0
for such modules should be of the form http://registry.npmjs.org/<modulename>/-/<modulename>-<version>.tgz
. For instance:
Source0: http://registry.npmjs.org/npm/-/npm-1.1.70.tgz
This method should be preferred to using checkouts from git or automatically generated tarballs from GitHub.
These tarballs store the contents of the module inside a package
directory, so every package using these tarballs should use the following in %prep
:
%prep %setup -q -n package
Installing Modules
Most node modules do not contain their own install mechanism. Instead they rely on npm
to do it for them. npm
must not be used to install modules in Fedora packages, since it usually requires network access, always tries to bundle libraries, and installs files in a manner inconsistent with the Filesystem Hierarchy Standard (FHS).
Instead, install files in their proper place manually using install
or cp
. Most files should be installed in %{nodejs_sitelib}/<npm module name>
but documentation should be installed via
%doc
. In the event that the module ships arch independent content other than JavaScript code, that content should be installed in %{_datadir}
and the module should be patched to cope with that.
Client-side JavaScript
Many node modules contain JavaScript that can be used both client-side and server-side and it is sometimes hard to identify code intended only for use in the browser. Since there are no current packaging guidelines for client-side JavaScript and bundling of such code is currently permitted in Fedora, it is currently permissible for client-side JavaScript to be bundled with nodejs modules in %{nodejs_sitelib}
.
Automatic Requires and Provides
The nodejs package includes an automatic Requires and Provides generator that automatically adds versioned dependencies based on the information provided in a module's package.json file.
Provides
It also adds virtual provides in the form npm(<module name>)
to identify modules listed in the npm registry (the module is listed at npmjs.org) . If a module is not listed in the npm registry, it must not provide this. Modules that aren't listed in the npm registry should set private
to true
in their package.json
file. If not, you must patch package.json
to include that.
Correcting Dependencies
Occasionally the dependencies listed in package.json are inaccurate. For instance, the module may work with a newer version of a dependency than the one explictly listed in the package.json file. You can use a patch to fix this and then send the patch to upstream.
Symlinking Dependencies
Node.js and npm require that dependencies explicitly be included or linked into a node_modules directory inside the module directory. To make this easier, a %nodejs_symlink_deps
macro is provided and will automatically create a node_modules tree with symlinks for each dependency listed in package.json. This macro should be called in the %install
section of every Node.js module package.
Removing bundled modules
Some node modules contain copies of other libraries in their source tree. You must remove these in %prep
. Simply running rm -rf node_modules
is sufficient for most modules.
%nodejs_symlink_deps
outputs a warning when a node_modules directory already exists in the %buildroot
, and will fail if it cannot create a symlink because a directory for it already exists.
Building native modules with node-gyp
Most native modules use the node-gyp
tool to build themselves, which configures and uses the gyp
build framework to build addon modules that can interact with Node.js and the V8 JavaScript interpreter used by it.
The WAF build framework has been abandoned by upstream and is not supported in Fedora.
BuildRequires
To build a native module designed to be built with node-gyp, add BuildRequires: node-gyp
, along with BuildRequires: nodejs-devel
and -devel packages for any shared libraries needed by the module.
%build
Some native modules have Makefiles or other build processes that handle any special needs that module has, such as linking to system versions of dependencies. If present, these should be used. Check the module's package.json file for information about what command npm will run to build these modules.
Most modules use vanilla node-gyp, and may not have build instructions in package.json. To build these, simply use the following:
%build
export CXXFLAGS="%{optflags}"
node-gyp rebuild
Note that some modules may specify something like node-gyp configure && node-gyp build
. This is equivalent to node-gyp rebuild
.
%install
node-gyp
creates a shared object file conventionally named <module name>.node
as part of its build process, which should be located in build/Release
. This file may be used as the main entry point for the library, or is utilized by JavaScript wrapper code included with the module.
If the shared object is used as the main entry point, it should be installed at %{nodejs_sitelib}/<module name>/<module_name>.node
. The require()
function will automatically load this if there is no corresponding <module name>.js
or entry point defined in package.json to override it. For example:
%install
mkdir -p %{buildroot}%{nodejs_sitelib}/foomodule
cp -p build/Release/foomodule.node package.json %{buildroot}%{nodejs_sitelib}/foomodule/
If the shared object is called by JavaScript wrapper code, the situation is slightly more complicated.
If the module uses the npm bindings module, the shared object file should be installed in %{nodejs_sitelib}/<module name>/build/<module name>.node
, which is at the top of bindings' search path and where node-gyp
usually creates a symlink to wherever the real shared object file exists. For example:
%install
mkdir -p %{buildroot}%{nodejs_sitelib}/foomodule/build
cp -p package.json wrapper.js %{buildroot}%{nodejs_sitelib}/foomodule/
cp -p build/Release/foomodule.node %{buildroot}%{nodejs_sitelib}/foomodule/build/
If the module hardcodes build/Release/<module name>.node
, the module should be patched to use build/<module name>.node
instead, and upstream should be advised that they should use the bindings module, because their module could break when users use debug builds of node.
If the module uses it's own Makefiles to locate the shared object file(s) to a specific location, then those files should installed in that location.
Dealing with Bundled Libraries
Many native modules contain bundled copies of libraries already present in Fedora. You must build against the system version of these libraries. For more information, see Packaging:No Bundled Libraries.
The Fedora version of node-gyp
will handle the fact that shared versions of libuv, v8, and http_parser without modification to the module, since node-gyp
always unconditionally configures these libraries. However, some modules may rely on other libraries bundled with node, such as openssl or c-ares. These may need to be patched to use the system headers for these libraries.
Questions
- clarification (does not need vote) of the "[...]shared versions of libuv,[...]" line
- Node.js upstream bundles everything, and some native modules make some assumptions about the structure of headers and such based on that. Our
node-gyp
is patched so things "just work" 95% of the time, but some special attention might be required if modules try doing something fancy. I'll clarify the wording in the section a little bit.
- Thanks
- http://nodejs.org/api/addons.html <= Is this still static linking or has it been fixed?
- This is true with the standard upstream distribution, but not true in Fedora. Our
node-gyp
package ensures all necessary linker flags are set, so this isn't a problem though. I'll talk with upstream about clarifying that documentation, as it probably isn't true in e.g. Debian too.
- Thanks
- Do we really need a multilib exemption or would %{_libdir} for both module locations work?
- That would be tricky. npm only looks in %{_prefix}/lib/node_modules and would need to be patched to handle this. We probably couldn't ship it as noarch if we did this, correct?
- Correct. I think that some of the FPC members wanted the package to simply declare itself to be arch-specific and use %{_libdir} instead of %{_prefix}/lib . A little rationale for using %{_prefix}/lib would probably get the votes needed (assuming that a fesco exemption is also approved).
- Come to think of it, we'll have to ship every Node.js module arch-specfic if we did that, since the install destination would be different for all of them. I really don't think we want that.
- "The nodejs package includes an automatic Requires and Provides generator that automatically adds versioned dependencies based on the information provided in a module's package.json file." <= Should that be in nodejs-devel instead?
- That's what I thought, but when I set this up I checked repoquery/rpm all the dep generators I saw shipped in the main package. It'd be nice to have FPC guidance on the proper location.
- The *-devel package is usually what we use. sgallagh says that he can move them there.
- Would like a spec template
- Something like this? [1]
- Looks good to me.
RE: %nodejs fixdep
After some thought, I think it might be better to drop %nodejs_fixdep and provide a similar script that generates a patch instead. (I'll soon put together an RPM with some useful scripts for node packaging where it can live comfortably.) That way I can depend on a json library that respects the original structure so patches are upstreamable without bloating the nodejs package's deps.