This question already has an answer here:
- Escaping in makefile 2 answers
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 value of %, info bellow. I attempted to correct it:.cpp
...%.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?
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 invoked 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 $
.
来源:https://stackoverflow.com/questions/30445218/why-does-awk-not-work-correctly-in-a-makefile