Pertanyaan Prasyarat pesanan saja tidak berfungsi dengan benar di GNU make?


Saya memiliki masalah dengan prasyarat khusus pesanan. Ini tidak mengeksekusi pertama sama sekali. Apakah saya salah memahami cara prasyarat agar-agar bekerja?

Buat skrip berikut:

.PHONY: mefirst mefirst2

mefirst:
    @echo "I'm first!"

mefirst2:
    @echo "I'm first too!"

normaltarget: normaltarget2 | mefirst2
    @echo "normaltarget done"

normaltarget2: a b c 
    @echo "normaltarget2 done"

helloworld: normaltarget | mefirst
    @echo "helloworld done"

.DEFAULT_GOAL := go
go: helloworld
    @echo "go done"

a:
    @echo a
b:
    @echo b
c:
    @echo c

... mencetak yang berikut:

a
b
c
normaltarget2 done
I'm first too!
normaltarget done
I'm first!
helloworld done
go done

... bukan apa yang saya harapkan:

I'm first!
I'm first too!
a
b
c
normaltarget2 done
normaltarget done
helloworld done
go done

Apa yang saya lakukan salah?


16
2017-07-18 09:28


asal


Jawaban:


Apakah saya salah memahami cara prasyarat agar-agar bekerja?

Ya, seperti itulah rupanya.

Nama "pesanan saja" agak membingungkan. Prasyarat di belakang | disebut "prasyarat pesanan saja" bukan karena mereka mengubah urutan eksekusi resep di dalam daftar prasyarat untuk satu target, tetapi karena satu-satunya tujuan mereka adalah memiliki target tertentu yang dibuat sebelum orang lain, seperti bootstrap. Sebagaimana dijelaskan dengan akurat oleh pengguna bobbogo di bawah (- terima kasih untuk mengoreksi): jika make memutuskan untuk membangun kembali prasyarat target, itu akan menjalankan resep untuk prasyarat itu. Sekarang, untuk prasyarat biasa pembaruan ini menyiratkan bahwa target sekarang sudah tidak berlaku lagi, dan make harus menjalankan resep target. Untuk prasyarat pesanan saja di sisi lain, make tidak menandai target sebagai perlu pembaruan.

Misalnya lihat bagian Jenis Prasyarat untuk use case di mana direktori harus dibuat sebelum objek di direktori itu dibuat.

Ambil contoh ini makefile:

a: b
    touch a

b: c
    touch b

c:
    touch c

x: | y 
    touch x

y: | z 
    touch y

z:
    touch z

Seperti yang Anda lihat, b dan c adalah prasyarat normal a dan b, sedangkan y dan z adalah prasyarat pesanan saja x dan y. Mulai dari yang bersih, mereka terlihat sama:

:~$ make a
touch c
touch b
touch a
:~$ make x
touch z
touch y
touch x
:~$ make a
make: `a' is up to date.
:~$ make x
make: `x' is up to date.

Namun, jika kita sekarang secara manual "memperbarui" prasyarat di akhir rantai (c dan z), kami melihat perbedaannya:

:~$ touch c
:~$ make a
touch b
touch a
:~$ touch z
:~$ make x
make: `x' is up to date.

Ini menunjukkan bagaimana prasyarat khusus pesanan yang ada tidak membatalkan target apa pun, terlepas dari cap waktu mereka. Menghapus target hanya-pesanan memang menghasilkan pembangunan ulang (tetapi hanya membangun kembali file yang hilang itu):

:~$ rm c
:~$ make a
touch c
touch b
touch a
:~$ rm z
:~$ make x
touch z

Setelah itu dikatakan, cara yang benar untuk mengubah urutan resep Anda dijalankan adalah dengan mengoreksi ketergantungan antara target. Misalnya, jika Anda mau mefirst akan dibangun sebelumnya a, maka Anda perlu membuatnya mefirst sebuah prasyarat untuk a, seperti dalam

a: mefirst
    @echo a

Tidak mungkin memberikan seluruh solusi atas pertanyaan Anda karena Anda tidak menjelaskan secara detail di mana urutan yang Anda harapkan untuk menjalankan resep.


Ada jalan pintas untuk jawaban Anda yang bukan solusi tetapi masih menarik untuk diketahui. Meskipun tidak didokumentasikan, tampaknya prasyarat satu target diproses dalam urutan yang muncul. Itu | tanda tidak mengubah itu. Dalam kasus sederhana Anda, Anda dapat mengambil keuntungan dari itu untuk mencapai output yang Anda cari:

normaltarget: mefirst2 normaltarget2
    @echo "normaltarget done"

dan

helloworld: mefirst normaltarget
    @echo "helloworld done"

Namun, seperti yang ditunjukkan oleh Anda sendiri, "solusi" ini segera pecah begitu -j bendera digunakan untuk menjalankan resep secara paralel. Juga, seperti yang ditunjukkan oleh pengguna bobbogo, mengandalkan mekanisme pemesanan ini adalah praktik yang buruk. Memperkenalkan dependensi baru dapat mengganggu pemesanan. Jadi jangan lakukan ini :-)


35
2017-07-21 01:52