3

I'm using node-gyp to build a native Node.js add-on written in C++ on Linux.

The add-on is dependent on another shared library. This library is not currently built with gyp, it just has a makefile.

If I build the shared library first, then build my add-on specifying a value for 'libraries' in the main target in my binding.gyp file, everything works fine.

However, what I would like to do is build the shared library from source from within the node-gyp process, by invoking make on the shared library's makefile. I tried adding a dependent target using the 'action' property to the add-on's binding.gyp and making the main target dependent on it:

    {
        "target_name": "other_library",
        "type": "none",
        "actions": [
            {
                "action_name": "build_other_library",
                "inputs": [],
                "outputs": [ "/path/to/build/output/libother.so" ],
                "action": [ "make", "-C", "/path/to/makefile" ]
            }
        ]
    }

This doesn't completely work. It is finding the other makefile and make is being launched (I can see this happening with --verbose set), but the makefile is not executing properly.

It seems that GNU make's implicit build rules are being suppressed when the makefile for the shared library runs. This means that .cc and .cpp files are not being compiled to .o files.

I realise that node-gyp is itself generating a set of makefiles for the add-on from the targets in the binding.gyp, and the the shared library's makefile is being spawned from one of these.

Is it inheriting the make settings from node-gyp, including the suppression of built-in rules?

Is there a way around it? (Other than adding explicit build rules to the shared library's makefile)?

(I've tried replacing make with $(MAKE), it made no difference).

EDIT:

Running GNU make on the shared library with -d specified from the shell (i.e. outside node-gyp), the search for an implicit rule for a typical source file looks like this:

   Considering target file `code.o'.
     File `code.o' does not exist.
     Looking for an implicit rule for `code.o'.
     Trying pattern rule with stem `code'.
     Trying implicit prerequisite `code.c'.
     Trying pattern rule with stem `code'.
     Trying implicit prerequisite `code.cc'.
     Trying pattern rule with stem `code'.
     Trying implicit prerequisite `code.C'.
     Trying pattern rule with stem `code'.
     Trying implicit prerequisite `code.cpp'.
     Found prerequisite `code.cpp' as VPATH `../Common/code.cpp'
     Found an implicit rule for `code.o'.

Adding -d to the invocation from within the action block in the node-gyp dependent target, the same source file gets this:

Considering target file `code.o'.
 File `code.o' does not exist.
 Looking for an implicit rule for `code.o'.
 No implicit rule found for `code.o'.

So it does look like implicit build rules are being suppressed (?)

dtopham75
  • 540
  • 5
  • 14

1 Answers1

1

node-gyp sets MAKEFLAGS=-r in its toplevel makefile. -r is the short form of --no-builtin-rules, and by default this is passed down to any sub-makes.

However, you'll be able to re-enable builtin-rules for your sub-make by setting MAKEFLAGS back to their default state in the calling environment.

Without changing your binding action, you can achieve this by prememptively exporting rectified MAKEFLAGS in your makefile, and then reinvoking $(MAKE).

To illustrate, pretend this is your original makefile:

all: foo

foo: foo.o
    $(CC) -o $@ $<

in which you're making a program foo from one source file foo.c (assumed to exist in the working directory) and counting on the builtin rule for %o: %c to compile foo.o from foo.c. So with this makefile the build will fail:

*** No rule to make target 'foo.o', needed by 'foo'. Stop.

Change the makefile like so:

ifneq ($(MAKEFLAGS),w)
all:
    export MAKEFLAGS=-w && $(MAKE)
else
all: foo

foo: foo.o
    $(CC) -o $@ $<

endif

Now the make will recurse if -r is in the MAKEFLAGS and run with MAKEFLAGS=-w instead:

$ node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.0.3
gyp info using node@4.2.6 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/imk/develop/scrap/build'
  ACTION binding_gyp_prog_target_build_foo foo
make[1]: Entering directory '/home/imk/develop/scrap'
export MAKEFLAGS=-w && make
make[2]: Entering directory '/home/imk/develop/scrap'
cc    -c -o foo.o foo.c
cc -o foo foo.o
make[2]: Leaving directory '/home/imk/develop/scrap'
make[1]: Leaving directory '/home/imk/develop/scrap'
  TOUCH Release/obj.target/prog.stamp
make: Leaving directory '/home/imk/develop/scrap/build'
gyp info ok 

The -w (short for --print-directory) is the one default option that was operative before node-gyp added -r.

Note that the test ifneq ($(MAKEFLAGS),w) is correct. It is not supposed to be ifneq ($(MAKEFLAGS),-w). If the environment variable MAKEFLAGS contains a make commandline option then the GNU Make special variable MAKEFLAGS will contain only the option character.

Mike Kinghan
  • 46,463
  • 8
  • 124
  • 156
  • I see what you are getting at, and purely from a make perspective it makes sense. – dtopham75 Jun 22 '16 at 21:53
  • I see what you're getting at, and from a make perspective it makes sense. However, it doesn't work. The problem seems to be the way that node-gyp (or just gyp) concatenates the 'action' array together. It doesn't like elements containing the = sign. This: '"action": [ "make", "-C", "/path/to/makefile" ]' gets expanded to ''make -C /path/to/makefile' in the generated makefile for the target. But '"action": [ "export MAKEFLAGS=-w && make -C", "/path/to/makefile"']' goes to '"export MAKEFLAGS=-w && make -C" /path/to/makefile', with the quotes intact. Same for anything containing an =. – dtopham75 Jun 22 '16 at 22:07
  • @dtopham75 I should have taken the trouble to give you a tested solution. Here's one now ^ – Mike Kinghan Jun 23 '16 at 19:42
  • Accepted as the answer, although I actually resolved it by explicitly adding the default rules to the makefile. I've asked another question about the issues with certain characters causing problems in gyp action targets. – dtopham75 Jun 28 '16 at 15:42