19

I'm writing binding.gyp file for my new node.js module. I have all my source files under src/ subdirectory. I would like to use all of them while building the module. Instead of modifying binding.gyp each time I add a new cpp file, I would like to list all cpp files through some wildcard mechanism. Does node-gyp support that? Something like following (which doesn't work

{
  'targets' : [
      {
          'target_name' : 'mymod',
          'sources' : 'src/*.cpp'
      }
   ]
}

I looked at https://code.google.com/p/gyp/wiki/InputFormatReference , but didn't find anything readily useful.

Jayesh
  • 51,787
  • 22
  • 76
  • 99

5 Answers5

31

Figured it out

{
  'targets' : [
      {
          'target_name' : 'mymod',
          'sources' : [ '<!@(ls -1 src/*.cpp)' ],
      }
   ]
}

Check out this link

Update

The solution above is not portable across platforms. Here's a portable version:

{
  'targets' : [
      {
          'target_name' : 'mymod',
          'sources' : [  "<!@(node -p \"require('fs').readdirSync('./src').map(f=>'src/'+f).join(' ')\")" ],
      }
   ]
}

Essentially it replaces the platform specific directory listing command (ls), by Javascript code that uses node's fs module to list the directory contents.

Jayesh
  • 51,787
  • 22
  • 76
  • 99
0

An even more portable version (that doesn't depend on node, but rather python):

"<!@(python -c \"import os; print '\n'.join(['%s' % x for x in os.listdir('.') if x[-3:] == '.cc' and 'test' not in x])\")"
Erik
  • 87
  • 3
0

To filter specific file extensions like cpp and to support also pre-compiled libraries .a files, I have slightly modified the accepted solution to be:

'sources': [
        'jamspell.cpp',
        "<!@(node -p \"require('fs').readdirSync('./src').filter(f=>f.endsWith('.cpp')).map(f=>'src/'+f).join(' ')\")",
        "<!@(node -p \"require('fs').readdirSync('./src/jamspell').filter(f=>f.endsWith('.cpp')).map(f=>'src/jamspell/'+f).join(' ')\")"
        ],
        'include_dirs': [
            "<!@(node -p \"require('node-addon-api').include\")"
        ],
        'libraries': [
          "<!@(node -p \"require('fs').readdirSync('./lib/contrib').filter(f=>f.endsWith('.a')).map(f=>'lib/contrib/'+f).join(' ')\")"
        ],
        'dependencies': [
            "<!(node -p \"require('node-addon-api').gyp\")"
        ],
loretoparisi
  • 15,724
  • 11
  • 102
  • 146
0

If anyone wants to include all sub files and folders within a certain folder (defined at end of line, here as "sources"):

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ 
            "<!@(node -p \"var fs=require('fs'),path=require('path'),walk=function(r){let t,e=[],n=null;try{t=fs.readdirSync(r)}catch(r){n=r.toString()}if(n)return n;var a=0;return function n(){var i=t[a++];if(!i)return e;let u=path.resolve(r,i);i=r+'/'+i;let c=fs.statSync(u);if(c&&c.isDirectory()){let r=walk(i);return e=e.concat(r),n()}return e.push(i),n()}()};walk('./sources').join(' ');\")"
        ]
    }
  ]
}

(based off, but not exactly: node.js fs.readdir recursive directory search)

0

Recursive script for windows, might work for linux/macos too.

"sources": [
  "<!@(node sources.js)"
],

sources.js

const { resolve, relative } = require('path');
const { readdir } = require('fs').promises;

async function getFiles(dir) {
  const dirents = await readdir(dir, { withFileTypes: true });
  const files = await Promise.all(
    dirents.map(dirent => {
      const res = resolve(dir, dirent.name);
      return dirent.isDirectory() ? getFiles(res) : res;
    }),
  );
  return Array.prototype.concat(...files);
}

(async () => {
  const files = (await getFiles(resolve(__dirname)))
    .filter(
      v =>
        v.endsWith('.cpp') ||
        v.endsWith('.h') ||
        v.endsWith('.hpp') ||
        v.endsWith('.cc') ||
        v.endsWith('.c'),
    )
    .map(v => relative(__dirname, v))
    .map(v => v.replace(/\\/g, '/')) // remove on mac/linux
    .join(' ');
  console.log(files);
  return files;
})();
nikitakot
  • 75
  • 6