【问题标题】:How do I write a makefile for multiple variants of the same library/executable?如何为同一库/可执行文件的多个变体编写生成文件?
【发布时间】:2015-05-06 13:22:54
【问题描述】:

我正在使用 Intel 的 ifort 和 GNU make 在 linux 机器上构建我的项目。 lib依赖于源目录下的源文件a.f90、b.f90和c.f90。

我正在通过

调用 make
make FLAG

这些 FLAGS 在我的 makefile 中定义并对应于编译器的不同优化标志。

  1. 我希望我的 makefile 为每个标志创建一个新的子目录,这样我就可以一次或一个接一个地编译不同的目标,而不必先删除另一个目标。如何做到这一点?

  2. 稍后,在我的库编译后,我想将我的可执行文件链接到该库的特定变体,因此我必须告诉可执行文件的 makefile,它应该采用哪个变体。如何以可维护的方式做到这一点?

到目前为止我的 makefile 示例:

#
# Include system specific include.mk file.
# This sets the correct compiler and PREFIX path.
#
# sth like:
# PREFIX=~/local
# FC=ifort
# LDR=$(FC)
#
include include.mk
#
#
# Extra Flags for optimization, debug and style.
#
INSPECTOR   := -O0 -g -check none -fPIC
O1          := -O1 -fPIC
O2          := -O2 -fPIC
OPT         := -O3 -fPIC -fast
PEDANTIC    := -fPIC -warn all -warn errors
DEBUG       := -g -fPIC -traceback -debug -check -fpe0

#
# Dircetories for .o, .mod and lib
#
DOC_DIR     := doc
BUILD_DIR   := .build
INSTALL_LIB := $(addprefix $(PREFIX),/lib)
INSTALL_INC := $(addprefix $(PREFIX),/mod)
#
# SOURCE
#
SRC_DIR     := src
vpath %.f90 $(SRC_DIR)

BASIC_OBJ  := a.o b.o c.o

OBJECTS     := $(addprefix $(BUILD_DIR)/,$(BASIC_OBJ) )

MOD_LIST := a_mod.mod b_mod.mod c_mod.mod

MODLIST := $(addprefix $(INSTALL_INC)/,$(MOD_LIST) )


# 
# RULES
#
.PHONY: clean inspector o1 o2 opt pedantic debug

all: $(BUILD_DIR)/libmyexample.so

#
inspector:
    @EXTRA="$(INSPECTOR)" make

#
o1:
    @EXTRA="$(O1)" make

#
o2:
    @EXTRA="$(O2)" make
#
opt:
    @EXTRA="$(OPT)" make

#
pedantic:
    @EXTRA="$(OPT) $(PEDANTIC)" make
#
debug:
    @EXTRA="$(DEBUG)" make
#
install: $(INSTALL_LIB) $(INSTALL_INC) $(INSTALL_LIB)/libmyexample.so

#
uninstall:
    rm $(INSTALL_LIB)/libmyexample.so
    rm $(MODLIST)
#
reinstall: uninstall install
#
doc: $(BUILD_DIR)
    doxygen $(SRC_DIR)/myexample.dxy
    mv warnlog.dxy $(BUILD_DIR)/
#
$(INSTALL_LIB)/libmyexample.so:
    cp $(BUILD_DIR)/libmyexample.so $(INSTALL_LIB)/

#
$(BUILD_DIR)/libmyexample.so: $(OBJECTS)
    $(LDR) -shared -o $@ $(OBJECTS) $(INCDIRS) $(LDFLAGS) 
#
clean:
    rm -f $(BUILD_DIR)/*.o $(BUILD_DIR)/*.mod 
    rm -rf $(BUILD_DIR)
    rm -rf $(DOC_DIR)/html $(DOC_DIR)/latex
#
$(BUILD_DIR)/%.o : %.f90
    $(FC) -o $@ -c $(EXTRA) $(INCDIRS) $(MODDIR) $<
#
$(OBJECTS): | $(BUILD_DIR) $(INSTALL_LIB) $(INSTALL_INC)
#
$(BUILD_DIR):
    mkdir -p $(BUILD_DIR)
#
$(INSTALL_LIB):
    mkdir -p $(INSTALL_LIB)
#
$(INSTALL_INC):
    mkdir -p $(INSTALL_INC)
#

【问题讨论】:

    标签: makefile fortran target fortran90


    【解决方案1】:

    关于您的 makefile 的一些清理说明。

    如果你使用O1/etc. instead ofo1/etc. for the target names (oro1`/等。对于变量名),那么您可以将这些目标清理为:

    PEDANTIC: EXTRA = $(PEDANTIC)
    
    O1 O2 OPT DEBUG PEDANTIC INSPECTOR:
            @$(MAKE) EXTRA="$(EXTRA) $($@)"
    

    这还允许您在原始 make 调用上手动传递额外的 EXTRA 标志(例如 EXTRA=-newoption make O1)。

    此外,底部的所有mkdir 目标可以合并为一个目标:

    $(BUILD_DIR) $(INSTALL_LIB) $(INSTALL_INC):
            mkdir -p $@
    

    至于您问题的主旨,如果您根据标志级别(或其他)设置 BUILD_DIR,那么您将获得所需的内容,并且以后也可以在应用程序链接期间使用正确的目录。

    这样的事情(不是我实际做的,而是一个简单的例子):

    O1 O2 OPT DEBUG PEDANTIC INSPECTOR:
            @$(MAKE) EXTRA="$(EXTRA) $($@)" BUILD_DIR=.$@
    
    .O1 .O2 .OPT .DEBUG .PEDANTIC .INSPECTOR:
            mkdir $@
    

    这将使用目标值覆盖BUILD_DIR 的文件内定义并构建到它们中。

    应用程序目标只需要在链接时将-L$@(或其他)添加到适当的标志。

    【讨论】:

    • 感谢您的想法!那么,@$(MAKE) 本质上是替代我在单个目标中进行的递归调用?我发现这真的很有用,因为我尝试了类似的方法,解析更多变量,但它没有工作,它以@STH="..." not found 错误退出。是不是因为它真的是一个命令行调用,而你的建议做得更好?
    • 你写的我实际上不会这样做,你能详细说明一下吗?我有兴趣学习!
    • 使用 $(MAKE) 会触发 make 的特殊处理。该手册谈到了here
    • 我不会像这样在命令行上覆盖BUILD_DIR,我可能会使用条件来控制makefile本身中的自动定义。我也可能使用OPTLEVEL(或其他)变量来选择要使用的标志,而不是触发递归调用。
    猜你喜欢
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多