Biến điều kiện trong Makefile


1

Tôi đang cố gắng biên dịch mã nguồn theo nhiều cách khác nhau. Ví dụ, giả sử tôi muốn biên dịch một chương trình fortran với mã nguồn main.f90, file1.f90file2.f90như đầu vào. Để tạo hello.exe, tôi chỉ cần làm

FC=gfortran
EXE=hello.exe
OBJS=file1.o file2.o
FFLAGS=

$(EXE): $(OBJS)
    $(FC) $(FFLAGS) main.f90 $(OBJS) -o $(EXE)

file1.o: file1.f90
    $(FC) $(FFLAGS) -c file1.f90

file2.o: file2.f90
    $(FC) $(FFLAGS) -c file2.f90

clean:
    rm -rf *.o

Bây giờ, giả sử tôi muốn tạo các phiên bản khác nhau của điều này và so sánh đầu ra. Tôi muốn tạo một hello_O2.execái sử dụng -O2cờ biên dịch, một hello_O3.exephiên bản có -O3cờ và thậm chí biên dịch với các trình biên dịch khác nhau. Tôi muốn một ví dụ hello_intel_O2.exesử dụng -O2cờ cũng như sử dụng iforttrình biên dịch intel.

Lý tưởng nhất, tôi muốn chỉ định make intelO3sử dụng iforttrình biên dịch và -O3gắn cờ và sẽ tạo ra hello_intel_O3.exetệp thực thi. Nếu tôi chỉ định make allnó sẽ tạo ra hello_O2.exe, hello_O3.exe, hello_intel_O2.exe, và hello_intel_O3.exenhững chương trình, mỗi trình biên dịch chính xác và mức độ tối ưu hóa.

Làm thế nào điều này có thể đạt được trong ví dụ tối thiểu này? Makefile thực tế của tôi là ~ 120 dòng ngay bây giờ và sử dụng nhiều biến mà tôi thay đổi mỗi lần tôi muốn xây dựng cho một phiên bản khác.

Câu trả lời:


0

Bạn có thể chỉ cần ghi đè bất kỳ biến nào được đặt trong tệp thực hiện khi bạn đưa chúng làm đối số cho lệnh make. Vì vậy, ví dụ:

#!/bin/make
FC=gfortran
EXE=hello$(SUFFIX).exe
OBJS=file1.o file2.o
FFLAGS=

default: $(EXE)

intelO3:
        $(MAKE) FC=ifort FFLAGS=-O3 SUFFIX=_intel_O3
all:
        $(MAKE) FFLAGS=-O2 SUFFIX=_O2
        $(MAKE) FFLAGS=-O3 SUFFIX=_O3
        $(MAKE) FC=ifort FFLAGS=-O3 SUFFIX=_intel_O3

... rest of makefile

0
  1. Tôi đề nghị rằng, giống như bạn muốn nhiều bản sao khác nhau của .exetệp chương trình, bạn cũng duy trì nhiều bản sao của .otệp. Một cái gì đó như thế này:

    file1_gfortran.o: file1.f90
            gfortran $(FFLAGS) -c file1.f90 -o file1_gfortran.o
    
    file2_gfortran.o: file2.f90
            gfortran $(FFLAGS) -c file2.f90 -o file2_gfortran.o
    
    file1_ifort.o:    file1.f90
            ifort    $(FFLAGS) -c file1.f90 -o file1_ifort.o
    
    file2_ifort.o:    file2.f90
            ifort    $(FFLAGS) -c file2.f90 -o file2_ifort.o
    

    nếu không, bạn sẽ cần biên dịch lại mọi .f90 tệp bất cứ khi nào bạn sửa đổi bất kỳ tệp nào trong số chúng. (Điều này sẽ có được có ý nghĩa khi bạn có file3.f90, file4.f90, vv ...)

    • Bạn có thể loại bỏ một số dư thừa dài dòng; ví dụ, sử dụng -o $<. Xem thêm đoạn 5, bên dưới.
    • Bạn có thể cần phải có hai bản sao khác nhau FFLAGS, nếu có nhiều hơn chỉ là cờ.-On
    • Tôi đoán bạn sẽ muốn xác định OBJS=file1_$(FC).o file2_$(FC).o.
  2. Thay vì chỉ có một danh sách các lệnh, tôi khuyên bạn nên xác định rõ ràng tất cả các tệp mục tiêu mà bạn (có thể) muốn tạo ra; ví dụ,

    hello.exe:
            $(MAKE)
    
    hello_O2.exe:
            $(MAKE)          FFLAGS=-O2 SUFFIX=_O2
    
    hello_O3.exe:
            $(MAKE)          FFLAGS=-O3 SUFFIX=_O3
    
    hello_intel.exe:
            $(MAKE) FC=ifort            SUFFIX=_intel
    
    hello_intel_O2.exe:
            $(MAKE) FC=ifort FFLAGS=-O2 SUFFIX=_intel_O2
    
    hello_intel_O3.exe:
            $(MAKE) FC=ifort FFLAGS=-O3 SUFFIX=_intel_O3
    

    vậy thì bạn có thể nói

    intelO3: hello_intel_O3.exe

    mà không phải nhập $(MAKE) FC=ifort FFLAGS=-O3 SUFFIX=_intel_O3 lệnh hai lần. Sau đó, rõ ràng, bạn sẽ nói:

    all: hello.exe hello_O2.exe hello_O3.exe hello_intel.exe hello_intel_O2.exe hello_intel_O3.exe
  3. Trên thực tế, những điều trên có thể sẽ hoạt động tốt hơn với các mục tiêu giả:

    all: gf gfO2 gfO3 intel intelO2 intelO3
    
    gf:
            $(MAKE) FC=gfortran
    
    gfO2:
            $(MAKE) FC=gfortran FFLAGS=-O2 SUFFIX=_O2
    
    gfO3:
            $(MAKE) FC=gfortran FFLAGS=-O3 SUFFIX=_O3
    
    intel:
            $(MAKE) FC=ifort               SUFFIX=_intel
    
    intelO2:
            $(MAKE) FC=ifort    FFLAGS=-O2 SUFFIX=_intel_O2
    
    intelO3:
            $(MAKE) FC=ifort    FFLAGS=-O3 SUFFIX=_intel_O3
    
  4. Và sau đó bạn có thể thu gọn sáu khổ thơ cuối ở trên thành một thứ như thế này:

    gf gfO2 gfO3 intel intelO2 intelO3:
            case $< in (gf*) compiler=gfortran; suffix="";; \
                       (in*) compiler=ifort; suffix="_intel";; esac; \
            case $< in (*O2) flags="-O2"; suffix="${suffix}_O2";; \
                       (*O3) flags="-O3"; suffix="${suffix}_O3";; esac; \
            $(MAKE) FC="$compiler" FFLAGS="$flags" SUFFIX="$suffix"
    

    Lưu ý rằng đây là lệnh shell nhiều dòng (tiếp tục bằng dấu gạch chéo ngược ở cuối dòng). Bạn cần điều này nếu bạn muốn đặt một biến shell trong một dòng và sử dụng nó trong dòng tiếp theo; hành vi mặc định của make là sinh ra một quy trình shell riêng cho mỗi dòng lệnh, do đó làm mất các hiệu ứng phụ cục bộ như thư mục làm việc ( cd) và các biến shell.

  5. Quay trở lại đoạn đầu tiên: bạn có thể đơn giản hóa nó thành

    file1_gfortran.o file1_ifort.o: file1.f90
            case $< in (_gf*) compiler=gfortran;; \
                       (_if*) compiler=ifort;; esac; \
            "$compiler" $(FFLAGS) -c file1.f90 -o $<
    
    file2_gfortran.o file2_ifort.o: file2.f90
            case $< in (_gf*) compiler=gfortran;; \
                       (_if*) compiler=ifort;; esac; \
            "$compiler" $(FFLAGS) -c file2.f90 -o $<
    

    và tôi nghi ngờ rằng bạn có thể kết hợp những điều trên thành một khổ thơ duy nhất (bắt đầu bằng một cái gì đó như ), nhưng tôi không thể nhớ làm thế nào.X_gfortran.o X_ifort.o: X.f90

Hãy cẩn thận: Tôi đã không kiểm tra bất kỳ điều này.

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.