# -*- Makefile -*- # # $Id$ # # makefile to configure the C++ Standard library # ######################################################################## # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to you under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # Copyright 1999-2007 Rogue Wave Software, Inc. # ######################################################################## # # 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 ; \ src=$(SRCDIR)/$$fname.cpp; \ [ ! -r $$src ] && fname="NO_$$fname" ; \ grep "_RWSTD_NO_$$sym$$" config.h >/dev/null ; \ if [ $$? -ne 0 ] ; then \ 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="$$fname.o $$fname run RUN=$$fname \ $(LOPT)=$$opts" ; \ 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: