2009-07-27 8 views
5

Tôi đang sử dụng mã tương tự như sau trong một Makefile:

empty:= 
space:= $(empty) $(empty) 
path_escape = $(subst $(space),\$(space),$(1)) 

TOP=$(call path_escape,$(abspath .)) 
TARGET=$(TOP)/foo 

$(info TOP='$(TOP)') 
$(info TARGET='$(TARGET)') 

all: $(TARGET) 

$(TARGET): 
    touch '$(notdir [email protected])' 

.PHONY: $(TARGET) 

Nếu tôi sử dụng này trong một thư mục không có dấu cách, nói space-test, nó hoạt động tốt:

$ make 
TOP='/tmp/space-test' 
TARGET='/tmp/space-test/foo' 
touch 'foo' 

Tuy nhiên, nếu tôi sử dụng nó trong một thư mục với các không gian, nói space test, sau đó $(notdir) làm điều sai:

TOP='/tmp/space\ test' 
TARGET='/tmp/space\ test/foo' 
touch 'space foo' 

gì đang xảy ra ở đây là $(notdir) diễn giải /tmp/space test/foo như hai đường dẫn và trả về "một phần tập tin" của cả (ví dụ: spacefoo). Phần kỳ lạ của điều này là TARGET được thoát đúng cách; bằng cách nào đó, bên trong quy tắc hoặc bên trong $(notdir), các dấu gạch chéo ngược được bỏ qua.

Tôi đang làm gì sai ở đây?

Trả lời

9

Các $(notdir) chức năng trong GNU Make mất một danh sách các đối số, cách nhau bằng dấu cách. Một số chức năng hỗ trợ không gian thoát với \\, nhưng $(notdir) không phải là một trong số chúng.

này nên làm việc:

s? = $(subst $(empty) ,?,$1) 
?s = $(subst ?, ,$1) 
notdirx = $(call ?s,$(notdir $(call s?,$1))) 

$(TARGET): 
    touch '$(call notdirx,[email protected])' 

này định nghĩa một phiên bản "không gian an toàn" của notdir gọi notdirx. Nó khá đơn giản: s? đầu tiên biến tất cả các dấu cách thành dấu chấm hỏi (hy vọng rằng chúng không thể hiện diện trong tên tệp) và ?s sẽ chuyển đổi trở lại. Ở giữa chúng ta có thể gọi hàm notdir ban đầu một cách an toàn.

Để có bản tóm tắt tuyệt vời về GNU Tạo và khoảng trống trong tên tệp, hãy xem GNU Make meets file names with spaces in them.

+1

Cảm ơn, Ville. Nó là vô lý mà không có cách nào để thoát khỏi đầu vào đến $ (notdir) ngoại trừ thông qua hack này (hoặc vì vậy nó có vẻ). –

+1

Vâng. GNU Make thực sự có thể sử dụng một phiên bản tùy chọn được kích hoạt (ngược lại không tương thích) 2 của ngôn ngữ và các chức năng tiêu chuẩn. Hoặc có lẽ tốt nhất là chỉ cần sử dụng, nói, SCons hoặc một cái gì đó với một ngôn ngữ lập trình thực sự. –

0

Đây chỉ là một shot trong bóng tối:

TOP='"/home/chris/src/tests/make/space test"' 
+7

Gary, tôi không ghét bạn, tôi tràn đầy tình yêu. Không hạ gục phiếu bầu cá nhân, họ chỉ báo hiệu câu trả lời là chính xác và/hoặc hữu ích. Trong trường hợp này, không, điều này không hoạt động. –

+6

Chúng tôi không downvoting ** bạn **, chúng tôi đang downvoting ** câu trả lời của bạn **. Đừng cảm thấy xấu về điều đó. – JesperE

0

Giả sử bạn có một vỏ Unix, bạn có thể bao ra:

notdirx = $(shell basename '$1') 
dirx = $(shell dirname '$1') 

Một chiến lược tương tự có thể áp dụng đối với các chức năng khác. Chỉ cần nhớ các dấu trích dẫn xung quanh biến chứa văn bản bị nhiễm khoảng trắng mà bạn muốn coi là một đối số duy nhất. Điều này cũng sẽ bảo vệ bạn khỏi các ký tự đặc biệt khác (ngoại trừ dấu ngoặc kép!). Dưới đây là một ví dụ để đúp dấu chéo ngược thoát khỏi bất kỳ khoảng trống trong kết quả của một glob wildcard:

$(shell ls -1 '*.foo' | sed 's/ /\\\\ /g') 

Windows được đặt dấu ngoặc đơn trong tên thư mục bây giờ, quá: C:\Program Files (x86)\ Đó là chưa rõ ràng với tôi ý nghĩa của điều này khi là gì sử dụng make.