7

I know that I can use the automatic variable $@ from within a target in a makefile to retrieve the name of the current target. Now I wonder whether it is possible to have a makefile that looks like this:...

$@:
    g++ $@ && ./a.out

The idea is that typing make test.cpp should run g++ test.cpp && ./a.out where as make main.cpp should run g++ main.cpp && ./a.out.

I see that wildcards might be strongly related to my problem. However, a makefile like this:

*.cpp:
    g++ $@ && ./a.out

does indeed create the appropriate targets, but running make test.cpp with such a makefile yields make: >>test.cpp<< is already up-to-date - without the compilation taking place.

Max Beikirch
  • 2,053
  • 5
  • 25
  • 36

2 Answers2

4

The behavior you described is the behavior you want from the make system and this is why it is so loved by many and scales so well.

make test.cpp does not work because what you want is make a.out

Try starting from a simple but correct makefile and evolve it to your needs

To trigger the compilation remove test.o and say make test.o, or say touch test.cpp and then again make test.o. If you do not want intermediate object files (I tell you - you do want them) you can apply the above advice replacing test.o with a.out.

You are trying to push where you should be pulling :-)

As @MadScientist reminded in his comment, one of useful features of GNU Make is a vast set of default rules which may save quite a bit of boilerplate when you don't need fine control of each step.

vog
  • 23,517
  • 11
  • 59
  • 75
bobah
  • 18,364
  • 2
  • 37
  • 70
  • To be fully complete this answer should point out that make has a set of built-in _implicit rules_ that lets it understand how to build a `.o` from a `.c` file, as well as various other types of source files. Further, you can define your own implicit rules or override the built-in ones if they don't do what you need. Standard make supports _suffix rules_ which are a limited form of implicit rule, and GNU make supports _pattern rules_ which are a more powerful form. You can look up these terms with Google to learn about them and how to specify them. – MadScientist Feb 05 '14 at 18:18
  • @MadScientist - I agree that automatic rules are useful to certain degree, but when building anything simpler than a test app you better have a full control – bobah Feb 05 '14 at 18:24
  • Using implicit rules in no way cedes any control over anything. And, in any build system simpler than a test app they are absolutely CRUCIAL to avoid lots of wasteful redundancy. Some people prefer static pattern rules, but I don't see any big advantage personally. – MadScientist Feb 05 '14 at 19:25
  • 1
    @MadScientist - I added a note on default rules, I have even found a sample makefile in one of my old projects (link in the answer). – bobah Feb 05 '14 at 19:34
  • Maybe when you said "automatic rules" you mean the default or built-in implicit rules, and not implicit rules in general? It's true that the built-in rules sometimes won't do what you want, which is why you can (and perhaps should) redefine them. However, they are nicely variable-ized so very often all you need to do is set `CC`, `CFLAGS`, `CXX`, `CXXFLAGS`, `CPPFLAGS`, etc. and everything will work quite well. – MadScientist Feb 05 '14 at 19:41
  • @MadScientist - have a look here http://bobah.net/d4d/source-code/misc/cpp-dependency-injection, precisely what you've just said – bobah Feb 05 '14 at 19:43
  • Thank you and sorry for the late response :) – Max Beikirch Feb 11 '14 at 21:05
3

I had a similar need when trying to make Go program. I solved my problem by setting the target to *.

In addition, you need to pass the .PHONY directive to filter out the files you want to process, otherwise something like make: 'clock1' is up to date, because my makefile already has clock1's folder in its directory.

GO_BUILD = go build
GO_BIN ?= $(shell go env GOPATH)/bin
PROG = $(GO_BIN)/$@

*:
    $(GO_BUILD) -o $(PROG) ./$@/*.go
    ls -al $(PROG)
test:
    @echo ${GO_BIN}

.PHONY: clock1 clock2 countdown*

RUN make command:

$ make clock1   
go build -o /data/go/bin/clock1 ./clock1/*.go
ls -al /data/go/bin/clock1
-rwxr-xr-x  1 Terry  staff  3013840 Sep 25 16:53 /data/go/bin/clock1

$ make clock2 
go build -o /data/go/bin/clock2 ./clock2/*.go
ls -al /data/go/bin/clock2
-rwxr-xr-x  1 Terry  staff  3177296 Sep 25 16:53 /data/go/bin/clock2

$ make countdown1
go build -o /data/go/bin/countdown1 ./countdown1/*.go
ls -al /data/go/bin/countdown1

lupguo
  • 1,525
  • 13
  • 13
  • its probably better to use `$*` over `$@` since `$*` will treat all args as a single string while `$@` will treat them as individual strings. – The Fool Apr 09 '22 at 21:29
  • @TheFool I don't see any use of `$*` in the makefile, just `*` as a target, and again as a shell wildcard in the recipe. – Peter Whittaker Jan 29 '23 at 16:06
  • @PeterWhittaker, there is multiple times $@ in the recipes. Which can have undesirable effects. – The Fool Jan 29 '23 at 16:15
  • @TheFool Apologies, you are correct, I read your comment backwards somehow. Since `$@` is used multiple times, once explicitly and twice via the reference to `PROG`, would you recommend something like `*: TGT=$@` on one line, above the current `*:` rule, then using `${TGT}` and `${GO_BIN}/${TGT}` in the current rule? My thinking is that TGT would be defined once, then referenced directly to avoid issues with potential reevaluations of `$@`. – Peter Whittaker Jan 30 '23 at 17:15