#!/bin/bash # # BLIS # An object-based framework for developing high-performance BLAS-like # libraries. # # Copyright (C) 2014, The University of Texas # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # - Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # - Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # - Neither the name of The University of Texas nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # # Makefile # # Field G. Van Zee # # Top-level makefile for libflame linear algebra library. # # # # --- Makefile PHONY target definitions ---------------------------------------- # .PHONY: all libs test install uninstall clean \ check-env check-env-mk check-env-fragments check-env-make-defs \ testsuite testsuite-run testsuite-bin \ install-libs install-headers install-lib-symlinks \ showconfig \ cleanlib distclean cleanmk cleanleaves \ changelog \ uninstall-libs uninstall-headers uninstall-lib-symlinks \ uninstall-old # # --- Makefile initialization -------------------------------------------------- # # The base name of the BLIS library that we will build. BLIS_LIB_BASE_NAME := libblis # Define the name of the configuration file. CONFIG_MK_FILE := config.mk # Define the name of the file containing build and architecture-specific # makefile definitions. MAKE_DEFS_FILE := make_defs.mk # All makefile fragments in the tree will have this name. FRAGMENT_MK := .fragment.mk # Locations of important files. BUILD_DIR := build CONFIG_DIR := config FRAME_DIR := frame OBJ_DIR := obj LIB_DIR := lib TESTSUITE_DIR := testsuite # The names of the testsuite binary executable and related default names # of its input/configuration files. TESTSUITE_NAME := test_$(BLIS_LIB_BASE_NAME) TESTSUITE_CONF_GEN := input.general TESTSUITE_CONF_OPS := input.operations TESTSUITE_OUT_FILE := output.testsuite # The name of the file where the version string is stored. VERSION_FILE := version # The name of the "special" directories, which contain source code that # use non-standard compiler flags. NOOPT_DIR := noopt KERNELS_DIR := kernels # Text strings that alert the user to the fact that special source code is # being compiled. NOOPT_TEXT := "(NOTE: using flags for no optimization)" KERNELS_TEXT := "(NOTE: using flags for kernels)" # CHANGELOG file. CHANGELOG := CHANGELOG # # --- Include makefile configuration file -------------------------------------- # # Include the configuration file. -include $(CONFIG_MK_FILE) # Detect whether we actually got the configuration file. If we didn't, then # it is likely that the user has not yet generated it (via configure). ifeq ($(strip $(CONFIG_MK_INCLUDED)),yes) CONFIG_MK_PRESENT := yes else CONFIG_MK_PRESENT := no endif # Now we have access to CONFIG_NAME, which tells us which sub-directory of the # config directory to use as our configuration. Also using CONFIG_NAME, we # construct the path to the general framework source tree. CONFIG_PATH := $(DIST_PATH)/$(CONFIG_DIR)/$(CONFIG_NAME) FRAME_PATH := $(DIST_PATH)/$(FRAME_DIR) # Construct base paths for the object file tree. BASE_OBJ_PATH := ./$(OBJ_DIR)/$(CONFIG_NAME) BASE_OBJ_CONFIG_PATH := $(BASE_OBJ_PATH)/$(CONFIG_DIR) BASE_OBJ_FRAME_PATH := $(BASE_OBJ_PATH)/$(FRAME_DIR) # Construct base path for the library. BASE_LIB_PATH := ./$(LIB_DIR)/$(CONFIG_NAME) # # --- Include makefile definitions file ---------------------------------------- # # Construct the path to the makefile definitions file residing inside of # the configuration sub-directory. MAKE_DEFS_MK_PATH := $(CONFIG_PATH)/$(MAKE_DEFS_FILE) # Include the makefile definitions file. -include $(MAKE_DEFS_MK_PATH) # Detect whether we actually got the make definitios file. If we didn't, then # it is likely that the configuration is invalid (or incomplete). ifeq ($(strip $(MAKE_DEFS_MK_INCLUDED)),yes) MAKE_DEFS_MK_PRESENT := yes else MAKE_DEFS_MK_PRESENT := no endif # # --- Main target variable definitions ----------------------------------------- # # Construct the architecture-version string, which will be used to name the # library upon installation. VERSION := $(shell cat $(DIST_PATH)/$(VERSION_FILE)) VERS_CONF := $(VERSION)-$(CONFIG_NAME) # --- Library names --- # Note: These names will be modified later to include the configuration and # version strings. BLIS_LIB_NAME := $(BLIS_LIB_BASE_NAME).a #BLIS_DLL_NAME := $(BLIS_LIB_BASE_NAME).so # --- BLIS framework source and object variable names --- # These are the makefile variables that source code files will be accumulated # into by the makefile fragments. Notice that we include separate variables # for regular and "special" source. MK_FRAME_SRC := MK_FRAME_NOOPT_SRC := MK_FRAME_KERNELS_SRC := MK_CONFIG_SRC := MK_CONFIG_NOOPT_SRC := MK_CONFIG_KERNELS_SRC := # These hold object filenames corresponding to above. MK_FRAME_OBJS := MK_FRAME_NOOPT_OBJS := MK_FRAME_KERNELS_OBJS := MK_CONFIG_OBJS := MK_CONFIG_NOOPT_OBJS := MK_CONFIG_KERNELS_OBJS := # Append the base library path to the library name. MK_ALL_BLIS_LIB := $(BASE_LIB_PATH)/$(BLIS_LIB_NAME) # --- Define install target names for static libraries --- MK_BLIS_LIB := $(MK_ALL_BLIS_LIB) MK_BLIS_LIB_INST := $(patsubst $(BASE_LIB_PATH)/%.a, \ $(INSTALL_PREFIX)/lib/%.a, \ $(MK_BLIS_LIB)) MK_BLIS_LIB_INST_W_VERS_CONF := $(patsubst $(BASE_LIB_PATH)/%.a, \ $(INSTALL_PREFIX)/lib/%-$(VERS_CONF).a, \ $(MK_BLIS_LIB)) # --- Determine which libraries to build --- MK_LIBS := MK_LIBS_INST := MK_LIBS_INST_W_VERS_CONF := ifeq ($(BLIS_ENABLE_STATIC_BUILD),yes) MK_LIBS += $(MK_BLIS_LIB) MK_LIBS_INST += $(MK_BLIS_LIB_INST) MK_LIBS_INST_W_VERS_CONF += $(MK_BLIS_LIB_INST_W_VERS_CONF) endif # Strip leading, internal, and trailing whitespace. MK_LIBS_INST := $(strip $(MK_LIBS_INST)) MK_LIBS_INST_W_VERS_CONF := $(strip $(MK_LIBS_INST_W_VERS_CONF)) # Set the include directory names MK_INCL_DIR_INST := $(INSTALL_PREFIX)/include/blis # # --- Include makefile fragments ----------------------------------------------- # # Initialize our list of directory paths to makefile fragments with the empty # list. This variable will accumulate all of the directory paths in which # makefile fragments reside. FRAGMENT_DIR_PATHS := # This variable is used by the include statements as they recursively include # one another. For the framework source tree ('frame' directory), we initialize # it to the top-level directory since that is its parent. PARENT_PATH := $(DIST_PATH) # Recursively include all the makefile fragments in the framework itself. -include $(addsuffix /$(FRAGMENT_MK), $(FRAME_PATH)) # Now set PARENT_PATH to $(DIST_PATH)/config in preparation to include the # fragments in the configuration sub-directory. PARENT_PATH := $(DIST_PATH)/$(CONFIG_DIR) # Recursively include all the makefile fragments in the configuration # sub-directory. -include $(addsuffix /$(FRAGMENT_MK), $(CONFIG_PATH)) # Create a list of the makefile fragments. MAKEFILE_FRAGMENTS := $(addsuffix /$(FRAGMENT_MK), $(FRAGMENT_DIR_PATHS)) # Detect whether we actually got any makefile fragments. If we didn't, then it # is likely that the user has not yet generated them (via configure). ifeq ($(strip $(MAKEFILE_FRAGMENTS)),) MAKEFILE_FRAGMENTS_PRESENT := no else MAKEFILE_FRAGMENTS_PRESENT := yes endif # # --- Compiler include path definitions ---------------------------------------- # # Expand the fragment paths that contain .h files to attain the set of header # files present in all fragment paths. MK_HEADER_FILES := $(foreach frag_path, $(FRAGMENT_DIR_PATHS), \ $(wildcard $(frag_path)/*.h)) # Strip the leading, internal, and trailing whitespace from our list of header # files. This makes the "make install-headers" much more readable. MK_HEADER_FILES := $(strip $(MK_HEADER_FILES)) # Expand the fragment paths that contain .h files, and take the first # expansion. Then, strip the header filename to leave the path to each header # location. Notice this process even weeds out duplicates! Add the config # directory manually since it contains FLA_config.h. MK_HEADER_DIR_PATHS := $(dir $(foreach frag_path, $(FRAGMENT_DIR_PATHS), \ $(firstword $(wildcard $(frag_path)/*.h)))) # Add -I to each header path so we can specify our include search paths to the # C compiler. INCLUDE_PATHS := $(strip $(patsubst %, -I%, $(MK_HEADER_DIR_PATHS))) CFLAGS := $(CFLAGS) $(INCLUDE_PATHS) CFLAGS_NOOPT := $(CFLAGS_NOOPT) $(INCLUDE_PATHS) CFLAGS_KERNELS := $(CFLAGS_KERNELS) $(INCLUDE_PATHS) # # --- Special preprocessor macro definitions ----------------------------------- # # Define a C preprocessor macro to communicate the current version so that it # can be embedded into the library and queried later. VERS_DEF := -DBLIS_VERSION_STRING=\"$(VERSION)\" CFLAGS := $(CFLAGS) $(VERS_DEF) CFLAGS_NOOPT := $(CFLAGS_NOOPT) $(VERS_DEF) CFLAGS_KERNELS := $(CFLAGS_KERNELS) $(VERS_DEF) # # --- Library object definitions ----------------------------------------------- # # Convert source file paths to object file paths by replacing the base source # directories with the base object directories, and also replacing the source # file suffix (eg: '.c') with '.o'. MK_BLIS_FRAME_OBJS := $(patsubst $(FRAME_PATH)/%.c, $(BASE_OBJ_FRAME_PATH)/%.o, \ $(filter %.c, $(MK_FRAME_SRC))) MK_BLIS_FRAME_NOOPT_OBJS := $(patsubst $(FRAME_PATH)/%.c, $(BASE_OBJ_FRAME_PATH)/%.o, \ $(filter %.c, $(MK_FRAME_NOOPT_SRC))) MK_BLIS_FRAME_KERNELS_OBJS := $(patsubst $(FRAME_PATH)/%.c, $(BASE_OBJ_FRAME_PATH)/%.o, \ $(filter %.c, $(MK_FRAME_KERNELS_SRC))) MK_BLIS_CONFIG_OBJS := $(patsubst $(CONFIG_PATH)/%.S, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.S, $(MK_CONFIG_SRC))) MK_BLIS_CONFIG_OBJS += $(patsubst $(CONFIG_PATH)/%.c, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.c, $(MK_CONFIG_SRC))) MK_BLIS_CONFIG_NOOPT_OBJS := $(patsubst $(CONFIG_PATH)/%.S, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.S, $(MK_CONFIG_NOOPT_SRC))) MK_BLIS_CONFIG_NOOPT_OBJS += $(patsubst $(CONFIG_PATH)/%.c, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.c, $(MK_CONFIG_NOOPT_SRC))) MK_BLIS_CONFIG_KERNELS_OBJS := $(patsubst $(CONFIG_PATH)/%.S, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.S, $(MK_CONFIG_KERNELS_SRC))) MK_BLIS_CONFIG_KERNELS_OBJS += $(patsubst $(CONFIG_PATH)/%.c, $(BASE_OBJ_CONFIG_PATH)/%.o, \ $(filter %.c, $(MK_CONFIG_KERNELS_SRC))) # Combine all of the object files into some readily-accessible variables. MK_ALL_BLIS_OPT_OBJS := $(MK_BLIS_CONFIG_OBJS) \ $(MK_BLIS_FRAME_OBJS) MK_ALL_BLIS_NOOPT_OBJS := $(MK_BLIS_CONFIG_NOOPT_OBJS) \ $(MK_BLIS_FRAME_NOOPT_OBJS) MK_ALL_BLIS_KERNELS_OBJS := $(MK_BLIS_CONFIG_KERNELS_OBJS) \ $(MK_BLIS_FRAME_KERNELS_OBJS) MK_ALL_BLIS_OBJS := $(MK_ALL_BLIS_OPT_OBJS) \ $(MK_ALL_BLIS_NOOPT_OBJS) \ $(MK_ALL_BLIS_KERNELS_OBJS) # # --- Test suite definitions --------------------------------------------------- # # The location of the test suite's general and operations-specific # input/configuration files. TESTSUITE_CONF_GEN_PATH := $(DIST_PATH)/$(TESTSUITE_DIR)/$(TESTSUITE_CONF_GEN) TESTSUITE_CONF_OPS_PATH := $(DIST_PATH)/$(TESTSUITE_DIR)/$(TESTSUITE_CONF_OPS) # The locations of the test suite source directory and the local object # directory. TESTSUITE_SRC_PATH := $(DIST_PATH)/$(TESTSUITE_DIR)/src BASE_OBJ_TESTSUITE_PATH := $(BASE_OBJ_PATH)/$(TESTSUITE_DIR) # Convert source file paths to object file paths by replacing the base source # directories with the base object directories, and also replacing the source # file suffix (eg: '.c') with '.o'. MK_TESTSUITE_OBJS := $(patsubst $(TESTSUITE_SRC_PATH)/%.c, \ $(BASE_OBJ_TESTSUITE_PATH)/%.o, \ $(wildcard $(TESTSUITE_SRC_PATH)/*.c)) # The test suite binary executable filename. TESTSUITE_BIN := $(TESTSUITE_NAME).x # # --- Uninstall definitions ---------------------------------------------------- # # This shell command grabs all files named "libblis-*.a" in the installation # directory and then filters out the name of the library archive for the # current version/configuration. We consider this remaining set of libraries # to be "old" and eligible for removal upon running of the uninstall-old # target. UNINSTALL_LIBS := $(shell $(FIND) $(INSTALL_PREFIX)/lib/ -name "$(BLIS_LIB_BASE_NAME)-*.a" 2> /dev/null | $(GREP) -v "$(BLIS_LIB_BASE_NAME)-$(VERS_CONF).a" | $(GREP) -v $(BLIS_LIB_NAME)) # # --- Targets/rules ------------------------------------------------------------ # # --- Primary targets --- all: libs libs: blis-lib test: testsuite install: libs install-libs install-headers install-lib-symlinks uninstall: uninstall-libs uninstall-lib-symlinks uninstall-headers clean: cleanlib cleantest # --- General source code / object code rules --- # Define two functions, each of which takes one argument (an object file # path). The functions determine which CFLAGS and text string are needed to # compile the object file. Note that we match with a preceding forward slash, # so the directory name must begin with the special directory name, but it # can have trailing characters (e.g. 'kernels_x86'). get_cflags_for_obj = $(if $(findstring /$(NOOPT_DIR),$1),$(CFLAGS_NOOPT),\ $(if $(findstring /$(KERNELS_DIR),$1),$(CFLAGS_KERNELS),\ $(CFLAGS))) get_ctext_for_obj = $(if $(findstring /$(NOOPT_DIR),$1),$(NOOPT_TEXT),\ $(if $(findstring /$(KERNELS_DIR),$1),$(KERNELS_TEXT),)) $(BASE_OBJ_FRAME_PATH)/%.o: $(FRAME_PATH)/%.c $(MK_HEADER_FILES) $(MAKE_DEFS_MK_PATH) ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(CC) $(call get_cflags_for_obj,$@) -c $< -o $@ else @echo "Compiling $<" $(call get_ctext_for_obj,$@) @$(CC) $(call get_cflags_for_obj,$@) -c $< -o $@ endif $(BASE_OBJ_CONFIG_PATH)/%.o: $(CONFIG_PATH)/%.[cS] $(MK_HEADER_FILES) $(MAKE_DEFS_MK_PATH) ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(CC) $(call get_cflags_for_obj,$@) -c $< -o $@ else @echo "Compiling $<" $(call get_ctext_for_obj,$@) @$(CC) $(call get_cflags_for_obj,$@) -c $< -o $@ endif # --- Environment check rules --- check-env: check-env-make-defs check-env-fragments check-env-mk check-env-mk: ifeq ($(CONFIG_MK_PRESENT),no) $(error Cannot proceed: config.mk not detected! Run configure first) endif check-env-fragments: check-env-mk ifeq ($(MAKEFILE_FRAGMENTS_PRESENT),no) $(error Cannot proceed: makefile fragments not detected! Run configure first) endif check-env-make-defs: check-env-fragments ifeq ($(MAKE_DEFS_MK_PRESENT),no) $(error Cannot proceed: make_defs.mk not detected! Invalid configuration) endif # --- Static library archiver rules --- blis-lib: check-env $(MK_LIBS) $(MK_ALL_BLIS_LIB): $(MK_ALL_BLIS_OBJS) ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(AR) $(ARFLAGS) $@ $? $(RANLIB) $@ else @echo "Archiving $@" @$(AR) $(ARFLAGS) $@ $? @$(RANLIB) $@ endif # --- Test suite rules --- testsuite: testsuite-run testsuite-bin: check-env $(TESTSUITE_BIN) $(BASE_OBJ_TESTSUITE_PATH)/%.o: $(TESTSUITE_SRC_PATH)/%.c ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(CC) $(CFLAGS) -c $< -o $@ else @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ endif $(TESTSUITE_BIN): $(MK_TESTSUITE_OBJS) $(MK_BLIS_LIB) ifeq ($(FLA_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(LINKER) $(MK_TESTSUITE_OBJS) $(MK_BLIS_LIB) $(LDFLAGS) -o $@ else @echo "Linking $@ against '$(MK_BLIS_LIB) $(LDFLAGS)'" @$(LINKER) $(MK_TESTSUITE_OBJS) $(MK_BLIS_LIB) $(LDFLAGS) -o $@ endif testsuite-run: testsuite-bin ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) ./$(TESTSUITE_BIN) -g $(TESTSUITE_CONF_GEN_PATH) \ -o $(TESTSUITE_CONF_OPS_PATH) \ > $(TESTSUITE_OUT_FILE) else @echo "Running $(TESTSUITE_BIN) with output redirected to '$(TESTSUITE_OUT_FILE)'" @./$(TESTSUITE_BIN) -g $(TESTSUITE_CONF_GEN_PATH) \ -o $(TESTSUITE_CONF_OPS_PATH) \ > $(TESTSUITE_OUT_FILE) endif # --- Install rules --- install-libs: check-env $(MK_LIBS_INST_W_VERS_CONF) install-headers: check-env $(MK_INCL_DIR_INST) $(MK_INCL_DIR_INST): $(MK_HEADER_FILES) $(CONFIG_MK_FILE) ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(INSTALL) -m 0755 -d $(@) $(INSTALL) -m 0644 $(MK_HEADER_FILES) $(@) else @$(INSTALL) -m 0755 -d $(@) @echo "Installing C header files into $(@)/" @$(INSTALL) -m 0644 $(MK_HEADER_FILES) $(@) endif $(INSTALL_PREFIX)/lib/%-$(VERS_CONF).a: $(BASE_LIB_PATH)/%.a $(CONFIG_MK_FILE) ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(INSTALL) -m 0755 -d $(@D) $(INSTALL) -m 0644 $< $@ else @echo "Installing $(@F) into $(INSTALL_PREFIX)/lib/" @$(INSTALL) -m 0755 -d $(@D) @$(INSTALL) -m 0644 $< $@ endif # --- Install-symlinks rules --- install-lib-symlinks: check-env $(MK_LIBS_INST) $(INSTALL_PREFIX)/lib/%.a: $(INSTALL_PREFIX)/lib/%-$(VERS_CONF).a ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) $(SYMLINK) $( $(DIST_PATH)/$(CHANGELOG) # --- Uninstall rules --- uninstall-old: $(UNINSTALL_LIBS) uninstall-libs: check-env ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) - $(RM_F) $(MK_LIBS_INST_W_VERS_CONF) else @echo "Removing $(MK_LIBS_INST_W_VERS_CONF)." @- $(RM_F) $(MK_LIBS_INST_W_VERS_CONF) endif uninstall-lib-symlinks: check-env ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) - $(RM_F) $(MK_LIBS_INST) else @echo "Removing $(MK_LIBS_INST)." @- $(RM_F) $(MK_LIBS_INST) endif uninstall-headers: check-env ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) - $(RM_RF) $(MK_INCL_DIR_INST) else @echo "Removing $(MK_INCL_DIR_INST)/." @- $(RM_RF) $(MK_INCL_DIR_INST) endif $(UNINSTALL_LIBS): check-env ifeq ($(BLIS_ENABLE_VERBOSE_MAKE_OUTPUT),yes) - $(RM_F) $@ else @echo "Removing $(@F) from $(@D)/." @- $(RM_F) $@ endif