25

NOTICE: Escaping not problem, sample from shell is only sample, in Makefile $$.

GNU Makefile man says why it's doesn't work:

Note that expansion using ‘%’ in pattern rules occurs after any variable or function expansions, which take place when the makefile is read.

--Orig. question:
In pure shell, the next script works correctly:

echo "test2.cpp src2/test2.cpp src1/test1.cpp src1/test.cpp" | \
awk 'BEGIN{RS=" "}{if(NR == 1) f=$0; else if(match($0, f)) print $0;}'

Filter is first: test1.cpp
And it returns: src1/test1.cpp

But in Makefile it does not work correctly (error compared to awk):

OBJ_DIR:=obj    
SOURCES:=$(wildcard */*.cpp *.cpp)
OBJECTS_LOCAL:= $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:.cpp=.o)))
LOCAL_PATHS_HEADERS:=$(sort $(dir $(wildcard *.h */*.h)))

TARGET:=libcommon.a

all:$(TARGET)

$(TARGET): $(OBJECTS_LOCAL)
        ar -rcs $@ $^

$(OBJECTS_LOCAL): $(OBJ_DIR)/%.o : $(shell echo %.cpp $(SOURCES) | awk 'BEGIN{RS=" "}{if(NR == 1) f=$$0; else if($$0 ~ f) print $$0;}' )
        @mkdir -p $(OBJ_DIR)
        @$(CC) -c $< -o $@ $(addprefix -I,$(LOCAL_PATHS_HEADERS))

So I take simple in Makefile and check value f, and found some strange length of f

...%.cpp $(SOURCES)  | awk '{print ("file1.cpp" ~ $$1)"."$$1"."length($$1)}' )

awk return fail in compared; print returns "0.file1.cpp.5" to fail with length, because it has forgotten .cppvalue of %, info bellow. I attempted to correct it:

...%.cpp $(SOURCES) | awk 'BEGIN{RS=" "}{if(NR == 1) f=$$0".cpp"; print ("file1.cpp.cpp" ~ f)"."("file1.cpp" ~ f)"."f"."length(f)}' )

but awk return fail in all compared; print returns "0.0.file1.cpp.cpp.9".

I check awk in manual mode, like this:

...%.cpp $(SOURCES) : $(shell echo %.cpp $(SOURCES) | awk '{print "src/"$$1}' )

It works fine, but it isn't variant, because it will kill automatic mode.

--Add
Information about lost length from parameter % to AWK

...%.cppppppp $(SOURCES) | awk '{print ("file1.cpp" ~ $$1)"."$$1"."length($$1)}' )

print returns "0.test2.cppppppp.10"

--Upd, some problem
Above, I was printing return value from $<
But file redirect show that value % does not work in prerequisites(file redirect: "0.%.cpp.5").

Can I use any automatic variable with value in prerequisites?

Anton Riab
  • 488
  • 1
  • 4
  • 9

1 Answers1

84

Almost invariably, when a question is asked about awk in a Makefile, the solution is to properly escape the $ symbols. It's not entirely clear what your question is, but there are some substantial misunderstandings that need to be resolved. In particular, the following "works", but hardly for the reasons you think:

echo "test2.cpp src2/test2.cpp src1/test1.cpp src1/test.cpp" | \
awk 'BEGIN{RS=" "}{if(NR == 1) f=$$0; else if(match($$0, f)) print $$0;}'

You almost certainly do not want $$ in any of the cases they appear here. awk is generally looking for single dollar signs, and when they appear in a Makefile, they are doubled because Make parses the $$ and invokes awk with a single $. In the quoted sample, $$0 on the first record is equivalent to $test2.cpp, but the variable test2.cpp is uninitialized and so has value 0, so on the first pass f is set to the value of $0 (the string "test2.cpp").

In short, if you are invoking awk from the shell, use single $. In the Makefile, use $$ and awk will only see $.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Thanks. I corrected this in my question, but awk does not work correctly in Makefile with $$ – Anton Riab May 26 '15 at 03:33
  • On first glance, the awk in the Makefile looks okay, but how are you determining the output of awk? Since awk's output is being parsed by make on the dependency side of a rule, are you just printing `$<`? (You could try redirecting awk's output to a file) More importantly, why are you trying to generate this list dynamically? It is generally considered best practice to explicitly list this type of dependency. – William Pursell May 26 '15 at 11:31
  • I just printing $<; redirect to file output like "0.%.cpp.5", so templates variable does not work in prerequisites in current sequence line – Anton Riab May 26 '15 at 12:54