blob: 1778bd877f8f8e5137fbcb308ad413bca11ac4a6 [file] [log] [blame]
# -*- Makefile -*-
#
# $Id$
#
# makefile to configure the C++ Standard library
#
##############################################################################
#
# Creates a C++ header file, config.h, containing a list of (possibly
# commented out) preprocessor #defines in the form _RWSTD_NO_XXX,
# where the XXX is the file name part (w/o the extension) of XXX.cpp
# (some C or C++ program)
#
# Files named NO_XXX.cpp are assumed to be negative tests, which are
# considered successful unless they exit with zero status, in which
# case they are considered failed and the corresponding macro,
# _RWSTD_NO_XXX, is #defined.
#
# Each test named XXX.lib.cpp is translated into a static or dynamic
# library (depending on the presence of shared in BUILDMODE variable),
# and may be linked into other executables. To link a library into an
# executable the name of the library must be mentioned in LDOPTS
# somewhere in the executable's source.
#
# XXX.cpp can but doesn't need to contain main(). If it doesn't, the
# macro _RWSTD_NO_XXX will be commented out in config.h iff XXX.cpp
# successfully compiles.
#
# If XXX.cpp contains main(), _RWSTD_NO_XXX will be commented out iff
# XXX.cpp not only successfully compiles, but also links and runs.
#
# Any output produced by the executable XXX obtained by compiling and
# linking XXX.cpp is appended to the end of config.h.
#
##############################################################################
include ../makefile.in
SRCDIR = $(TOPDIR)/etc/config/src
VPATH = $(SRCDIR)
CPPFLAGS += -I.
CPPFLAGS := $(filter-out -I$(TOPDIR)/include/ansi,$(CPPFLAGS))
CXXFLAGS += $(WARNFLAGS)
# get a sorted list of config tests, starting with any shell scripts
# with the .sh suffix, followed by C++ (.cpp) programs
SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.sh)))
SRCS += $(sort $(notdir $(wildcard $(SRCDIR)/*.cpp)))
OBJS := $(SRCS:.cpp=.o)
TARGET := $(SRCS:.cpp=)
PWD := $(shell pwd)
DASH_H = -H
CCNAME = $(CXX)-$(CCVER)
LOGFILE = config.log
# can't use LDOPTS when working with HP aCC, it's used by the linker
ifneq ($(CXX),aCC)
LOPT = LDOPTS
LDFLAGS += $(LDOPTS)
else
LOPT = _LDOPTS
LDFLAGS += $(_LDOPTS)
endif
# append $(LDLIBS) last, after $(LDOPTS), since the latter may depend
# on the former being after it on the link line
LDFLAGS += -lm $(LDLIBS)
# CXXPRELINK - command for compilers that use template
# instantiation models that require a prelink stage
ifneq ($(PRELINKFLAGS),)
CXXPRELINK = $(CXX) $(CPPFLAGS) $(LDFLAGS) $(PRELINKFLAGS)
endif # ($(PRELINKFLAGS),)
# helper function to compile a file and log results
# arguments:
# $(1): source file name
# $(2): object file name
# $(3): additional compiler flags (optional)
define compile
command="$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(3) -c $(1) -o $(2)"; \
echo "$$command" >>$(LOGFILE); \
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(3) -c $(1) -o $(2) >>$(LOGFILE) 2>&1
endef
# helper function to link a file and log results
# arguments:
# $(1): object file name
# $(2): executable file name
# $(3): additional linker flags (optional)
define link
command="$(LD) $(1) $(LDFLAGS) $(3) -o $(2)"; \
echo "$$command" >>$(LOGFILE); \
$(LD) $(1) $(LDFLAGS) $(3) -o $(2) >>$(LOGFILE) 2>&1
endef
# helper function to compile and link a file and log results
# arguments:
# $(1): source file name
# $(2): object file name
# $(3): executable file name
# $(4): additional compiler flags (optional)
# $(5): additional linker flags (optional)
define compile_then_link
command="$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(4) -c $(1) -o $(2)" \
"&& $(LD) $(2) $(LDFLAGS) $(5) -o $(3)"; \
echo "$$command" >>$(LOGFILE); \
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(4) -c $(1) -o $(2) >>$(LOGFILE) 2>&1 \
&& $(LD) $(2) $(LDFLAGS) $(5) -o $(3) >>$(LOGFILE) 2>&1
endef
# helper function to prelink a file and log results
# arguments:
# $(1): source file name
# $(2): object file name
define prelink
command="$(CXXPRELINK) $(1) -o $(2)"; \
echo "$$command" >>$(LOGFILE); \
$(CXXPRELINK) $(1) -o $(2) >>$(LOGFILE)
endef
# helper function to create an archive out of an object file
define archive
command="$(AR) $(ARFLAGS) $(1) $(2)"; \
echo "$$command" >>$(LOGFILE); \
$(AR) $(ARFLAGS) $(1) $(2) >>$(LOGFILE)
endef
##############################################################################
# TARGETS
##############################################################################
all: config.h
# recreate config.h and update its timestamp
config.h: $(SRCS)
$(MAKE) config
touch config.h
# (re)create config.h; do not change timestamp if the new file is the same
# make .o first to make sure the %.o: %.cpp rule gets invoked (make bug?)
# run a configure script as the last step (e.g., to remove unwanted files)
# creates a file named vars.sh, containing shell assignments corresponding
# to makefile variables defined in $(BUILDDIR)/makefile.in (variables with
# invalid names (those containing periods) are commented out); vars.sh is
# used in libc_decl.sh to invoke the compiler and linker
config: clean sane
@([ -f config.h ] && mv config.h config.h.~ ; \
echo "// configured for $(CCNAME) on `uname -sr`" >config.h ; \
for file in $(TARGET) ; do \
src=$(SRCDIR)/$$file.cpp; \
desc=`head -n 1 2>/dev/null $$src | sed "s:// *::"`; \
[ "$$desc" != "" ] && printf "%-50.50s " "$$desc"; \
grep "[^a-zA-Z0-9_]*main *(" $$src >/dev/null 2>&1 ; \
if [ $$? -eq 0 ] ; then \
opts=`sed -n "s/^[^A-Z_a-z0-9]*LDOPTS *= *\(.*\)/\1/p" \
$$src`; \
targets="$$file.o $$file run RUN=$$file $(LOPT)=$$opts"; \
elif [ `echo $$file | grep "\.lib"` ] ; then \
targets="$$file$(LIBSUFFIX)" ; \
elif [ `echo $$file | grep "\.sh"` ] ; then \
if [ ! -f vars.sh ] ; then \
cat ../makefile.in \
| sed -e "s/= *\([^ ][^ ]* .*\)/=\"\1\"/" \
-e "s/^\( *[^=]*\.[^=]*=.*\)/# \1/" \
-e "s/^\([^ ]*\) *= *\(.*\)/\1=\2 ; export \1/" \
-e 's/$$(\([^)]*\))/${\1}/g' >vars.sh ; \
fi ; \
$(SRCDIR)/$$file config.h $(LOGFILE) ; \
echo ; \
continue ; \
else \
targets="$$file.o run RUN=$$file.o" ; \
fi; \
$(MAKE) $$targets OUTPUT=config.h -k >/dev/null 2>&1 ; \
if [ "$$desc" != "" ] ; then \
sym="_RWSTD_" ; \
echo $$file | grep "^NO_" >/dev/null ; \
[ $$? -ne 0 ] && sym="$${sym}NO_" ; \
str=`sed -n "s/\(.*\)\(#\)define $$sym$$file$$/\1\2/p" \
config.h`; \
if [ "$$str" = "// #" ] ; then \
echo "ok"; \
elif [ "$$str" = "#" ] ; then \
echo "no ($$sym$$file)"; \
else \
echo "--" ; \
fi; \
fi; \
done; \
diff config.h config.h.~ >/dev/null 2>&1 ; \
if [ $$? -eq 0 ] ; then \
mv config.h.~ config.h ; \
echo "config.h unchanged"; \
elif [ -f config.h~ ] ; then \
echo "previous config.h saved in config.h~"; \
fi; \
[ -x ./configure ] && ./configure -f ./config.h -d $(TOPDIR) ; \
exit 0)
# run one or more (perhaps all) executables in $(RUN) or $(TARGET) if
# the former is not defined; if an executable doesn't exist and the .o
# doesn't contain main it is still considered success (this is needed
# when the run target is invoked from within the %.o: %.cpp pattern rule
# .o's are not run (obviously) and are just assumed to be the result of
# a successful compilation
run:
@(output=$(OUTPUT) ; \
[ "$$output" = "" ] && output=/dev/tty ; \
target=$(RUN) ; \
[ "$$target" = "" ] && target=$(TARGET) ; \
for file in $$target ; do \
symbol="#define _RWSTD_" ; \
basename $$file | grep "^NO_" >/dev/null 2>&1 ; \
neg=$$? ; \
[ $$neg -ne 0 ] && symbol="$${symbol}NO_" ; \
symbol="$${symbol}`echo $$file \
| sed -e 's:.*/::' -e 's/\.o//'`"; \
if [ `echo $$file | grep "\.o"` ] ; then \
test -r $$file ; \
elif [ ! -x $$file ] ; then \
nm -gp $$file.o 2>&1 | grep "T *main *$$" >/dev/null ; \
test -f $$file.o -a ! $$? -eq 0 ; \
else \
echo "./$$file" >>$(LOGFILE) ; \
LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:. ; \
LIBPATH=$$LIBPATH:. ; \
export LIBPATH LD_LIBRARY_PATH ; \
text=`./$$file` ; \
fi; \
res=$$? ; \
[ $$res -eq 0 -a $$neg -ne 0 ] \
|| [ $$res -ne 0 -a $$neg -eq 0 ] && symbol="// $$symbol" ;\
grep "$$symbol$$" config.h ; \
if [ $$? -ne 0 ] ; then \
echo "$$symbol" >>$$output; \
if [ "$$text" != "" ]; then \
printf "%s\n" "$$text" >>$$output; \
fi; \
fi; \
done; \
exit 0)
# determine the type of architecture (LP32, ILP32, ILP64, LLP64, or LP64)
arch:
@(output=$(OUTPUT); \
[ "$$output" = "" ] && output=/dev/tty ; \
for type in int long "long long" "void*" ; do \
echo "int main () { return sizeof ($$type); }" \
| tee a.cpp >>$(LOGFILE) ; \
$(call compile_then_link,a.cpp,a.o,a.out); \
if [ $$? -eq 0 ] ; then \
size="$$size`./a.out ; echo $$?`" ; \
else \
size="$${size}-"; \
fi; \
done; \
case "$$size" in \
24?4 ) arch="LP32" ;; 44?4 ) arch="ILP32" ;; \
88?8 ) arch="ILP64" ;; 4488 ) arch="LLP64" ;; \
48?8 ) arch="LP64" ;; * ) arch="$$size" ;; \
esac ; \
echo "int main () { int i = 1; return *(char*)&i; }" \
| tee a.cpp >>$(LOGFILE) ; \
$(call compile_then_link,a.cpp,a.o,a.out); \
if [ $$? -eq 0 ] ; then \
endian=" little endian" ; \
./a.out ; \
[ $$? -eq 0 ] && endian=" big endian" ; \
else \
echo "error"; \
cat $(LOGFILE); \
exit 1; \
fi; \
echo "$$arch$$endian" >$$output ; \
)
# check compiler, linker, and run environment's sanity, determine
# system (or compiler) architecture (word size, address size, etc.)
sane:
@(echo; \
echo "configuring stdcxx $(LIBVER) for $(CCNAME) on $(PLATFORM)"; \
echo; \
rm -f a.out ; \
echo "int main () { return 0; }" | tee a.cpp >>$(LOGFILE) ; \
printf "%-50.50s " "checking if the compiler is sane"; \
$(call compile,a.cpp,a.o); \
if [ $$? -eq 0 ] ; then \
echo "ok (invoked with $(CXX))"; \
else \
echo "no"; echo; \
cat $(LOGFILE) ; \
exit 1; \
fi; \
printf "%-50.50s " "checking if the linker is sane"; \
$(call link,a.o,a.out); \
if [ $$? -eq 0 ] ; then \
echo "ok (invoked with $(LD))"; \
else \
echo "no"; echo; \
cat $(LOGFILE) ; \
exit 1; \
fi; \
printf "%-50.50s " "checking system architecture"; \
`$(MAKE) arch OUTPUT=a.cpp>/dev/null 2>&1` ; \
cat a.cpp ; \
rm a.cpp )
clean:
@rm -f a.out core *.o *.i *.ii *.ti vars.sh \
*$(LIBSUFFIX) $(TARGET)
realclean: clean
rm -f *.d *.o *.a *.so a.cpp
listtarget:
@echo $(TARGET)
.PHONY: all clean config configure c_headers listtarget realclean run
##############################################################################
# COMMON RULES
##############################################################################
#empty rule for .cc files so they won't be separately compiled
%: %.cc ;
# compile .cpp so that any macros used by the translation unit are configured
# checks config.h to make sure macro isn't yet defined before going recursive
# *.lib.cpp files a compiled (and linked) into libraries (shared or static)
# with LDOPTS reset to the empty string
%.o: %.cpp
@(dep=`egrep "^ *# *if[n]*def *_RWSTD_" $< \
| sed -e "s/.*# *if[n]*def *\([^ ]*\) */\1/g" \
-e "s/_RWSTD_NO_//g" -e "s/_RWSTD_//g"` ; \
for sym in $$dep ; do \
fname=$$sym ; \
[ ! -r $(SRCDIR)/$$fname.cpp ] && fname="NO_$$fname" ; \
grep "_RWSTD_NO_$$sym$$" config.h >/dev/null ; \
if [ $$? -ne 0 ] ; then \
grep "[^a-zA-Z0-9_]*main *(" $(SRCDIR)/$$fname.cpp \
>/dev/null 2>&1 ; \
if [ $$? -eq 0 ] ; then \
targets="$$fname.o $$fname run RUN=$$fname" ; \
elif [ `echo $$fname | grep "\.lib"` ] ; then \
targets="$$fname$(LIBSUFFIX) $(LOPT)=" ; \
else \
targets="$$fname.o run RUN=$$fname.o" ; \
fi; \
$(MAKE) $$targets OUTPUT=config.h -k ; \
fi; \
done; \
true)
$(call compile,$<,$@)
# remove .o to prevent the run target from getting confused
%: %.o
$(call link,$^,$@); rm $<
# build a library from any source file named *.lib.cpp
%.lib$(LIBSUFFIX): %.lib.cpp
ifeq ($(findstring shared,$(BUILDMODE)),shared)
$(call compile,$<,$@.o,$(PICFLAGS))
ifeq ($(findstring xlC,$(CXX)),xlC)
# IBM xlC first "preprocesses" .o's with -qmkshrobj
# and then uses `ar' to create a shared library...
$(call prelink,$@.o,@.lib.o)
$(call archive,$@,$@.lib.o)
else
$(call link,$@.o,$@,$(LDSOFLAGS))
endif
else
$(call compile,$<,$@.o)
$(call archive,$@,$@.o)
endif
# parallelization of the configuration infrastructure not supported
.NOTPARALLEL: