unix Makefile中文件名中的转义冒号

lvmkulzt  于 2023-04-29  发布在  Unix
关注(0)|答案(8)|浏览(230)

有没有办法让GNU make正确处理包含冒号的文件名?
我遇到的具体问题恰好涉及到一个模式规则。下面是一个简化的版本,它不依赖于剪切和粘贴制表符:

% make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-redhat-linux-gnu
% cat Makefile
COLON := \:
all: ; true
%.bar: ; cp $< $@
x.bar: x.foo
%.foo: ; touch $@
a$(COLON)b.bar: a$(COLON)b.foo
all: x.bar a$(COLON)b.bar
clean: ; rm -f *.foo *.bar
% make clean
rm -f *.foo *.bar
% make
touch x.foo
cp x.foo x.bar
cp  a\:b.bar
cp: missing destination file operand after `a:b.bar'
Try `cp --help' for more information.
make: *** [a\:b.bar] Error 1

将$(COLON)替换为文字:产生完全相同的结果。如果没有反斜杠,它会这样做:

Makefile:6: *** target pattern contains no `%'.  Stop.
6mw9ycah

6mw9ycah1#

我怀疑这是不可能的:参见this discussion about colons in Makefiles。总而言之,GNUmake从来没有很好地处理过包含空格或冒号的文件名。维护者Paul D.Smith说,增加对转义的支持将倾向于break existing makefiles。此外,添加这种支持将需要对代码进行重大更改。
你也许可以用一些讨厌的临时文件安排来工作。
祝你好运!

yyhrrdl8

yyhrrdl82#

这里的答案似乎太复杂了,毫无帮助。我终于找到了一个解决方案here

colon := :
$(colon) := :

然后使用文件名中的宏作为:

filename$(:)

其在评估时成功地转换为“filename:”。

xeufq47z

xeufq47z3#

下面的黑客对我很有效,尽管不幸的是它依赖于$(shell)。

# modify file names immediately
PRE := $(shell rename : @COLON@ *)
# example variables that I need
XDLS = $(wildcard *.xdl)
YYYS = $(patsubst %.xdl,%.yyy,$(XDLS))
# restore file names later
POST = $(shell rename @COLON@ : *)

wrapper: $(YYYS)
    @# restore file names
    $(POST)

$(YYYS):
    @# show file names after $(PRE) renaming but before $(POST) renaming
    @ls

因为PRE被分配了:=,所以在计算XDLS变量之前,会运行与之关联的shell命令。关键是通过显式调用$(POST)将冒号放回原处。

b1payxdu

b1payxdu4#

今天我发现了另一种方法,当处理Makefile变量定义文件名(包含冒号)时。

# definition
SOME_FNAME = $(NAME)__colon__$(VERSION)

# usage in target
foo:
    $(do_something) $(subst __colon__,:,$(SOME_FNAME))
kmbjn2e3

kmbjn2e35#

我不确定这应该起作用,但它说“丢失目标文件”的原因很简单:

%.bar: ; cp $< $@

那一行说从 first 依赖项复制目标。你的a: www.example.com 。你想让它复制什么a: www.example.com 这种情况下,您需要:

%.bar: %.foo ; cp $< $@
kmb7vmvb

kmb7vmvb6#

使用\:转义冒号应该可以。唯一的问题是,你不能用这样一个转义的分号二次展开(读取.SECONDEXPANSION:)变量,否则分号将留在路径名中。
下面是一些使用简单Makefile的测试:

$ tree
.
├── Makefile
├── dst
│   ├── a
│   ├── b
│   └── c
└── src
    └── :

6 directories, 2 files

$ cat Makefile

SRC := $(shell find src -type f | sed 's,:,\\:,')
DST_a := $(patsubst src/%,dst/a/%,$(SRC))
DST_b := $(patsubst src/%,dst/b/%,$(SRC))
DST_c := $(patsubst src/%,dst/c/%,$(SRC))

.PHONY: a
a: $(DST_a);

$(DST_a): $(SRC)
    touch $@

.SECONDEXPANSION:

.PHONY: b
b: $(DST_b);

$(DST_b): $(SRC)
    touch $@

.PHONY: c
c: $(DST_c);

$(DST_c): $$(SRC)
    touch $@
$ make a
touch dst/a/:
$ make b
touch dst/b/:
$ make c
make: *** No rule to make target 'src/\:', needed by 'dst/c/:'.  Stop.
$ tree
.
├── Makefile
├── dst
│   ├── a
│   │   └── :
│   ├── b
│   │   └── :
│   └── c
└── src
    └── :

6 directories, 4 files

与这些交互的另一个特性是$(wildcard ...)。它取消了冒号转义,因此您可能需要在它之后再次转义。

nmpmafwu

nmpmafwu7#

这对我很有效:

colon = :
C$(colon)/temp/foo: C$(colon)/temp/bar
    cp $^ $@
kgsdhlau

kgsdhlau8#

我不能让@navjotk发布的答案工作,所以我只是要作弊,这样做;

FILENAME:=foo:bar
foo_bar:
    touch $(FILENAME)

run:
    if [ ! -e "$(FILENAME)" ]; then $(MAKE) foo_bar; fi

输出:

$ make run
if [ ! -e "foo:bar" ]; then /Library/Developer/CommandLineTools/usr/bin/make foo_bar; fi
touch foo:bar

$ ls
Makefile foo:bar

对我来说够近了。

相关问题