27

I work with a Makefile generated by an external tool (Netbeans), where I can not change the logic of the main target, but I am able to "inject" logic in a target that is executed before the actual build (.build-pre to be specific in Netbeans-generated Makefile)

I would like for that target to conditionally terminate the make execution, but without raising an error. If I do

exit

inside the "pre" rule, nothing happens (I mean, the rule terminates, but make continues). If I add

exit 1

make will terminate, but it will return an error status.

Is there a way to force make to exit in a clean way? I searched for make functions, but found only error/warn/info, but nothing like exit.

Thanks in advance!

EDIT: Based on comments it does not seem possible. Pity.

For completeness, a more specific example of what I'd like to achieve:

default: pre
  @echo "Doing default"

pre: 
  @echo "Doing pre"
ifeq "$(SOME_VARIABLE)" "yes"
  exit 0
fi

With Makefile like above, I'd like to be able for pre to execute, and conditionally prevent 'default' from executing, but still return 0 to the shell.

Marcin Zukowski
  • 4,281
  • 1
  • 19
  • 28
  • Like I said - I want to force exiting "make" without raising an error. I don't want to have Netbeans-generated rules continue in some cases. – Marcin Zukowski Nov 04 '13 at 17:48
  • 1
    There is no way to do that. If you say `make foo` then make will try to make `foo`, and the only way it will stop making `foo` is if it sees an error. You can't ask it to give up without making `foo` and without generating an error. If this is some way not an accurate description of what you're trying to achieve please make your question more specific. – MadScientist Nov 04 '13 at 17:55
  • Thanks @MadScientist. I actually suspected it might be impossible, but if you don't ask, you don't learn, right? :) Thanks! – Marcin Zukowski Nov 04 '13 at 18:03
  • 1
    @Marcin: I read you, but you are repeating strange technical steps you want. You still haven't stated your real problem – which probably has a completely different solution. – Daniel Nov 04 '13 at 18:08
  • @Daniel OK, to be more specific. I use Netbeans-generated Makefiles, integrated with IDE. However, I also sometimes have ability to do faster compilation than with Netbeans-generated Makefiles (using unity builds), so I want to prevent the actual Netbeans-generated compilation logic from executing. I know I could do it if I switched to manually- or automake- generated Makefiles, but if what I described worked, I could just put my logic in "pre", and then exit. I know it's all a bit obscure, and it was a long shot. Thanks for all the help. – Marcin Zukowski Nov 04 '13 at 18:13
  • There might still be a way, but almost by definition it would be by some horrible black magic. For instance, you could redefine variables so that the first command in the default recipe would expand to `exit;...`, or have the `pre` rule call a rule to temporarily rebuild the makefile itself with a default do-nothing rule. In short, you should talk to the person who imposed this protocol and explain the advantage of unity builds, or else accept the slow compilation and keep some crossword puzzles on hand. – Beta Nov 04 '13 at 18:37
  • I don't know how oversimplified your example is, but in this case it would be as easy as calling `make pre`. This doesn't even require modifying the makefile, but you could, if pre were in fact a long list of targets. – Daniel Nov 04 '13 at 19:18
  • @Daniel Of course, it was a simplification. Problem is that how make is called is managed by Netbeans in this case, and also that the exit is only conditional on some external factors. Thanks everyone! – Marcin Zukowski Nov 04 '13 at 19:43
  • DIFFERENT USE CASE: verifying a server state that does not have a filesystem manifestation - e.g. 'database up' or 'stop the database'. I have a target 'is the database up?' and when I'm trying to stop the database, I can check this by running $(MAKE) isDatabaseUp. If it returns false, I don't need to anything else in the target. I don't really want to (re-) run the shutdown sequence needlessly in this configuration. – Andrew Wolfe Feb 02 '16 at 17:16

4 Answers4

25

You can have the all target do nothing if a variable is not set:

ifeq ($(SOME_VAR),)
$(info SOME_VAR not set!)
all:
else
all: target1 target2 targetetc
endif
Ken
  • 251
  • 3
  • 3
  • 2
    There are 3 possible functions - `info`, `warning` and `error`. For more information visit [make's documentation about control function](https://www.gnu.org/software/make/manual/html_node/Make-Control-Functions.html) – Lirt Feb 15 '21 at 23:33
4

Just expanding a bit on @Ken's excellent response. You can also do this:

ifeq ("test", "test")
postinstall:
    @echo "test = test"
else
postinstall:
    @echo "test != test"
endif
Matt
  • 22,224
  • 25
  • 80
  • 116
3

What you are seeing happens because each line in a recipe runs in its own shell.

You can use .ONESHELL, so that all commands run in the same shell. That way, "exit" works:

.ONESHELL:

sayhi:
    @echo Hi
    exit
    @echo "I won't be printed"
adelfino
  • 45
  • 7
  • wow how is it I never ran into `ONESHELL` before.. btw the "Bye" should not be printed ..? – WestCoastProjects Apr 30 '22 at 16:39
  • @WestCoastProjects exactly, Bye won't be printed in this example – adelfino May 01 '22 at 14:58
  • 2
    You might change that to say "I won't be printed" rather than "Bye" . I tried `ONESHELL` and it did not work even after some fiddling. I'm not saying it *can not* work , but it's not simple in any case – WestCoastProjects May 01 '22 at 15:48
  • @WestCoastProjects want to share what you tried and didn't work? – adelfino May 01 '22 at 19:19
  • I dropped in a snippet of bash code and after about 30 minutes of tinkering it still was not happy. I do not remember the details. My position on this is - it does not just "drop in " to a `make` target - so I put it into a script instead. – WestCoastProjects May 01 '22 at 19:39
0

Instead of exit 0 try $(eval $(exit 0))

ds-bos-msk
  • 780
  • 9
  • 13