2010-08-03 27 views
5

Tôi có một dự án có makefile sử dụng các tính năng độc quyền với GNU Make. Đáng buồn thay, có những nền tảng chúng ta phải hỗ trợ nơi mà GNU thực hiện vẫn không phải là mặc định khi chạy make.Phát hiện (không phải) GNU Thực hiện khi ai đó chạy `make`

Một trong những đồng nghiệp của tôi bị cắn bởi điều này, khi một người không phải GNU thực hiện âm thầm không xây dựng mã của chúng tôi một cách chính xác (nó mở rộng một biến tự động thành một chuỗi rỗng). Tôi muốn ngăn chặn điều đó xảy ra lần nữa, bằng cách tạo ra một thông báo lỗi rõ ràng để thay thế.

Tôi có thể viết gì trong một số Makefile để phân biệt GNU được tạo từ không phải GNU, in ra lỗi rõ ràng và thoát?

Tôi đã tìm ra cách giải quyết để đổi tên makefile thực thành GNUmakefile và đặt một nhánh nhỏ trong Makefile, nhưng tôi muốn có một thứ gì đó trực tiếp hơn.

Những câu trả lời của Beta và Dan khuôn trông thật sự tốt đẹp và đơn giản, nhưng trên AIX 6.1, làm cho thực hiện không thể xử lý một trong hai trong số họ:

$ cat testmake 

foo: 
     touch foo 

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

ifeq "${MAKE_VERSION}" "" 
$(info GNU Make not detected) 
$(error ${MIN_MAKE_VER_MSG}) 
endif 


$ /usr/bin/make -f testmake 
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator. 
make: 1254-058 Fatal errors encountered -- cannot continue. 

tôi chạy vào các vấn đề tương tự trên cả hai cổ xưa và hiện đại phiên bản (Solaris 8 & 10) của Sun làm. Điều đó ít quan trọng hơn, nhưng sẽ rất tốt để quản lý.

+0

Phiên bản GNU nào bạn đang chạy? – bta

+0

Bạn đúng. Cách tiếp cận tôi đã thực hiện dựa quá nhiều vào GNU, vì vậy có thể không hoạt động * ở tất cả * với việc thực hiện không phải GNU. Tôi bây giờ nghi ngờ rằng có một cách di động để đạt được mục tiêu của bạn bằng cách sử dụng chỉ một Makefile (tức là mà không cần đến một kịch bản shell hoặc tài nguyên bên ngoài khác). Tôi đã hủy bỏ câu trả lời của mình. –

Trả lời

2

Tôi không biết bất kỳ tính năng bên trong nào chắc chắn là duy nhất đối với GNUMake, nhưng đây là một kludge: gọi "make -v" và phân tích đầu ra cho "GNU" (vì có vẻ như không phải là GNU sẽ có MAKE thiết lập để một GNU Make):

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

EDIT:
Giống như Dan khuôn mẫu, tôi bắt đầu để xem kích thước thật của vấn đề này. Theo văn bản, nó đòi hỏi một Makefile đó là cú pháp chính xác trong tất cả phiên bản của Make. Tôi không có quyền truy cập vào Sun Make (và tôi không thể tìm thấy hướng dẫn sử dụng cho nó) vì vậy tôi không biết liệu điều đó có thể xảy ra hay không hoặc viết nó như thế nào, hoặc làm thế nào để kiểm tra nó nếu tôi đã làm.

Nhưng tôi có thể đề xuất một phương pháp có thể hoạt động. Có thể một cái gì đó như thế này có thể được làm phổ biến:

default: 
    ./runGNUMake.pl 

Đó là toàn bộ makefile. Sau đó, viết kịch bản runGNUMake trong Perl (hoặc bash hoặc bất kỳ thứ gì bạn thích) sẽ thực hiện giống như "make-" kludge của tôi và sau đó in thông báo lỗi hoặc chạy "make -f realMakefile".

+0

Tôi đã nghĩ đến việc làm điều này trong một kịch bản bên ngoài chạy trước khi thực hiện, nhưng tôi đã không nghĩ đến việc nhúng nó vào trong makefile. – Novelocrat

+0

Không hoạt động trên AIX 6.1 :-( – Novelocrat

+0

Tiểu thuyết: thực sự? Làm thế nào để nó thất bại, không phải là GNU Hãy tạo ra một 'MAKE' dường như được đặt thành GNU Make, hoặc thực hiện GNU không phải GNU? (Tôi đoán chúng ta có thể gọi những "sai dương tính" và "sai âm" tương ứng.) – Beta

6

Như đã đề cập, GNU make kiểm tra cho GNUmakefile trước makefile hoặc Makefile, tôi đã sử dụng một sửa chữa tầm thường như bạn mô tả, một mặc định (mồi) Makefile mà gây ra một lỗi/cảnh báo:

default: 
    @echo "This requires GNU make, run gmake instead" 
    exit 70 

Các GNU make documentation khuyên bạn nên sử dụng tên GNUmakefile khi Makefile là GNU cụ thể, vì vậy đó là giải pháp ưa thích của tôi.

Trên nền tảng nơi người gốc make thích một tên Makefile khác, bạn có thể thực hiện một biến thể về điều này, ví dụ:trên FreeBSD Tôi có mồi trên trong BSDmakefile được sử dụng theo sở thích Makefile (do đó ngăn hệ thống make khỏi xâu chuỗi xây dựng của tôi). AFAICT AIX hoặc Solaris make không có tên thay thế mà bạn có thể sử dụng theo cách này.

Một vấn đề với trình bao bọc Makefile cố gắng gọi GNU make là chuyển tất cả các đối số.

Một thử nghiệm dường như di động (cho đến nay, tôi đã tìm thấy nó để làm việc trên một kết hợp của OSF1 cổ, BSD và hệ thống Solaris), bạn có thể sử dụng SOMETHING=$(shell ...) để phát hiện nếu GNU make đang chạy, phiên bản phi GNU sẽ không đặt SOMETHING . Do deferred evaluation of variables, bạn không thể sử dụng điều này dễ dàng như mong đợi. Điều này dựa vào việc triển khai âm thầm xử lý tên macro có dấu cách khi mở rộng bằng $() (tức là xử lý $(shell foo) dưới dạng tên biến/macro thay vì function, mặc dù việc gán cho tên như vậy trong quá trình triển khai đó sẽ gây ra lỗi).

Cách di động duy nhất mà bạn có thể in một rõ ràng lỗi là phải có một mục tiêu giả mà luôn chạy, bằng cách sử dụng thủ thuật trên:

GNUMAKE=$(shell echo GNUMAKE) 

default: gnumake all 

gnumake: 
     @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; } 

này giả định bạn có một POSIX sh vỏ.

(Tôi đã thấy các bài kiểm tra mà kiểm tra $(MAKE) -v thất bại khi cả hai hệ thống và GNU thực hiện được gọi là "make", hệ thống make âm mưu chống lại bạn và gọi GNU make ... Bạn sẽ cần một số cẩn thận kiểm tra các biến môi trường PATH, MAKE và có thể SHELL để xử lý mọi trường hợp.)

Các vấn đề liên quan