##--------------------------------------------------------------------- # Makefile for python (supporting multiple versions) ##--------------------------------------------------------------------- Project = python VERSIONERDIR = /usr/local/versioner FIX = $(SRCROOT)/fix DEFAULT = 2.7 VERSIONS = 2.5 2.6 2.7 ORDEREDVERS := $(DEFAULT) $(filter-out $(DEFAULT),$(VERSIONS)) REVERSEVERS := $(filter-out $(DEFAULT),$(VERSIONS)) $(DEFAULT) VERSIONERFLAGS = -std=gnu99 -Wall -mdynamic-no-pic -I$(DSTROOT)$(VERSIONERDIR)/$(Project) -I$(FIX) -framework CoreFoundation RSYNC = rsync -rlpt PWD = $(shell pwd) ifeq ($(MAKECMDGOALS),) MAKECMDGOALS = build endif ifneq ($(filter build install,$(MAKECMDGOALS)),) ifndef DSTROOT ifdef DESTDIR export DSTROOT = $(shell mkdir -p '$(DESTDIR)' && echo '$(DESTDIR)') else export DSTROOT = / endif endif ifndef OBJROOT export OBJROOT = $(shell mkdir -p '$(PWD)/OBJROOT' && echo '$(PWD)/OBJROOT') RSYNC += --exclude=OBJROOT endif ifndef SYMROOT export SYMROOT = $(shell mkdir -p '$(PWD)/SYMROOT' && echo '$(PWD)/SYMROOT') RSYNC += --exclude=SYMROOT endif endif ifndef SRCROOT export SRCROOT = $(PWD) endif ifndef RC_ARCHS export RC_ARCHS = $(shell arch) export RC_$(RC_ARCHS) = YES endif ifndef RC_CFLAGS export RC_CFLAGS = $(foreach A,$(RC_ARCHS),-arch $(A)) $(RC_NONARCH_CFLAGS) endif ifndef RC_NONARCH_CFLAGS export RC_NONARCH_CFLAGS = -pipe endif ifndef RC_ProjectName export RC_ProjectName = $(Project) endif ##--------------------------------------------------------------------- # 6320664 - when the default gcc compiler version changes, the recorded # compiler options for compiler python was originally built with may be # incompatible. So we force python to use a version-specific name for the # compiler, which will be recorded, and used in all subsequent extension # (and other) builds. # # 7215121 - for now, we assume cc and c++ are symbolic links to the # version-specific name of the compiler. If/when this changes, this # fix will have to be redone. ##--------------------------------------------------------------------- export WITH_GCC = $(shell test -L /usr/bin/cc && basename `readlink /usr/bin/cc` || gcc-`gcc -dumpversion | sed -e 's/\([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/'`) export WITH_GXX = $(shell test -L /usr/bin/c++ && basename `readlink /usr/bin/c++` || g++-`g++ -dumpversion | sed -e 's/\([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/'`) ##--------------------------------------------------------------------- # The "strip" perl script, works around a verification error caused by a # UFS bug (stripping a multi-link file breaks the link, and sometimes causes # the wrong file to be stripped/unstripped). By using the "strip" perl script, # it not only causes the correct file to be stripped, but also preserves the # link. # # The cc/gcc scripts take a -no64 argument, which causes 64-bit architectures # to be removed, before calling the real compiler. ##--------------------------------------------------------------------- export PATH:=$(OBJROOT)/bin:$(PATH) TESTOK := -f $(shell echo $(foreach vers,$(VERSIONS),$(OBJROOT)/$(vers)/.ok) | sed 's/ / -a -f /g') include $(MAKEFILEPATH)/CoreOS/ReleaseControl/Common.make VERSIONVERSIONS = $(VERSIONERDIR)/$(Project)/versions VERSIONHEADER = $(VERSIONERDIR)/$(Project)/versions.h VERSIONBINLIST = $(VERSIONERDIR)/$(Project)/usr-bin.list VERSIONMANLIST = $(VERSIONERDIR)/$(Project)/usr-share-man.list VERSIONERFIX = dummy.py scriptvers.ed build:: $(RSYNC) '$(SRCROOT)/' '$(OBJROOT)' ln -sf gcc $(OBJROOT)/bin/$(WITH_GCC) ln -sf gcc $(OBJROOT)/bin/$(WITH_GXX) @set -x && \ for vers in $(VERSIONS); do \ mkdir -p "$(SYMROOT)/$$vers" && \ mkdir -p "$(OBJROOT)/$$vers/DSTROOT" && \ (echo "######## Building $$vers:" `date` '########' > "$(SYMROOT)/$$vers/LOG" 2>&1 && \ TOPSRCROOT='$(SRCROOT)' \ $(MAKE) -C "$(OBJROOT)/$$vers" install \ SRCROOT="$(SRCROOT)/$$vers" \ OBJROOT="$(OBJROOT)/$$vers" \ DSTROOT="$(OBJROOT)/$$vers/DSTROOT" \ SYMROOT="$(SYMROOT)/$$vers" \ RC_ARCHS='$(RC_ARCHS)' >> "$(SYMROOT)/$$vers/LOG" 2>&1 && \ touch "$(OBJROOT)/$$vers/.ok" && \ echo "######## Finished $$vers:" `date` '########' >> "$(SYMROOT)/$$vers/LOG" 2>&1 \ ) & \ done && \ wait && \ install -d $(DSTROOT)$(VERSIONERDIR)/$(Project)/fix && \ (cd $(FIX) && rsync -pt $(VERSIONERFIX) $(DSTROOT)$(VERSIONERDIR)/$(Project)/fix) && \ echo DEFAULT = $(DEFAULT) > $(DSTROOT)$(VERSIONVERSIONS) && \ for vers in $(VERSIONS); do \ echo $$vers >> $(DSTROOT)$(VERSIONVERSIONS) && \ cat $(SYMROOT)/$$vers/LOG && \ rm -f $(SYMROOT)/$$vers/LOG || exit 1; \ done && \ if [ $(TESTOK) ]; then \ $(MAKE) merge; \ else \ echo '#### error detected, not merging'; \ exit 1; \ fi ##--------------------------------------------------------------------- # After the rest of the merge, we need to merge /usr/lib manually. The # problem is that now libpythonN.dylib is ambiguous, and probably best # to just avoid it, and just keep libpythonN.M.dylib. libpython.dylib # will correspond with the default version. ##--------------------------------------------------------------------- MERGELIB = /usr/lib merge: mergebegin mergedefault mergeversions mergeplist mergebin mergeman install -d $(DSTROOT)$(MERGELIB) @set -x && \ for vers in $(VERSIONS); do \ ln -sf ../../System/Library/Frameworks/Python.framework/Versions/$$vers/Python $(DSTROOT)$(MERGELIB)/lib$(Project)$$vers.dylib && \ ln -sf ../../System/Library/Frameworks/Python.framework/Versions/$$vers/lib/$(Project)$$vers $(DSTROOT)$(MERGELIB)/$(Project)$$vers || exit 1; \ done ln -sf lib$(Project)$(DEFAULT).dylib $(DSTROOT)$(MERGELIB)/lib$(Project).dylib mergebegin: @echo ####### Merging ####### MERGEBIN = /usr/bin TEMPWRAPPER = $(MERGEBIN)/.versioner mergebin: $(DSTROOT)$(VERSIONHEADER) $(OBJROOT)/wrappers cc $(RC_CFLAGS) $(VERSIONERFLAGS) $(VERSIONERDIR)/versioner.c -o $(DSTROOT)$(TEMPWRAPPER) @set -x && \ for w in `sort -u $(OBJROOT)/wrappers`; do \ ln -f $(DSTROOT)$(TEMPWRAPPER) $(DSTROOT)$(MERGEBIN)/$$w || exit 1; \ done rm -f $(DSTROOT)$(TEMPWRAPPER) cd $(DSTROOT)$(MERGEBIN) && ls | sort > $(DSTROOT)$(VERSIONBINLIST) DUMMY = dummy.py $(OBJROOT)/wrappers: install -d $(DSTROOT)$(MERGEBIN) install $(FIX)/$(DUMMY) $(DSTROOT)$(MERGEBIN) @set -x && \ touch $(OBJROOT)/wrappers && \ for vers in $(ORDEREDVERS); do \ pbin=/System/Library/Frameworks/Python.framework/Versions/$$vers/bin && \ cd $(DSTROOT)$$pbin && \ if [ -e 2to3 ]; then \ mv 2to3 2to3$$vers && \ ln -s 2to3$$vers 2to3 && \ sed -e 's/@SEP@//g' -e "s/@VERSION@/$$vers/g" $(FIX)/scriptvers.ed | ed - 2to3$$vers; \ fi && \ for f in `find . -type f | sed 's,^\./,,'`; do \ f0=`echo $$f | sed "s/$$vers//"` && \ ln -sf ../..$$pbin/$$f $(DSTROOT)$(MERGEBIN)/$$f && \ if file $$f | head -1 | fgrep -q script; then \ sed -e 's/@SEP@//g' -e "s/@VERSION@/$$vers/g" $(FIX)/scriptvers.ed | ed - $$f && \ if [ ! -e $(DSTROOT)$(MERGEBIN)/$$f0 ]; then \ ln -f $(DSTROOT)$(MERGEBIN)/$(DUMMY) $(DSTROOT)$(MERGEBIN)/$$f0; \ fi; \ else \ echo $$f0 >> $@; \ fi || exit 1; \ done || exit 1; \ done rm -f $(DSTROOT)$(MERGEBIN)/$(DUMMY) $(DSTROOT)$(VERSIONHEADER): @set -x && ( \ echo '#define DEFAULTVERSION "$(DEFAULT)"' && \ echo '#define NVERSIONS (sizeof(versions) / sizeof(const char *))' && \ echo '#define PROJECT "$(Project)"' && \ printf '#define UPROJECT "%s"\n' `echo $(Project) | tr a-z A-Z` && \ echo 'static const char *versions[] = {' && \ touch $(OBJROOT)/versions && \ for vers in $(VERSIONS); do \ echo $$vers >> $(OBJROOT)/versions || exit 1; \ done && \ for vers in `sort -u $(OBJROOT)/versions`; do \ printf ' "%s",\n' $$vers || exit 1; \ done && \ echo '};' ) > $@ MERGEDEFAULT = \ Developer/Examples \ usr/local/OpenSourceLicenses mergedefault: cd $(OBJROOT)/$(DEFAULT)/DSTROOT && rsync -Ra $(MERGEDEFAULT) $(DSTROOT) MERGEMAN = /usr/share/man mergeman: domergeman customman listman # When merging man pages from the multiple versions, allow the man pages # to be compressed (.gz suffix) or not. domergeman: @set -x && \ for vers in $(ORDEREDVERS); do \ cd $(OBJROOT)/$$vers/DSTROOT$(MERGEMAN) && \ for d in man*; do \ cd $$d && \ for f in `find . -type f -name '*.*' | sed 's,^\./,,'`; do \ ff=`echo $$f | sed -E "s/\.[^.]*(.gz)?$$/$$vers&/"` && \ ditto $$f $(DSTROOT)$(MERGEMAN)/$$d/$$ff && \ if [ ! -e $(DSTROOT)$(MERGEMAN)/$$d/$$f ]; then \ ln -fs $$ff $(DSTROOT)$(MERGEMAN)/$$d/$$f; \ fi || exit 1; \ done && \ cd .. || exit 1; \ done || exit 1; \ done # When adding custom python.1 and pythonw.1 man pages, autodetect if we are # compressing man pages, and if so, compress these custom man pages as well CUSTOMTEMP = .temp.1 customman: $(OBJROOT)/wrappers @set -x && \ cp -f $(FIX)/$(Project).1 $(DSTROOT)$(MERGEMAN)/man1/$(CUSTOMTEMP) && \ cd $(DSTROOT)$(MERGEMAN)/man1 && \ suffix='' && \ if ls | grep -q '\.gz$$'; then suffix='.gz'; fi && \ if [ "$${suffix}" ]; then gzip $(CUSTOMTEMP); fi && \ for w in `sort -u $(OBJROOT)/wrappers`; do \ rm -f $${w}.1$${suffix} && \ ln -f $(CUSTOMTEMP)$${suffix} $${w}.1$${suffix} || exit 1; \ done && \ rm -f $(CUSTOMTEMP)$${suffix} listman: cd $(DSTROOT)$(MERGEMAN) && find . ! -type d | sed 's,^\./,,' | sort > $(DSTROOT)$(VERSIONMANLIST) OPENSOURCEVERSIONS = /usr/local/OpenSourceVersions PLIST = $(OPENSOURCEVERSIONS)/$(Project).plist mergeplist: mkdir -p $(DSTROOT)/$(OPENSOURCEVERSIONS) echo '' > $(DSTROOT)/$(PLIST) echo '' >> $(DSTROOT)/$(PLIST) @set -x && \ for vers in $(VERSIONS); do \ sed -e '/^<\/*plist/d' -e '/^<\/*array/d' -e 's/^/ /' $(OBJROOT)/$$vers/DSTROOT/$(PLIST) >> $(DSTROOT)/$(PLIST) || exit 1; \ done echo '' >> $(DSTROOT)/$(PLIST) echo '' >> $(DSTROOT)/$(PLIST) chmod 644 $(DSTROOT)/$(PLIST) MERGEVERSIONSCONDITIONAL = \ Developer/Applications MERGEVERSIONS = \ Library \ usr/include MERGEREVERSEVERSIONS = \ System mergeversions: @set -x && \ for vers in $(VERSIONS); do \ cd $(OBJROOT)/$$vers/DSTROOT && \ rsync -Ra $(MERGEVERSIONS) $(DSTROOT) && \ for c in $(MERGEVERSIONSCONDITIONAL); do \ if [ -e "$$c" ]; then \ rsync -Ra "$$c" $(DSTROOT); \ fi || exit 1; \ done || exit 1; \ done for vers in $(REVERSEVERS); do \ cd $(OBJROOT)/$$vers/DSTROOT && \ rsync -Ra $(MERGEREVERSEVERSIONS) $(DSTROOT) || exit 1; \ done