Bagaimana Anda memaksa makefile untuk membangun kembali target

184

Saya memiliki makefile yang dibangun dan kemudian memanggil makefile lain. Karena makefile ini memanggil lebih banyak makefile yang berfungsi, itu tidak benar-benar berubah. Karena itu ia terus berpikir proyek ini dibangun dan terbaru.

dnetdev11 ~ # make
make: `release' is up to date.

Bagaimana saya memaksa makefile untuk membangun kembali target?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Catatan: Nama dihapus untuk melindungi yang tidak bersalah

Edit: Versi Final Tetap:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib
Lodle
sumber
Lodle, karena ini adalah pertanyaan yang sering dikunjungi, apakah Anda ingin mengedit pertanyaan menjadi lebih modern? (Sepertinya .PHONYitu bukan satu-satunya masalah Anda, dan Anda tidak seharusnya mengedit solusi menjadi pertanyaan, atau setidaknya tidak lagi.)
Keith M

Jawaban:

23

Anda dapat mendeklarasikan satu atau lebih dari target Anda sebagai palsu .

Target palsu adalah salah satu yang tidak benar-benar nama file; melainkan itu hanya nama untuk resep yang akan dieksekusi ketika Anda membuat permintaan eksplisit. Ada dua alasan untuk menggunakan target palsu: untuk menghindari konflik dengan file dengan nama yang sama, dan untuk meningkatkan kinerja.

...

Target palsu tidak boleh menjadi prasyarat file target nyata; jika ya, resepnya akan dijalankan setiap kali make untuk memperbarui file itu. Selama target palsu tidak pernah merupakan prasyarat dari target nyata, resep target palsu akan dieksekusi hanya ketika target palsu adalah tujuan yang ditentukan

Dave
sumber
68
Jawaban ini, sementara itu "diterima" dan sangat "terangkat" benar-benar luar biasa. Pertama, dikatakan "menyatakan target sebagai palsu" tetapi kemudian mengatakan "target palsu sebenarnya bukan nama file". Nah, jika target Anda adalah file, maka itu kontradiksi dalam jawabannya. Kedua, dikatakan "target palsu tidak harus menjadi prasyarat yang nyata" - yah, bagaimana jika itu? Pertanyaan aslinya, tidak menentukan apakah itu benar atau tidak. Jawaban yang benar, adalah, bukan untuk menyatakan target Anda sebagai palsu, tetapi lebih tepatnya, menyatakan target palsu tambahan, dan kemudian, tergantung target yang ingin Anda bangun kembali, pada itu.
Mark Galeck
2
@MarkGaleck. Ketika jawabannya menyatakan bahwa "Target palsu adalah salah satu yang tidak benar-benar nama file" itu mengutip langsung dari manual make gcc. Benar sekali.
drlolly
"Target" adalah istilah Make yang merujuk ke teks di sebelah kiri titik dua :, bukan hanya hasil akhir yang ingin Anda buat (mis. File biner Anda). Dalam pertanyaan, release, debug, clean, dan installadalah target Membuat, tidak xxx_utilatau xxxcore.soatau apa pun.
Keith M
728

The -Bberalih ke make, yang bentuknya panjang --always-make, mengatakan makeuntuk cap waktu mengabaikan dan membuat target yang ditentukan. Ini mungkin mengalahkan tujuan penggunaan make, tetapi mungkin itu yang Anda butuhkan.

sykora
sumber
4
@MarkKCowan Saya sepenuhnya setuju! Opsi ini tepat seperti yang saya cari, bukan solusi yang disarankan Dave.
Maarten Bamelis
8
Peringatan dengan pendekatan ini adalah, bahwa itu hanya membangun terlalu banyak hal. Khususnya dengan autotool, saya melihatnya mengkonfigurasi ulang .. Saya berharap solusi berbasis LD_PRELOAD dapat dibuat !!
vrdhn
ya, dan bahkan dapat menulis ulang file yang tidak Anda inginkan! seperti pustaka sistem global yang muncul dalam dependensi dan dibangun kembali dan ditimpa ...
Julio Guerra
18

Salah satu trik yang digunakan untuk didokumentasikan dalam manual Sun makeadalah dengan menggunakan target '.FORCE' (tidak ada). Anda bisa melakukan ini dengan membuat file, force.mk, yang berisi:

.FORCE:
$(FORCE_DEPS): .FORCE

Kemudian, dengan anggapan makefile Anda yang ada dipanggil makefile, Anda bisa menjalankan:

make FORCE_DEPS=release -f force.mk -f makefile release

Sejak .FORCE tidak ada, apa pun yang bergantung padanya akan ketinggalan zaman dan dibangun kembali.

Semua ini akan berfungsi dengan versi apa pun dari make; di Linux, Anda memiliki GNU Make dan karenanya dapat menggunakan target .PHONY seperti yang dibahas.

Ini juga layak mempertimbangkan mengapa makemenganggap rilis terbaru. Ini bisa jadi karena Anda memiliki touch releaseperintah di antara perintah yang dijalankan; itu bisa jadi karena ada file atau direktori yang disebut 'rilis' yang ada dan tidak memiliki dependensi dan juga up to date. Lalu ada alasan sebenarnya ...

Jonathan Leffler
sumber
14

Orang lain menyarankan .PHONY yang pasti benar. .PHONY harus digunakan untuk aturan apa pun yang perbandingan tanggal antara input dan output tidak valid. Karena Anda tidak memiliki target formulir, output: inputAnda harus menggunakan .PHONY untuk SEMUA dari mereka!

Semua yang dikatakan, Anda mungkin harus mendefinisikan beberapa variabel di bagian atas makefile Anda untuk berbagai nama file, dan mendefinisikan aturan make nyata yang memiliki bagian input dan output sehingga Anda dapat menggunakan manfaat make, yaitu bahwa Anda hanya akan benar-benar mengkompilasi hal-hal yang perlu untuk copmile!

Edit: contoh ditambahkan. Belum diuji, tetapi ini adalah bagaimana Anda melakukannya. PHONY

.PHONY: clean    
clean:
    $(clean)
kuda-kuda
sumber
1
Nah, jika Anda bisa menunjukkan kepada saya contoh, itu akan menyenangkan. Atm im hanya
meretasnya
1
Lokasi .PHONYtarget tidak masalah. Itu bisa di mana saja di Makefile.
Adrian W
5

Jika saya ingat dengan benar, 'make' menggunakan cap waktu (waktu modifikasi file) untuk menentukan apakah target sudah terkini atau tidak. Cara umum untuk memaksa membangun kembali adalah dengan memperbarui stempel waktu itu, menggunakan perintah 'sentuh'. Anda bisa mencoba memanggil 'sentuhan' di makefile Anda untuk memperbarui stempel waktu salah satu target (mungkin salah satu dari sub-makefile), yang mungkin memaksa Make untuk menjalankan perintah itu.

poundifdef
sumber
5

Teknik sederhana ini akan memungkinkan makefile berfungsi secara normal ketika pemaksaan tidak diinginkan. Buat target baru bernama force di akhir makefile Anda . The kekuatan target akan menyentuh file target default Anda tergantung pada. Pada contoh di bawah ini, saya telah menambahkan touch myprogram.cpp . Saya juga menambahkan panggilan rekursif untuk dilakukan . Ini akan menyebabkan target default dibuat setiap kali Anda mengetik memaksa .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make
groko
sumber
Anda seharusnya tidak pernah menggunakan makedi dalam Makefile. Gunakan $(MAKE)sebagai gantinya.
Benjamin Crawford Ctrl-Alt-Tut
3

Saya mencoba ini dan itu berhasil untuk saya

tambahkan baris ini ke Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

simpan dan sekarang panggil

make new 

dan itu akan mengkompilasi ulang semuanya lagi

Apa yang terjadi?

1) panggilan 'baru' bersih. 'clean' do 'rm' yang menghapus semua file objek yang memiliki ekstensi '.o'.

2) 'panggilan baru' lakukan '. 'buat' lihat bahwa tidak ada file '.o', jadi itu membuat semua '.o' lagi. kemudian linker menautkan semua file .o ke satu output yang dapat dieksekusi

Semoga berhasil

hamaney
sumber
1
Dalam resep untuk newpenggunaan yang lebih baik $(MAKE)daripadamake
Basile Starynkevitch
1

Sebagai Per Rekursif Miller Membuat Dianggap Berbahaya Anda harus menghindari menelepon$(MAKE) ! Jika Anda tunjukkan, itu tidak berbahaya, karena ini sebenarnya bukan makefile, hanya sebuah skrip pembungkus, yang mungkin juga telah ditulis di Shell. Tetapi Anda mengatakan bahwa Anda terus seperti itu pada tingkat rekursi yang lebih dalam, jadi Anda mungkin menemui masalah yang ditunjukkan dalam esai yang membuka mata itu.

Tentu saja dengan GNU membuatnya sulit untuk dihindari. Dan meskipun mereka menyadari masalah ini, itu adalah cara terdokumentasi mereka dalam melakukan sesuatu.

OTOH, makepp diciptakan sebagai solusi untuk masalah ini. Anda dapat menulis file makefile Anda pada tingkat per direktori, namun semuanya ditarik bersama ke dalam tampilan penuh proyek Anda.

Tetapi warisan makefile ditulis secara rekursif. Jadi ada solusi di mana $(MAKE)tidak melakukan apa pun kecuali menyalurkan subrequest kembali ke proses makepp utama. Hanya jika Anda melakukan hal-hal yang mubazir atau, lebih buruk lagi, yang bertentangan di antara submake Anda, Anda harus meminta --traditional-recursive-make(yang tentu saja merusak keunggulan makepp ini). Saya tidak tahu makefile Anda yang lain, tetapi jika itu ditulis dengan rapi, dengan makepp, pembangunan kembali yang diperlukan harus terjadi secara otomatis, tanpa perlu adanya peretasan yang disarankan di sini oleh orang lain.

Daniel
sumber
Tidak menjawab pertanyaan: bersinggungan dengan poin utama dan harus menjadi komentar, bukan jawaban.
flungo
Mungkin saya tidak cukup jelas. Dengan makepp seluruh makefile wrapper ini tidak diperlukan. Dengan mengetahui dependensi yang tepat (semuanya, bukan hanya yang terdaftar setelahnya :), ia akan selalu dibangun kembali jika diperlukan.
Daniel
1

Jika Anda tidak perlu mempertahankan output apa pun yang sudah berhasil dikompilasi

nmake /A 

membangun kembali semua

CZahrobsky
sumber
0

Ini sebenarnya tergantung pada apa targetnya. Jika itu adalah target palsu (yaitu target TIDAK terkait dengan file), Anda harus mendeklarasikannya sebagai .PHONY.

Namun jika targetnya bukan target palsu tetapi Anda hanya ingin membangunnya kembali untuk beberapa alasan (contohnya adalah ketika Anda menggunakan makro preprocessing __TIME__), Anda harus menggunakan skema FORCE yang dijelaskan dalam jawaban di sini.

Kostas
sumber
0

Itu sudah disebutkan, tetapi saya pikir saya bisa menambahkan untuk menggunakan touch

Jika Anda touchsemua file sumber yang akan dikompilasi, touchperintah mengubah cap waktu file ke waktu sistemtouch perintah dieksekusi.

Timstamp file sumber adalah apa yang makedigunakan untuk "tahu" file telah berubah, dan perlu dikompilasi ulang

Misalnya: Jika proyek itu adalah proyek c ++, maka lakukan touch *.cpp, lalu jalankan makelagi, dan buat harus mengkompilasi ulang seluruh proyek.

mrflash818
sumber
0

Seperti yang ditunjukkan oleh abernier, ada solusi yang disarankan dalam manual make GNU, yang menggunakan target 'palsu' untuk memaksa membangun kembali target:

clean: FORCE
        rm $(objects)
FORCE: ; 

Ini akan berjalan bersih, terlepas dari dependensi lainnya.

Saya menambahkan titik koma ke solusi dari manual, jika tidak, baris kosong diperlukan.

tdietel
sumber
-1

Pada sistem Linux saya (Centos 6.2), ada perbedaan yang signifikan antara mendeklarasikan target .PHONY dan membuat ketergantungan palsu pada FORCE, ketika aturan sebenarnya membuat file yang cocok dengan target. Ketika file harus dibuat ulang setiap kali, diperlukan FORCE dependensi palsu pada file, dan .PHONY untuk dependensi palsu.

salah:

date > $@

Baik:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
UncleBob
sumber
-1

make clean menghapus semua file objek yang sudah dikompilasi.

Hanan Shteingart
sumber