Hành vi kỳ lạ tự động hóa với mạng Make make -f


7

Tôi có một bộ thư mục, một số trong đó chứa tệp tạo tệp và một số tệp tạo tệp có cleanmục tiêu. Trong thư mục cha, tôi có một tập lệnh đơn giản:

#!/bin/bash

for f in *; do
        if [[ -d $f && -f $f/makefile ]]; then
                echo "Making clean in $f..."
                make -f $f/makefile clean
        fi
done

Điều này thực hiện một điều kỳ lạ khi nó chạm vào một thư mục với tệp thực hiện mà không có mục tiêu "sạch" (được xác định). Ví dụ, đưa ra hai thư mục, onetwo, có chứa;

một / làm cho

clean:
        -rm *.x

hai / makefile

clean:

Trong trường hợp thứ hai, "sạch" có mặt mà không có chỉ thị, vì vậy nếu bạn chạy "làm sạch" trong twobạn sẽ nhận được:

make: Nothing to be done for `clean'.

Nếu không có "sạch":

make: *** No rule to make target `clean'.  Stop.

Tuy nhiên, đối với vấn đề tôi sắp mô tả, kết quả là như nhau cho dù mục tiêu có mặt nhưng không xác định hoặc chỉ không hiện diện. Chạy clean.shtừ thư mục cha mẹ;

Making clean in one...
rm *.x
rm: cannot remove `*.x': No such file or directory
make: [clean] Error 1 (ignored)

Vì vậy, onekhông cần làm sạch. Không có vấn đề lớn, điều này là như mong đợi. Nhưng sau đó:

Making clean in two...
cat clean.sh >clean 
chmod a+x clean

Tại sao cat clean.sh>cleanvv? Lưu ý tôi đã tạo một ví dụ tối thiểu chính xác như được hiển thị ở trên - không có tệp hoặc thư mục nào khác xung quanh (chỉ là Clean.sh, thư mục một & hai, và các tệp thực hiện rất tối thiểu). Nhưng sau khi Clean.sh chạy, makeđã sao chép clean.sh > cleanvà thực hiện nó. Nếu tôi sau đó chạy sạch. Một lần nữa:

Making clean in one...
make: `clean' is up to date.
Making clean in two...
make: `clean' is up to date.
Press any key to continue...

Một cái gì đó thậm chí còn kỳ quặc hơn, bởi vì bây giờ nó hoàn toàn không sử dụng các tệp tạo tệp được chỉ định - nó đang sử dụng một số mục tiêu bí ẩn "cập nhật".

Tôi đã nhận thấy một hiện tượng có lẽ liên quan: nếu loại bỏ một trong các mệnh đề kiểm tra trong sạch. Như thế này:

#       if [[ -d $f && -f $f/makefile ]]; then
        if [[ -d $f ]]; then

Và tạo một thư mục threekhông có tệp thực hiện, một phần của đầu ra bao gồm:

Making clean in three...
make: three/makefile: No such file or directory
make: *** No rule to make target `three/makefile'.  Stop.

Rằng tôi không có tập tin hoặc thư mục như vậy, nhưng tại sao makesau đó lại tiếp tục tìm kiếm một mục tiêu với tên đó? Trang người đàn ông có vẻ khá đơn giản:

tập tin -f, --file = tập tin, --makefile = TẬP_TIN

  Use file as a makefile.

Câu trả lời:


9

Hành vi đó không phải là một lỗi. Nó là một tính năng. Một tính năng và một lỗi người dùng có thể chính xác.

Tính năng trong câu hỏi là một trong những quy tắc ngầm của Make. Trong trường hợp của bạn, quy tắc ngầm để "xây dựng" *.shtệp. Lỗi người dùng, lỗi của bạn, không thay đổi thư mục làm việc trước khi gọi tệp thực hiện trong thư mục con.


TL; DR: để sửa lỗi này, bạn có thể thực hiện một hoặc nhiều thao tác sau:

  1. Sửa tập lệnh shell để thay đổi thư mục làm việc:

    #!/bin/bash
    
    for f in *; do
            if [[ -d $f && -f $f/makefile ]]; then
                    echo "Making clean in $f..."
                    (cd $f; make clean)
            fi
    done
    
  2. Làm cho các quy tắc trống rõ ràng:

    clean: ;
    
  3. Thực hiện các cleanmục tiêu giả mạo:

    .PHONY: clean
    

Giải thích chi tiết:

Make có một loạt các quy tắc ngầm. Điều này cho phép một người gọi make trên các dự án đơn giản mà không cần viết makefile.

Hãy thử điều này cho một cuộc biểu tình:

  1. tạo một thư mục trống và thay đổi vào thư mục
  2. tạo một tập tin có tên clean.sh.
  3. chạy make clean

Đầu ra:

$ make clean
cat clean.sh >clean 
chmod a+x clean

BAM! Đó là sức mạnh của quy tắc bắt chước. Xem hướng dẫn sử dụng về các quy tắc ngầm để biết thêm thông tin.


Tôi sẽ cố gắng trả lời câu hỏi mở còn lại:

Tại sao nó không gọi quy tắc ngầm cho tệp thực hiện đầu tiên? Bởi vì bạn ghi đè lên quy tắc ngầm với cleanquy tắc rõ ràng của bạn .

Tại sao cleanquy tắc trong tệp thực hiện thứ hai không ghi đè lên quy tắc ngầm? Bởi vì nó không có công thức. Các quy tắc không có công thức không ghi đè lên các quy tắc ngầm, thay vào đó chúng chỉ nối các điều kiện tiên quyết. Xem hướng dẫn làm về nhiều quy tắc để biết thêm thông tin. Xem thêm hướng dẫn thực hiện về các quy tắc với công thức nấu ăn trống rõ ràng .

Tại sao không thay đổi thư mục làm việc trước khi gọi makefile trong thư mục con? Bởi vì make không thay đổi thư mục làm việc. Make sẽ làm việc trong thư mục làm việc được kế thừa. Về mặt kỹ thuật, điều này không nhất thiết là một lỗi, nhưng hầu hết thời gian là như vậy. Bạn có muốn các tệp tạo tệp trong thư mục con hoạt động trong thư mục con không? Hay bạn muốn họ làm việc trong thư mục cha?

Tại sao bỏ qua cleanquy tắc rõ ràng từ tệp thực hiện đầu tiên trong lần gọi thứ hai clean.sh? Bởi vì bây giờ tập tin đích cleanđã tồn tại. Vì quy tắc cleankhông có điều kiện tiên quyết nên không cần phải xây dựng lại mục tiêu. Xem hướng dẫn thực hiện về các mục tiêu giả mạo mô tả chính xác vấn đề này.

Tại sao thực hiện tìm kiếm mục tiêu three/makefiletrong lần gọi thứ ba? Bởi vì make luôn cố gắng làm lại các makefiles trước khi làm bất cứ điều gì khác. Điều này đặc biệt đúng nếu -ftệp thực hiện được yêu cầu rõ ràng bằng cách sử dụng nhưng nó không tồn tại. Xem hướng dẫn sử dụng về làm lại makefiles để biết thêm thông tin.


Tôi nghĩ rằng câu trả lời này sẽ được cải thiện bằng cách thêm rằng với mỗi phiên bản GNU tương ứng tạo ra (vâng, các hương vị khác tồn tại và đang được sử dụng) make -npf /dev/null(hoặc gmaketùy thuộc vào hệ thống) có thể được sử dụng để kết xuất cơ sở dữ liệu các quy tắc ngầm cho phiên bản chính xác đó. Đã giúp tôi đôi khi.
0xC0000022L
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.