ThomasReggi
ThomasReggi

Reputation: 59345

Specify makefile command target

Here's my Makefile

gitignore-create:
    touch .gitignore ;\
    echo 'node_modules' >> .gitignore ;\
    echo 'npm' >> .gitignore ;\
    echo '.DS_Store' >> .gitignore ;\

If I run make gitignore-create I get the gitignore file the current directory.

I'm looking for a way to run this makefile command from the same directory but have the target be specified to another. I'd like to not add a cd into the command itself though.

I tried something like this:

# make wrap package=my-package command=gitignore-create
wrap:
    pushd packages/$(package)/ && make -C ${CURDIR} $(command) && popd

And it only creates the file in the actual current dir.

Upvotes: 0

Views: 425

Answers (1)

MadScientist
MadScientist

Reputation: 100781

There's lots wrong with this:

wrap:
        pushd packages/$(package)/ && make -C ${CURDIR} $(command) && popd

The very first thing is you should never use the static command make when invoking recursive make rules. Always use the variable $(MAKE) (or if you prefer, ${MAKE}: they're identical).

Second, you can't use pushd and popd (at least not portably) because those are bash commands, but make always runs /bin/sh as its shell (unless you change it by setting the SHELL makefile variable) and on many systems, /bin/sh is not bash.

Third, you don't need to do that anyway because in UNIX/Linux, as with all right-thinking operating systems, the current directory is a property of the current process (part of its environment) and changing the current directory doesn't change the parent process's current directory. And, every recipe line in a makefile is a whole new process (that runs a shell). So you can use cd directly in any recipe line and as soon as that recipe line finishes and the shell exits, all the changes to the environment, including the current directory, will be gone: you don't have to explicitly undo them.

So you can write the rule above equivalently as:

wrap:
        cd packages/$(package)/ && $(MAKE) -C ${CURDIR} $(command)

However, ultimately this doesn't do anything because the -C option when given to make causes make to change it's working directory to the value you provided. So this recipe says, "first change directories to packages/$(package), then run make and tell it that the first thing it should do before it starts any commands is to change directories back to the original directory". Clearly this is identical to just running make without changing directories at all.

Your explanation is not completely clear but what I think you want to do is something like this:

# this variable assignment must come before any include statements
myMakefile := $(abspath $(lastword $(MAKEFILE_LIST)))
  ...
wrap:
        cd packages/$(package)/ && $(MAKE) -f $(myMakefile) $(command)

which first remembers the path to the current makefile, then creates a recipe which changes directory into packages/$(package) then runs make giving it the current makefile to parse (but not changing directories, don't use -C!) and the command to run.

Upvotes: 2

Related Questions