Makefile 中的条件变量

Makefile 中的条件变量

我正在尝试以各种方式编译源代码。例如,假设我想编译一个 Fortran 程序,其源代码为main.f90file1.f90file2.f90作为输入。要生成hello.exe,我只需执行

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

现在,假设我想制作此版本的各个版本并比较输出。我想制作一个hello_O2.exe使用-O2编译标志的版本,一个hello_O3.exe带有标志的版本,甚至使用不同的编译器进行编译。例如,-O3我想要一个hello_intel_O2.exe使用-O2标志以及使用英特尔编译器的版本。ifort

理想情况下,我希望指定make intelO3使用ifort编译器并-O3标记哪个和将生成hello_intel_O3.exe可执行文件。如果我指定,它将make all创建hello_O2.exe、、和二进制文件,每个文件都具有正确的编译器和优化级别。hello_O3.exehello_intel_O2.exehello_intel_O3.exe

在这个最小的例子中如何实现这一点?我实际的 Makefile 现在大约有 120 行,并且使用了许多变量,每次我想要构建不同的版本时,我都会更改这些变量。

答案1

当你将 makefile 中设置的任何变量作为参数提供给 make 命令时,你可以简单地覆盖它们。例如:

#!/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

答案2

  1. 我建议,就像您需要.exe程序文件的多个不同副本一样,您也需要维护.o文件的多个副本。如下所示:

    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
    

    否则你需要重新编译每一个 .f90file3.f90每次修改其中任何一个时,都会将其归档。(当您有、等时,这将变得很重要file4.f90……)

    • 您也许能够消除一些冗长的冗余;例如,使用-o $<。另请参阅下面的第 5 段。
    • FFLAGS如果除了标志之外还有别的东西,那么你可能需要有两个不同的副本。-On
    • 我猜你会想要定义OBJS=file1_$(FC).o file2_$(FC).o
  2. 我建议你不要只列出命令,而要明确标识出你(可能)想要生成的所有目标文件;例如,

    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
    

    那么你可以说

    intelO3: hello_intel_O3.exe
    

    而不必输入$(MAKE) FC=ifort FFLAGS=-O3 SUFFIX=_intel_O3 两次命令。那么,显然,你会说:

    all: hello.exe hello_O2.exe hello_O3.exe hello_intel.exe hello_intel_O2.exe hello_intel_O3.exe
    
  3. 实际上,以上方法可能更适合伪目标:

    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. 然后你也许可以将上面的最后六节折叠起来就像是这:

    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"
    

    请注意,这是一个多行 shell 命令(行尾以反斜杠结尾)。如果您想在一行中设置 shell 变量并在下一行中使用它,则需要这样做;的默认行为是make 为每个命令行生成一个单独的 shell 进程,从而丢失本地副作用,如工作目录(cd)和 shell 变量。

  5. 回到第一段:你也许可以将其简化为

    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 $<
    

    并且我认为您可以将上述内容合并为一个节(以类似的内容开头),但我不记得该怎么做。X_gfortran.o X_ifort.o: X.f90

警告:我还没有测试过这些。

相关内容