jurgen@cacilj.UUCP (Jurgen Heymann) (05/01/91)
It seems that string replacement doesn't work for "$$@"! I am trying to write make files for the following situation: - source files are in one directory - object files and targets are in a SUBdirectory of the sources (one subdir for each different machine we compile for). THe MAKEFILE is in this object directory. In a makefile I want to say that the object files depend on the source files in the parent dir. I write: $(SRCFILES:.c=.o) : ../$($@:.o=.sim) but that gives funny values for $$@ (try make -d) and "$$(@:.o=.sim)" doesn't work (syntax error from make). When I just write "$$@", I of course get the object file for $$@. What can I do? Thanks for any help. - Jurgen Heymann -- ---------------------------------------------------------------- Jurgen Heymann CACI Products jurgen@cacilj.cts.com 3344 N. Torrey Pines Ct La Jolla, CA 92037
martin@mwtech.UUCP (Martin Weitzel) (05/05/91)
In article <1499@cacilj.UUCP> jurgen@cacilj.UUCP (Jurgen Heymann) writes: >It seems that string replacement doesn't work for "$$@"! > >I am trying to write make files for the following situation: > > - source files are in one directory > - object files and targets are in a SUBdirectory of the sources > (one subdir for each different machine we compile for). > THe MAKEFILE is in this object directory. > >In a makefile I want to say that the object files depend on the source >files in the parent dir. I write: > >$(SRCFILES:.c=.o) : ../$($@:.o=.sim) > >but that gives funny values for $$@ (try make -d) and "$$(@:.o=.sim)" >doesn't work (syntax error from make). >When I just write "$$@", I of course get the object file for $$@. I stumbled over this too some time ago. I didn't have the time then to investigate this further, but this article made me curious again, and now I seem to have found an explanation together with a workaround. The source of all problems seems to be that macros in dependency lines may be expanded twice. (I got alarmed for that one day when read what someone wrote in a text about make, that "$$@" is `dynamically' expanded.) In the first phase after reading the whole Makefile, MAKE does macro expansion on dependency lines. During working from the leaves to the root of the dependency tree later, MAKE will do macro expansion a second time, on dependency lines as well as on command lines. Normally you will not notice much difference for the two possible occasions where macros in dependency lines get expanded, but you can verify what I wrote by trying the following Makefile: mac = foo bar: $(mac) @echo "$?" If file `foo' is newer than `bar', the echo will be excuted, otherwise MAKE tells you that `bar' is up to date. Now change the dependency line: mac = foo # vv---------- note THIS! bar: $$(mac) @echo "$?" The result is the same. BINGO! Not only the $$ gets expanded to $, later `$(mac)' is recognized and gets expanded to `foo'. Now let's change the example again: mac = foo foo2 bar: $(mac) @echo "$?" This will work as expected (provided some file `foo2' exists and is newer than `bar', it will be included in the message printed by echo; if `foo2' doesn't exist MAKE complains that it doesn't know how to make `foo2'). mac = foo foo2 # vv----------- again: "late expansion" bar: $$(mac) @echo "$?" In this example MAKE will complain that it doesn't know how to make `foo foo2', i.e. it looks for a file with a blank in its name. This clearly shows that the two passes of macro expansion are in fact done differently! So we have found the truth why we must write `$$@' if we want the "current target" in dependency lines, but name the same thing as `$@' in command lines: We simply must suppress the expansion during the first pass! `$$' gets expanded to `$' and what is stored in the dependency tree is `$@', the same thing that is used in command lines (for which obviously only one pass of macro expansion is done!) Now let's turn back to the original question: $(SRCFILES:.c=.o) : ../$($@:.o=.sim) With the assumption that SRCFILES is initialized with `foo.c' and `bar.c', further experiments show that the above expands to: foo.o : ../ bar.o : ../ (If the files foo.c and bar.c exist, MAKE further appends them to the dependencies because of the suffix rule ".c.o:". This doesn't matter too much here, I just write it so that you don't get confused if you try to experiment with some simple Makefiles to verify what I've written.) How comes this expansion: Because MAKE expands the contents of a macro with the name `$@'. Be careful with what I wrote here. Normally if you speak about macros you need not to try to avoid confusion between the name of a macro and the demand for expansion of this macro. Let's take a simple example: If `SRCFILES' is the name of a macro, `$(SRCFILES)' is the demand to expand this macro. Now, what do I demand from MAKE if I write $($@) ? The expansion of a macro with name `$@' which is quite different from the builtin macro `@', for which I demand expansion with `$@' !! Now add suffix replacement to the above and you'll see the light ... at least I saw it when I was this far :-) Back to the problem. (The next line contains a formfeed and makes your news reader propably stop at this point. One reason for this formfeed is to to make you more curious for the solution which will follow soon. Another, more trivial reason will be obvious as soon as you display the next page.) What do we want *after* the first pass of macro expansion? Obviously: foo.o : ../$(@:.o=.sim) <--+ bar.o : ../$(@:.o=.sim) <--+-----------------------+ | This would lead us directly to: | | $(SRCFILES:.c=.o) : ../$$(@:.o=.sim) | | as our specification in the Makefile. But as the original poster noticed, | this leaves us with an syntax error. (As I don't have the sources of MAKE | I'm not sure what makes MAKE stumble, but I strongly assume that it is the | colon as you can have dependency lines that read `a : b c (x)' but non | that read `a : b c:x', i.e. it is not possible to embedd a colon in a | components name on a dependency line. | | As I promised above, the intention of this article is not only to bore | you with details about how and why things don't work as expected - I also | have a workaround. Again have a look at the line we want to have *after* | the first expansion step. -------------------------------------------------+ (If you guess now that this arrow is the reason for the formfeed above, you're absolutely right :-)) How can we write this in the original Makefile, if we cannot write a colon in a dependency line? The trick that works (at least on ISC UNIX) is to hide the colon in a macro definition. I tried several solutions and came finally up with: o_sim = $(@:.o=.sim) $(SRCFILES:.c=.o) : ../$$(o_sim) During building the dependency tree, this (only) expands to: foo.o : ../$(o_sim) bar.o : ../$(o_sim) Later, when dependencies are checked, macros are further expanded with the final result of: foo.o : ../foo.sim bar.o : ../bar.sim Also the following works as desired: simfiles = ../$(@:.o=.sim) $(SRCFILES:.c=.o) : $$(simfiles) But in any case be sure to double the `$' in the dependency line. Otherwise macro substitution will allready recurse during the first phase, since MAKE detects that expansion of one macro yields in another macro. The important difference in the above workaround is that MAKE obviously does *not* detect that the concatenation of some expanded macro ($$ -> $) with a fixed string ((o_sim)) results into a construct that again looks like an expandable macro. (In aother words: MAKE only looks for the expansion buffer not for the context, if it has to decide about recursive macro expansion.) As the earlier experiments show, we can be quite lucky with this behaviour since MAKE recognizes and expands the macro later during checking the dependencies. This expansion ($(o_sim) -> $(@:.c=.sim)) results in what we need, and as this time the new text fully appears in the expansion buffer, MAKE recurses with macro expansion and gives us either `foo.sim' or `bar.sim', depending on the current target. OK for now, it's a rather long article again, but I think by showing the way how to come to the solution, the readership has gained a little more insight and understanding for some peculiarities of MAKE. (For me too it was quite instructive figuring all this out.) -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83