bindings.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /**
  2. * Module dependencies.
  3. */
  4. var fs = require('fs')
  5. , path = require('path')
  6. , join = path.join
  7. , dirname = path.dirname
  8. , exists = fs.existsSync || path.existsSync
  9. , defaults = {
  10. arrow: process.env.NODE_BINDINGS_ARROW || ' → '
  11. , compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled'
  12. , platform: process.platform
  13. , arch: process.arch
  14. , version: process.versions.node
  15. , bindings: 'bindings.node'
  16. , try: [
  17. // node-gyp's linked version in the "build" dir
  18. [ 'module_root', 'build', 'bindings' ]
  19. // node-waf and gyp_addon (a.k.a node-gyp)
  20. , [ 'module_root', 'build', 'Debug', 'bindings' ]
  21. , [ 'module_root', 'build', 'Release', 'bindings' ]
  22. // Debug files, for development (legacy behavior, remove for node v0.9)
  23. , [ 'module_root', 'out', 'Debug', 'bindings' ]
  24. , [ 'module_root', 'Debug', 'bindings' ]
  25. // Release files, but manually compiled (legacy behavior, remove for node v0.9)
  26. , [ 'module_root', 'out', 'Release', 'bindings' ]
  27. , [ 'module_root', 'Release', 'bindings' ]
  28. // Legacy from node-waf, node <= 0.4.x
  29. , [ 'module_root', 'build', 'default', 'bindings' ]
  30. // Production "Release" buildtype binary (meh...)
  31. , [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ]
  32. ]
  33. }
  34. /**
  35. * The main `bindings()` function loads the compiled bindings for a given module.
  36. * It uses V8's Error API to determine the parent filename that this function is
  37. * being invoked from, which is then used to find the root directory.
  38. */
  39. function bindings (opts) {
  40. // Argument surgery
  41. if (typeof opts == 'string') {
  42. opts = { bindings: opts }
  43. } else if (!opts) {
  44. opts = {}
  45. }
  46. opts.__proto__ = defaults
  47. // Get the module root
  48. if (!opts.module_root) {
  49. opts.module_root = exports.getRoot(exports.getFileName())
  50. }
  51. // Ensure the given bindings name ends with .node
  52. if (path.extname(opts.bindings) != '.node') {
  53. opts.bindings += '.node'
  54. }
  55. var tries = []
  56. , i = 0
  57. , l = opts.try.length
  58. , n
  59. for (; i<l; i++) {
  60. n = join.apply(null, opts.try[i].map(function (p) {
  61. return opts[p] || p
  62. }))
  63. tries.push(n)
  64. try {
  65. var b = require(n)
  66. b.path = n
  67. return b
  68. } catch (e) {
  69. if (!/not find/i.test(e.message)) {
  70. throw e
  71. }
  72. }
  73. }
  74. var err = new Error('Could not load the bindings file. Tried:\n'
  75. + tries.map(function (a) { return opts.arrow + a }).join('\n'))
  76. err.tries = tries
  77. throw err
  78. }
  79. module.exports = exports = bindings
  80. /**
  81. * Gets the filename of the JavaScript file that invokes this function.
  82. * Used to help find the root directory of a module.
  83. */
  84. exports.getFileName = function getFileName () {
  85. var origPST = Error.prepareStackTrace
  86. , dummy = {}
  87. , fileName
  88. Error.prepareStackTrace = function (e, st) {
  89. for (var i=0, l=st.length; i<l; i++) {
  90. fileName = st[i].getFileName()
  91. if (fileName !== __filename) {
  92. return
  93. }
  94. }
  95. }
  96. // run the 'prepareStackTrace' function above
  97. Error.captureStackTrace(dummy)
  98. dummy.stack
  99. // cleanup
  100. Error.prepareStackTrace = origPST
  101. return fileName
  102. }
  103. /**
  104. * Gets the root directory of a module, given an arbitrary filename
  105. * somewhere in the module tree. The "root directory" is the directory
  106. * containing the `package.json` file.
  107. *
  108. * In: /home/nate/node-native-module/lib/index.js
  109. * Out: /home/nate/node-native-module
  110. */
  111. exports.getRoot = function getRoot (file) {
  112. var dir = dirname(file)
  113. , prev
  114. while (true) {
  115. if (dir === '.') {
  116. // Avoids an infinite loop in rare cases, like the REPL
  117. dir = process.cwd()
  118. }
  119. if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {
  120. // Found the 'package.json' file or 'node_modules' dir; we're done
  121. return dir
  122. }
  123. if (prev === dir) {
  124. // Got to the top
  125. throw new Error('Could not find module root given file: "' + file
  126. + '". Do you have a `package.json` file? ')
  127. }
  128. // Try the parent dir next
  129. prev = dir
  130. dir = join(dir, '..')
  131. }
  132. }