8

GNU Make has -B option that forces make to ignore existing targets. It allows to rebuild a target, but it also rebuilds all the dependency tree of the target. I wonder is there a way to force rebuilding a target without rebuilding its dependencies (using GNU Make options, settings in Makefile, compatible make-like software, etc.)?

Illustration of the problem:

$ mkdir test; cd test
$ unexpand -t4 >Makefile <<EOF
huge:
    @echo "rebuilding huge"; date >huge
small: huge
    @echo "rebuilding small"; sh -c 'cat huge; date' >small
EOF
$ make small
rebuilding huge
rebuilding small
$ ls
huge  Makefile  small
$ make small
make: 'small' is up to date.
$ make -B small
rebuilding huge  # how to get rid of this line?
rebuilding small
$ make --version | head -n3
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.

Of course one can rm small; make small, but is there a built-in way?

Kirill Bulygin
  • 3,658
  • 1
  • 17
  • 23
  • Does [this question](http://stackoverflow.com/questions/12199237/telling-make-to-ignore-dependencies-when-the-top-target-has-been-created) help you out? – super schaap Feb 09 '17 at 15:04
  • Thanks, but not much: as I showed using `ls`, `huge` is preserved here (without `.SECONDARY:` target) and the rebuilding is rather due to `-B`. – Kirill Bulygin Feb 09 '17 at 15:39

5 Answers5

6

One way is to use the -o option for all targets you don't want to be remade:

-o FILE, --old-file=FILE, --assume-old=FILE
        Consider FILE to be very old and don't remake it.

EDIT

I think you're misreading the documentation for -B; it says:

  -B, --always-make
        Unconditionally make all targets.

Note, the all targets here; huge is certainly a target, and so if you use -B it will be remade.

However, I also misread your question a bit. I thought you wanted to rebuild small without rebuilding huge even though huge is new, but you're trying to get small to be rebuilt even though huge has not changed, right?

You definitely don't want to use -B. That option is not at all what you are looking for.

Normally people would do that by deleting small:

rm -f small
make small

It might be useful to have an option that forced a given target to be recreated, but that option doesn't exist.

You could use -W huge, but again this means you need to know the name of the prerequisite not just the target you want built.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thanks, `make -B -o huge small` really works, but it's not ideal unless such dependencies can be obtained automatically... – Kirill Bulygin Feb 10 '17 at 06:50
  • I agree that it's not ideal, but you did ask for any method :) – MadScientist Feb 10 '17 at 13:24
  • Yes, that's why I upvoted (but not ready to mark the answer as accepted). Actually, if the option did what it says itself (consider the target as very old and so force it alone to be remade instead of ignoring as very new), the answer would be ideal. – Kirill Bulygin Feb 10 '17 at 13:46
  • Only today did I see your update. I don't think that I or you misread something: I didn't claim that `-B` itself should behave differently, and you made a good suggestion after all. – Kirill Bulygin Jun 26 '18 at 16:24
4

File under rather nasty hack:

huge:
    @echo "rebuilding huge"; date >huge

small: $(if $(filter just,${MAKECMDGOALS}),huge)
    @echo "rebuilding small"; sh -c 'cat huge; date' >small

.PHONY: just
just: ;

Now you can

$ make -B just small
bobbogo
  • 14,989
  • 3
  • 48
  • 57
3

Will this help:

touch huge; make small

?

Alexey Semenyuk
  • 674
  • 4
  • 9
  • Thanks, it works (and so does `make -W huge small`), but it's not ideal unless such dependencies can be obtained automatically... – Kirill Bulygin Feb 10 '17 at 06:51
0

Well, so far I'm using this partial solution:

$ cat >~/bin/remake <<'EOF'
#!/bin/sh
# http://stackoverflow.com/questions/42139227
for f in "$@"; do
  if [ -f "$f" ]; then
    # Make the file very old; it's safer than removing.
    touch --date=@0 "$f" 
  fi
done
make "$@"
EOF
$ chmod u+x ~/bin/remake
$ # PATH="$HOME/bin:$PATH" in .bashrc
$ remake --debug=b small
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Updating goal targets....
 Prerequisite 'huge' is newer than target 'small'.
Must remake target 'small'.
rebuilding small
Kirill Bulygin
  • 3,658
  • 1
  • 17
  • 23
0

I use something like this:

remake()
{
  for f in "$@"
  do
    [ -f "$f" ] && rm -f "$f"
  done
  make "$@"
}
reinierpost
  • 8,425
  • 1
  • 38
  • 70