2009-03-12 6 views
7

Chúng tôi đang thảo luận gần đây về cách chúng tôi xử lý các tệp .d cho các phụ thuộc trong quy trình tạo dựa trên thực hiện của chúng tôi. Vấn đề đã được nêu ra rằng đôi khi các tệp .d có thể bị hỏng khi các bản dựng bị gián đoạn.Bắt đầu xóa các tệp bổ sung do lỗi

Chúng tôi đang sử dụng mục tiêu .DELETE_ON_ERROR để đảm bảo rằng nếu một phiên bản bị gián đoạn hoặc không thành công, các tệp đối tượng mà nó đang trong quá trình tạo sẽ bị xóa. Tuy nhiên chúng tôi cũng đang sử dụng GCC để tạo ra các tập tin .d tại thời gian biên dịch mà sẽ cần phải được xóa là tốt. Có vẻ như không phải là một cách đơn giản để nói về điều này.

Vì vậy, câu hỏi là, có cách nào chúng ta có thể dỗ thực hiện để xóa cả đối tượng và tệp phụ thuộc của chúng tôi trong trường hợp có lỗi? Có cách nào chúng tôi có thể thiết lập các quy tắc để biết rằng cả tệp .d và .o được tạo cùng một lúc và cần xóa nếu có lỗi?

Cách khác, có cách nào khác mà chúng tôi có thể thực hiện để khắc phục sự cố tệp .d bị hỏng không? Một gợi ý dọc theo những dòng này là tạo ra các tệp .d với tên tạm thời và có một bước biên dịch sau mỗi tệp sao chép nó thành tên chính xác.

Trả lời

6

Nói chung, GNU không hỗ trợ các mục tiêu có nhiều kết quả đầu ra. Tuy nhiên, có một ngoại lệ cho quy tắc đó: quy tắc mẫu. Nếu bạn có thể cấu trúc makefile của bạn sao cho nó sử dụng các quy tắc mẫu để tạo các tệp đối tượng, bạn có thể đạt được các mục tiêu của mình. Ví dụ:

.DELETE_ON_ERROR: 

all: foo.o 

%.o %.d: %.c 
    @touch $*.d 
    @touch $*.o 
    @exit 1 

Bạn sẽ thấy rằng với makefile này khi "lỗi" được phát hiện trong quy tắc, cả tệp .d và tệp .o đều bị xóa. Ưu điểm của phương pháp này là nó thể hiện chính xác hơn biểu đồ phụ thuộc bằng cách mô tả cách tệp .d được tạo ra và quy tắc nào sẽ tạo ra nó. Ngoài ra, một mô hình phổ biến trong trường hợp này cũng giống như bạn gợi ý: GCC tạo tệp .d thành một tên tệp tạm thời và chỉ di chuyển nó vào vị trí sau khi lệnh GCC đã hoàn tất thành công. Quay lại đầu trang Cung cấp Phản hồi THÔNG TIN THÊM Thông thường điều này được thực hiện với một thủ thuật của vỏ:

all: foo.o 

%.o: %.c 
    gcc -o [email protected] -MMD -MF $(basename [email protected]).d.tmp -c $< \ 
     && mv $(basename [email protected]).d.tmp $(basename [email protected]).d 

Ở đây, "ma thuật" Bí quyết là việc sử dụng các cờ GCC -MMD, tạo ra các tập tin phụ thuộc như một tác dụng phụ của biên soạn, và -MF, mà cho phép bạn chỉ định tên đầu ra cho tệp phụ thuộc; và việc sử dụng cú pháp của cú pháp cmd1 && cmd2, khiến cho trình bao chỉ thực thi cmd2 nếu thoát khỏi thành công cmd1.

+0

'.DELETE_ON_ERROR:' ở trên cùng của tệp makefile, hãy để tôi loại bỏ tất cả các tempfiles của tôi. Cảm ơn! –

+0

Tôi khuyên bạn nên đặt mv làm dòng thứ hai trong công thức cho quy tắc mẫu "% .o:% .c".Tôi không thấy bất kỳ thay đổi nào về hành vi hoặc lợi ích khi sử dụng shell '&&' để đặt nó trên dòng đầu tiên. –

+0

@RichardPerrin đề xuất của bạn sẽ tạo ra hành vi không chính xác nếu gmake được gọi với tùy chọn '-i' (bỏ qua lỗi). Trong trường hợp đó, phiên bản của bạn sẽ chạy lệnh 'mv' có hay không có lỗi trong' gcc', trong khi bản gốc của tôi sẽ không. –

-1

Tôi không có ví dụ nào của Eric để hoạt động bình thường. GCC (phiên bản 4.4) không biên dịch bất cứ thứ gì khi bạn chuyển qua khóa chuyển đổi -MM để nó không giống như bạn có thể biên dịch và viết .d trong một lần. Dưới đây là những gì tôi đã làm:

%.o: %.c 
    @rm -f [email protected] $(patsubst %.o,%.d,[email protected]) 
    gcc -c $< -o [email protected] 
    @$(CXX) -MM -MG > $(patsubst %.o,%.d,[email protected]) 

Nó bắt đầu ra bằng cách xóa một tập tin .d hiện, dòng thứ ba mà tạo ra những cái mới chỉ được thực hiện nếu lệnh thứ hai, bước biên dịch thực tế, thành công (Eric & & lừa không cần thiết, tự động thực hiện việc này). Vì một số lý do tôi không hiểu, tệp .o hiện tại không tự động bị xóa nếu quá trình biên dịch không thành công, nhưng điều đó đã được giải quyết dễ dàng bằng cách thêm [email protected] vào rm đầu tiên.

+0

Đúng, gcc sẽ không thực sự biên dịch tệp nếu bạn chỉ định '-MM'. Bạn cũng phải sử dụng '-MF' như được mô tả trong câu trả lời gốc của tôi. –

+0

@Eric Tôi cũng đã thêm chuyển đổi -MF, nhưng bộ tiền xử lý dường như không gửi đầu ra tới phần biên dịch của gcc vì vậy tôi kết thúc với một tệp đối tượng 0 byte ... – Wim

+0

Xin lỗi, tôi đã nhầm lẫn: bạn muốn '-MMD', không phải' -MM'. Tôi cũng đã sửa lại câu trả lời gốc. –