chris
chris

Reputation: 317

How do I write a makefile for multiple variants of the same library/executable?

I am using Intel's ifort and GNU make to build my project on a linux machine. The lib depends on the source files a.f90, b.f90 and c.f90 in the source directory.

I am invoking make via

make FLAG

where these FLAGS are defined in my makefile and correspond to different optimization flags for the compiler.

  1. I want my makefile to create a new subdirectory for each flag, so that I can compile different targets at once or after another without having to delete the other one first. How can this be done?

  2. Later, after my library is compiled, I would like to link my executable to a specific variant of that library, so I have to tell the makefile of the executable, which variant it should take. How do I do that in a maintainable way?

Example of my makefile up to now:

#
# 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)
#

Upvotes: 1

Views: 675

Answers (1)

Etan Reisner
Etan Reisner

Reputation: 80931

A few cleanup notes on your makefile.

If you use O1/etc. instead ofo1/etc. for the target names (oro1`/etc. for the variable names) then you can clean up those targets to just this:

PEDANTIC: EXTRA = $(PEDANTIC)

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

This also lets you pass additional EXTRA flags on the original make invocation manually (e.g. EXTRA=-newoption make O1).

Additionally all the mkdir targets at the bottom can be combined into a single target:

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

As to the main thrust of your question if you set the BUILD_DIR based on the flag-level (or whatever) then you get what you want and can use the correct directory during application linking later as well.

Something like this (not how I would actually do it but will work for a simple example):

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

.O1 .O2 .OPT .DEBUG .PEDANTIC .INSPECTOR:
        mkdir $@

That will override the in-file definition of BUILD_DIR with the value of the target and build into them.

The the application target just needs to add -L$@ (or whatever) to the appropriate flags when linking.

Upvotes: 1

Related Questions