Melewati variabel tambahan dari baris perintah untuk dibuat

614

Bisakah saya meneruskan variabel ke Makefile GNU sebagai argumen baris perintah? Dengan kata lain, saya ingin memberikan beberapa argumen yang akhirnya akan menjadi variabel di Makefile.

Pablo
sumber

Jawaban:

754

Anda memiliki beberapa opsi untuk mengatur variabel dari luar makefile Anda:

  • Dari lingkungan - setiap variabel lingkungan ditransformasikan menjadi variabel makefile dengan nama dan nilai yang sama.

    Anda mungkin juga ingin mengatur -eopsi (alias --environments-override) aktif, dan variabel lingkungan Anda akan menimpa penugasan yang dibuat menjadi makefile (kecuali penugasan ini sendiri menggunakan overridearahan . Namun, tidak disarankan, dan jauh lebih baik dan fleksibel untuk menggunakan ?=penugasan (variabel bersyarat) operator penugasan, itu hanya berpengaruh jika variabel belum didefinisikan):

    FOO?=default_value_if_not_set_in_environment
    

    Perhatikan bahwa variabel tertentu tidak diwarisi dari lingkungan:

    • MAKE didapat dari nama skrip
    • SHELLdiatur dalam makefile, atau default ke /bin/sh(rasional: perintah ditentukan dalam makefile, dan itu khusus shell).
  • Dari baris perintah - makedapat mengambil tugas variabel sebagai bagian dari baris perintahnya, berbaur dengan target:

    make target FOO=bar
    

    Tapi kemudian semua tugas ke FOOvariabel dalam makefile akan diabaikan kecuali jika Anda menggunakan overridearahan dalam penugasan. (Efeknya sama dengan -eopsi untuk variabel lingkungan).

  • Mengekspor dari induk Make - jika Anda memanggil Make dari Makefile, Anda biasanya tidak boleh secara eksplisit menulis tugas variabel seperti ini:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    Sebagai gantinya, solusi yang lebih baik mungkin untuk mengekspor variabel-variabel ini. Mengekspor variabel membuatnya ke lingkungan setiap permintaan shell, dan Melakukan panggilan dari perintah ini memilih variabel lingkungan seperti yang ditentukan di atas.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

    Anda juga dapat mengekspor semua variabel dengan menggunakan exporttanpa argumen.

P Shved
sumber
11
untuk lulus dari baris perintah sesuatu dengan spasi lakukanmake A='"as df"'
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
4
Sepertinya Anda meminta masalah jika Anda peduli dengan variabel lingkungan. Untuk satu hal, itu adalah mimpi buruk debugging jika bekerja di tempat A dan bukan di tempat B, hanya karena mereka memiliki lingkungan yang berbeda.
James Moore
12
Hanya berdasarkan pengalaman, mengekspor barang-barang seperti CFLAGS adalah resep untuk mimpi buruk untuk proyek-proyek besar. Proyek-proyek besar sering memiliki pustaka pihak ke-3 yang hanya dikompilasi dengan set bendera yang diberikan (yang tidak ada yang mengganggu perbaikan). Jika Anda mengekspor CFLAGS, CFLAGS proyek Anda berakhir dengan mengesampingkan perpustakaan pihak ketiga dan memicu kesalahan kompilasi. Cara alternatif mungkin untuk mendefinisikan export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)dan meneruskannya sebagai make -C folder $(PROJECT_MAKE_FLAGS). Jika ada cara untuk memberitahu makefile perpustakaan untuk mengabaikan lingkungan, itu akan ideal (kebalikan dari -e).
RD
24
PERINGATAN: Di bagian "Mengekspor dari induk Buat" di atas, "Jangan lakukan ini!" adalah kritis menyesatkan . Melewati variabel pada baris perintah menimpa penugasan di sub-makefile tetapi variabel yang diekspor tidak menimpa penugasan di sub-makefile. Dua metode ini untuk meneruskan variabel ke sub-makefile tidak sama dan tidak boleh bingung.
Jonathan Ben-Avraham
4
Ada perbedaan ? make target FOO=bar make FOO=bar target?
gfan
213

Cara paling sederhana adalah:

make foo=bar target

Kemudian di makefile Anda, Anda bisa merujuk $(foo). Perhatikan bahwa ini tidak akan menyebar ke sub-membuat secara otomatis.

Jika Anda menggunakan sub-merek, lihat artikel ini: Mengkomunikasikan Variabel ke Sub-merek

Mark Byers
sumber
2
oleh sub-make yang Anda maksud dengan makefile includeddi makefile utama?
Pablo
2
@Michael: Itu berarti memanggil make lagi dari dalam makefile. Saya telah memperbarui jawaban saya karena Anda tampaknya tertarik dengan detail ini.
Mark Byers
2
"Perhatikan bahwa ini tidak akan menyebar ke sub-merek secara otomatis." Tidak Benar! "Secara default, hanya variabel yang berasal dari lingkungan atau baris perintah yang dilewatkan ke permintaan rekursif. Anda dapat menggunakan arahan ekspor untuk melewati variabel lain." gnu.org/software/make/manual/html_node/…
ThomasMcLeod
82

Katakanlah Anda memiliki makefile seperti ini:

action:
    echo argument is $(argument)

Anda kemudian akan menyebutnya make action argument=something

nc3b
sumber
5
jadi target dan argumen bisa dipertukarkan dalam hal posisi?
Pablo
4
@Michael: Ya (lihat jawaban Mark Byers)
nc3b
25

Dari manual :

Variabel dalam make dapat berasal dari lingkungan di mana make dijalankan. Setiap variabel lingkungan yang membuat melihat ketika mulai diubah menjadi variabel make dengan nama dan nilai yang sama. Namun, tugas eksplisit dalam makefile, atau dengan argumen perintah, menimpa lingkungan.

Jadi, Anda dapat melakukan (dari bash):

FOOBAR=1 make

menghasilkan variabel FOOBARdi Makefile Anda.

Thomas
sumber
2
Cara lain memang lebih baik di hampir semua kasus. Saya akan meninggalkan ini di sini untuk kelengkapan.
Thomas
Ini adalah satu-satunya jawaban yang menunjukkan penugasan variabel sebelum perintah make pada baris yang sama - ada baiknya mengetahui ini bukan kesalahan sintaks.
M_M
7

Ada opsi lain yang tidak dikutip di sini yang termasuk dalam buku Make GNU oleh Stallman dan McGrath (lihat http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ). Ini memberikan contoh:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

Ini melibatkan verifikasi jika parameter yang diberikan muncul di MAKEFLAGS. Sebagai contoh .. misalkan Anda sedang mempelajari tentang utas di c ++ 11 dan Anda telah membagi studi Anda di beberapa file ( class01, ..., classNM) dan Anda ingin: kompilasi maka semua dan jalankan secara individu atau kompilasi satu per satu waktu dan jalankan jika bendera ditentukan ( -r, misalnya). Jadi, Anda bisa membuat yang berikut ini Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o [email protected] $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./[email protected]
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete

Dengan itu, Anda akan:

  • membangun dan menjalankan file w / make -r class02;
  • membangun semua w / makeatau make all;
  • build dan run all w / make -r(misalkan semuanya berisi beberapa jenis hal tertentu dan Anda hanya ingin menguji semuanya)
Ciro Costa
sumber
6

kelihatannya

perintah args menimpa variabel lingkungan

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Jalankan contoh

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
YumaIura
sumber
5

Jika Anda membuat file bernama Makefile dan menambahkan variabel seperti ini $ (belum dikirim) maka Anda akan dapat menggunakan variabel ini di dalam Makefile bahkan dengan wildcard

contoh:

make unittest=*

Saya menggunakan BOOST_TEST dan dengan memberikan wildcard ke parameter --run_test = $ (unittest) maka saya akan dapat menggunakan ekspresi reguler untuk menyaring tes. Saya ingin Makefile saya dijalankan

serup
sumber
4
export ROOT_DIR=<path/value>

Kemudian gunakan variabel, $(ROOT_DIR)di Makefile.

parasrish
sumber