diff --git a/.gitignore b/.gitignore index 1ae3d855a..38905b0e2 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ CONFIG.local .project .cproject .settings +mk/cc.mk diff --git a/CONFIG b/CONFIG index d2fd3a793..bcb39880e 100644 --- a/CONFIG +++ b/CONFIG @@ -37,6 +37,9 @@ CONFIG_DEBUG?=n # Treat warnings as errors (fail the build on any warning). CONFIG_WERROR?=n +# Build with link-time optimization. +CONFIG_LTO?=n + # Build with code coverage instrumentation. CONFIG_COVERAGE?=n diff --git a/Makefile b/Makefile index d2916971e..93cbf29e9 100644 --- a/Makefile +++ b/Makefile @@ -38,17 +38,23 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk DIRS-y += lib test examples app -.PHONY: all clean $(DIRS-y) config.h CONFIG.local +.PHONY: all clean $(DIRS-y) config.h CONFIG.local mk/cc.mk all: $(DIRS-y) clean: $(DIRS-y) + $(Q)rm -f mk/cc.mk $(Q)rm -f config.h app: lib test: lib examples: lib -$(DIRS-y): config.h +$(DIRS-y): mk/cc.mk config.h + +mk/cc.mk: + $(Q)scripts/detect_cc.sh --cc=$(CC) --cxx=$(CXX) --lto=$(CONFIG_LTO) > $@.tmp; \ + cmp -s $@.tmp $@ || mv $@.tmp $@ ; \ + rm -f $@.tmp config.h: CONFIG CONFIG.local scripts/genconfig.py $(Q)python scripts/genconfig.py $(MAKEFLAGS) > $@.tmp; \ diff --git a/configure b/configure index c593fbcc7..18fa97958 100755 --- a/configure +++ b/configure @@ -17,6 +17,7 @@ function usage() echo " --enable-asan Enable address sanitizer" echo " --enable-ubsan Enable undefined behavior sanitizer" echo " --enable-coverage Enable code coverage tracking" + echo " --enable-lto Enable link-time optimization" echo " --with-env=path Use an alternate environment implementation" echo "" echo "Specifying Dependencies:" @@ -67,6 +68,12 @@ for i in "$@"; do --disable-coverage) CONFIG_COVERAGE=n ;; + --enable-lto) + CONFIG_LTO=y + ;; + --disable-lto) + CONFIG_LTO=n + ;; --enable-werror) CONFIG_WERROR=y ;; @@ -139,6 +146,9 @@ fi if [ -n "$CONFIG_COVERAGE" ]; then echo "CONFIG_COVERAGE?=$CONFIG_COVERAGE" >> CONFIG.local fi +if [ -n "$CONFIG_LTO" ]; then + echo "CONFIG_LTO?=$CONFIG_LTO" >> CONFIG.local +fi if [ -n "$CONFIG_ASAN" ]; then echo "CONFIG_ASAN?=$CONFIG_ASAN" >> CONFIG.local fi diff --git a/mk/spdk.common.mk b/mk/spdk.common.mk index 66c524913..479b27dec 100644 --- a/mk/spdk.common.mk +++ b/mk/spdk.common.mk @@ -34,6 +34,8 @@ -include $(SPDK_ROOT_DIR)/CONFIG.local include $(SPDK_ROOT_DIR)/CONFIG +-include $(SPDK_ROOT_DIR)/mk/cc.mk + C_OPT ?= -fno-omit-frame-pointer ifneq ($(V),1) Q ?= @ @@ -54,6 +56,11 @@ ifeq ($(CONFIG_WERROR), y) COMMON_CFLAGS += -Werror endif +ifeq ($(CONFIG_LTO),y) +COMMON_CFLAGS += -flto +LDFLAGS += -flto +endif + COMMON_CFLAGS += -Wformat -Wformat-security COMMON_CFLAGS += -D_GNU_SOURCE @@ -149,7 +156,7 @@ LINK_CXX=\ LIB_C=\ $(Q)echo " LIB $(notdir $@)"; \ rm -f $@; \ - ar crDs $@ $(OBJS) + $(CCAR) crDs $@ $(OBJS) # Clean up generated files listed as arguments plus a default list CLEAN_C=\ diff --git a/scripts/detect_cc.sh b/scripts/detect_cc.sh new file mode 100755 index 000000000..21ccf8214 --- /dev/null +++ b/scripts/detect_cc.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -e + +function err() +{ + echo "$@" >&2 +} + +function usage() +{ + err "Detect compiler and linker versions, generate mk/cc.mk" + err "" + err "Usage: ./detect_cc.sh [OPTION]..." + err "" + err "Defaults for the options are specified in brackets." + err "" + err "General:" + err " -h, --help Display this help and exit" + err " --cc=path C compiler to use" + err " --cxx=path C++ compiler to use" + err " --lto=[y|n] Attempt to configure for LTO" + +} + +CC=cc +CXX=c++ +LTO=n + +for i in "$@"; do + case "$i" in + -h|--help) + usage + exit 0 + ;; + --cc=*) + CC="${i#*=}" + ;; + --cxx=*) + CXX="${i#*=}" + ;; + --lto=*) + LTO="${i#*=}" + ;; + --) + break + ;; + *) + err "Unrecognized option $i" + usage + exit 1 + esac +done + +CC_TYPE=$($CC -v 2>&1 | grep version | awk '{print $1}') +CXX_TYPE=$($CXX -v 2>&1 | grep version | awk '{print $1}') +LD_TYPE=$(ld -v 2>&1 | awk '{print $2}') + +if [ "$CC_TYPE" != "$CXX_TYPE" ]; then + err "C compiler is $CC_TYPE but C++ compiler is $CXX_TYPE" + err "This may result in errors" + exit 1 +fi + +CCAR="ar" +if [ "$LTO" = "y" ]; then + if [ "$CC_TYPE" = "clang" ]; then + if [ "$LD_TYPE" != "gold" ]; then + err "Using LTO with clang requires the gold linker." + exit 1 + fi + CCAR="llvm-ar" + else + CCAR="gcc-ar" + fi +fi + +echo "CC=$CC" +echo "CXX=$CXX" +echo "CCAR=$CCAR"