1##--------------------------------------------------------------------- 2# Makefile for python (supporting multiple versions) 3##--------------------------------------------------------------------- 4Project = python 5VERSIONERDIR = /usr/local/versioner 6# Look for /usr/local/versioner in $(SDKROOT), defaulting to /usr/local/versioner 7SDKVERSIONERDIR := $(or $(wildcard $(SDKROOT)$(VERSIONERDIR)),$(VERSIONERDIR)) 8FIX = $(SRCROOT)/fix 9DEFAULT = 2.7 10KNOWNVERSIONS = 2.6 2.7 11BOOTSTRAPPYTHON = 12VERSIONS = $(sort $(KNOWNVERSIONS) $(BOOTSTRAPPYTHON)) 13ORDEREDVERS := $(DEFAULT) $(filter-out $(DEFAULT),$(VERSIONS)) 14REVERSEVERS := $(filter-out $(DEFAULT),$(VERSIONS)) $(DEFAULT) 15 16PYFRAMEWORK = /System/Library/Frameworks/Python.framework 17PYFRAMEWORKVERSIONS = $(PYFRAMEWORK)/Versions 18VERSIONERFLAGS = -std=gnu99 -Wall -mdynamic-no-pic -I$(DSTROOT)$(VERSIONERDIR)/$(Project) -I$(FIX) -framework CoreFoundation 19 20RSYNC = rsync -rlpt 21PWD = $(shell pwd) 22 23ifeq ($(MAKECMDGOALS),) 24MAKECMDGOALS = build 25endif 26ifneq ($(filter build install,$(MAKECMDGOALS)),) 27ifndef DSTROOT 28ifdef DESTDIR 29export DSTROOT = $(shell mkdir -p '$(DESTDIR)' && echo '$(DESTDIR)') 30else 31export DSTROOT = / 32endif 33endif 34ifndef OBJROOT 35export OBJROOT = $(shell mkdir -p '$(PWD)/OBJROOT' && echo '$(PWD)/OBJROOT') 36RSYNC += --exclude=OBJROOT 37endif 38ifndef SYMROOT 39export SYMROOT = $(shell mkdir -p '$(PWD)/SYMROOT' && echo '$(PWD)/SYMROOT') 40RSYNC += --exclude=SYMROOT 41endif 42endif 43 44ifndef SRCROOT 45export SRCROOT = $(PWD) 46endif 47ifndef RC_ARCHS 48export RC_ARCHS = $(shell arch) 49export RC_$(RC_ARCHS) = YES 50endif 51ifndef RC_CFLAGS 52export RC_CFLAGS = $(foreach A,$(RC_ARCHS),-arch $(A)) $(RC_NONARCH_CFLAGS) 53endif 54ifndef RC_NONARCH_CFLAGS 55export RC_NONARCH_CFLAGS = -pipe 56endif 57ifndef RC_ProjectName 58export RC_ProjectName = $(Project) 59endif 60##--------------------------------------------------------------------- 61# Before, we used the versioned gcc (e.g., gcc-4.2) because newer compiler 62# would occasionally be incompatible with the compiler flags that python 63# records. With clang, it doesn't use names with versions, so we just go 64# back to using plain cc and c++. With 11952207, we will automatically 65# get xcrun support. 66##--------------------------------------------------------------------- 67export MY_CC = cc 68export MY_CXX = c++ 69 70##--------------------------------------------------------------------- 71# The "strip" perl script, works around a verification error caused by a 72# UFS bug (stripping a multi-link file breaks the link, and sometimes causes 73# the wrong file to be stripped/unstripped). By using the "strip" perl script, 74# it not only causes the correct file to be stripped, but also preserves the 75# link. 76# 77# The cc/c++ scripts take a -no64 argument, which causes 64-bit architectures 78# to be removed, before calling the real compiler. 79##--------------------------------------------------------------------- 80export PATH:=$(OBJROOT)/bin:$(PATH) 81 82TESTOK := -f $(shell echo $(foreach vers,$(VERSIONS),$(OBJROOT)/$(vers)/.ok) | sed 's/ / -a -f /g') 83 84include $(MAKEFILEPATH)/CoreOS/ReleaseControl/Common.make 85 86VERSIONVERSIONS = $(VERSIONERDIR)/$(Project)/versions 87VERSIONHEADER = $(VERSIONERDIR)/$(Project)/versions.h 88VERSIONBINLIST = $(VERSIONERDIR)/$(Project)/usr-bin.list 89VERSIONMANLIST = $(VERSIONERDIR)/$(Project)/usr-share-man.list 90VERSIONERFIX = dummy.py scriptvers.ed 91build:: 92 $(RSYNC) '$(SRCROOT)/' '$(OBJROOT)' 93 ln -sf _no64 $(OBJROOT)/bin/$(MY_CC) 94 ln -sf _no64 $(OBJROOT)/bin/$(MY_CXX) 95 @set -x && \ 96 for vers in $(VERSIONS); do \ 97 mkdir -p "$(SYMROOT)/$$vers" && \ 98 mkdir -p "$(OBJROOT)/$$vers/DSTROOT" && \ 99 (echo "######## Building $$vers:" `date` '########' > "$(SYMROOT)/$$vers/LOG" 2>&1 && \ 100 { [ "$$vers" != $(DEFAULT) ] || export PYTHON_DEFAULT=YES; } && \ 101 TOPSRCROOT='$(SRCROOT)' \ 102 $(MAKE) -C "$(OBJROOT)/$$vers" install \ 103 SRCROOT="$(SRCROOT)/$$vers" \ 104 OBJROOT="$(OBJROOT)/$$vers" \ 105 DSTROOT="$(OBJROOT)/$$vers/DSTROOT" \ 106 SYMROOT="$(SYMROOT)/$$vers" \ 107 RC_ARCHS='$(RC_ARCHS)' >> "$(SYMROOT)/$$vers/LOG" 2>&1 && \ 108 touch "$(OBJROOT)/$$vers/.ok" && \ 109 echo "######## Finished $$vers:" `date` '########' >> "$(SYMROOT)/$$vers/LOG" 2>&1 \ 110 ) & \ 111 done && \ 112 wait && \ 113 install -d $(DSTROOT)$(VERSIONERDIR)/$(Project)/fix && \ 114 (cd $(FIX) && rsync -pt $(VERSIONERFIX) $(DSTROOT)$(VERSIONERDIR)/$(Project)/fix) && \ 115 echo DEFAULT = $(DEFAULT) > $(DSTROOT)$(VERSIONVERSIONS) && \ 116 for vers in $(KNOWNVERSIONS); do \ 117 echo $$vers >> $(DSTROOT)$(VERSIONVERSIONS) || exit 1; \ 118 done && \ 119 for vers in $(VERSIONS); do \ 120 cat $(SYMROOT)/$$vers/LOG && \ 121 rm -f $(SYMROOT)/$$vers/LOG || exit 1; \ 122 done && \ 123 if [ $(TESTOK) ]; then \ 124 $(MAKE) merge; \ 125 else \ 126 echo '#### error detected, not merging'; \ 127 exit 1; \ 128 fi 129 130merge: mergebegin mergedefault mergeversions mergeplist mergebin mergeman fixsmptd legacySymLinks 131 132mergebegin: 133 @echo ####### Merging ####### 134 135MERGEBIN = /usr/bin 136TEMPWRAPPER = $(MERGEBIN)/.versioner 137mergebin: $(DSTROOT)$(VERSIONHEADER) $(OBJROOT)/wrappers 138 cc $(RC_CFLAGS) $(VERSIONERFLAGS) $(SDKVERSIONERDIR)/versioner.c -o $(DSTROOT)$(TEMPWRAPPER) 139 @set -x && \ 140 for w in `sort -u $(OBJROOT)/wrappers`; do \ 141 ln -f $(DSTROOT)$(TEMPWRAPPER) $(DSTROOT)$(MERGEBIN)/$$w || exit 1; \ 142 done 143 rm -f $(DSTROOT)$(TEMPWRAPPER) 144 cd $(DSTROOT)$(MERGEBIN) && ls | sort > $(DSTROOT)$(VERSIONBINLIST) 145 146DUMMY = dummy.py 147$(OBJROOT)/wrappers: 148 install -d $(DSTROOT)$(MERGEBIN) 149 install $(FIX)/$(DUMMY) $(DSTROOT)$(MERGEBIN) 150 @set -x && \ 151 touch $(OBJROOT)/wrappers && \ 152 for vers in $(ORDEREDVERS); do \ 153 pbin=$(PYFRAMEWORKVERSIONS)/$$vers/bin && \ 154 cd $(DSTROOT)$$pbin && \ 155 if [ -e 2to3 ]; then \ 156 mv 2to3 2to3$$vers && \ 157 ln -s 2to3$$vers 2to3 && \ 158 sed -e 's/@SEP@//g' -e "s/@VERSION@/$$vers/g" $(FIX)/scriptvers.ed | ed - 2to3$$vers; \ 159 fi && \ 160 for f in `find . -type f | sed 's,^\./,,'`; do \ 161 f0=`echo $$f | sed "s/$$vers//"` && \ 162 ln -sf ../..$$pbin/$$f $(DSTROOT)$(MERGEBIN)/$$f && \ 163 if file $$f | head -1 | fgrep -q script; then \ 164 sed -e 's/@SEP@//g' -e "s/@VERSION@/$$vers/g" $(FIX)/scriptvers.ed | ed - $$f && \ 165 if [ ! -e $(DSTROOT)$(MERGEBIN)/$$f0 ]; then \ 166 ln -f $(DSTROOT)$(MERGEBIN)/$(DUMMY) $(DSTROOT)$(MERGEBIN)/$$f0; \ 167 fi; \ 168 else \ 169 echo $$f0 >> $@; \ 170 fi || exit 1; \ 171 done || exit 1; \ 172 done 173 rm -f $(DSTROOT)$(MERGEBIN)/$(DUMMY) 174 175$(DSTROOT)$(VERSIONHEADER): 176 @set -x && ( \ 177 echo '#define DEFAULTVERSION "$(DEFAULT)"' && \ 178 echo '#define NVERSIONS (sizeof(versions) / sizeof(const char *))' && \ 179 echo '#define PROJECT "$(Project)"' && \ 180 printf '#define UPROJECT "%s"\n' `echo $(Project) | tr a-z A-Z` && \ 181 echo 'static const char *versions[] = {' && \ 182 touch $(OBJROOT)/versions && \ 183 for vers in $(VERSIONS); do \ 184 echo $$vers >> $(OBJROOT)/versions || exit 1; \ 185 done && \ 186 for vers in `sort -u $(OBJROOT)/versions`; do \ 187 printf ' "%s",\n' $$vers || exit 1; \ 188 done && \ 189 echo '};' ) > $@ 190 191MERGEDEFAULT = \ 192 usr/local/OpenSourceLicenses 193mergedefault: 194 cd $(OBJROOT)/$(DEFAULT)/DSTROOT && rsync -Ra $(MERGEDEFAULT) $(DSTROOT) 195 196MERGEMAN = /usr/share/man 197mergeman: domergeman customman listman 198 199# When merging man pages from the multiple versions, allow the man pages 200# to be compressed (.gz suffix) or not. 201domergeman: 202 @set -x && \ 203 for vers in $(ORDEREDVERS); do \ 204 cd $(OBJROOT)/$$vers/DSTROOT$(MERGEMAN) && \ 205 for d in man*; do \ 206 cd $$d && \ 207 for f in `find . -type f -name '*.*' | sed 's,^\./,,'`; do \ 208 ff=`echo $$f | sed -E "s/\.[^.]*(.gz)?$$/$$vers&/"` && \ 209 ditto $$f $(DSTROOT)$(MERGEMAN)/$$d/$$ff && \ 210 if [ ! -e $(DSTROOT)$(MERGEMAN)/$$d/$$f ]; then \ 211 ln -fs $$ff $(DSTROOT)$(MERGEMAN)/$$d/$$f; \ 212 fi || exit 1; \ 213 done && \ 214 cd .. || exit 1; \ 215 done || exit 1; \ 216 done 217 218# When adding custom python.1 and pythonw.1 man pages, autodetect if we are 219# compressing man pages, and if so, compress these custom man pages as well 220CUSTOMTEMP = .temp.1 221customman: $(OBJROOT)/wrappers 222 @set -x && \ 223 cp -f $(FIX)/$(Project).1 $(DSTROOT)$(MERGEMAN)/man1/$(CUSTOMTEMP) && \ 224 cd $(DSTROOT)$(MERGEMAN)/man1 && \ 225 suffix='' && \ 226 if ls | grep -q '\.gz$$'; then suffix='.gz'; fi && \ 227 if [ "$${suffix}" ]; then gzip $(CUSTOMTEMP); fi && \ 228 for w in `sort -u $(OBJROOT)/wrappers`; do \ 229 rm -f $${w}.1$${suffix} && \ 230 ln -f $(CUSTOMTEMP)$${suffix} $${w}.1$${suffix} || exit 1; \ 231 done && \ 232 rm -f $(CUSTOMTEMP)$${suffix} 233 234listman: 235 cd $(DSTROOT)$(MERGEMAN) && find . ! -type d | sed 's,^\./,,' | sort > $(DSTROOT)$(VERSIONMANLIST) 236 237OPENSOURCEVERSIONS = /usr/local/OpenSourceVersions 238PLIST = $(OPENSOURCEVERSIONS)/$(Project).plist 239mergeplist: 240 mkdir -p $(DSTROOT)/$(OPENSOURCEVERSIONS) 241 echo '<plist version="1.0">' > $(DSTROOT)/$(PLIST) 242 echo '<array>' >> $(DSTROOT)/$(PLIST) 243 @set -x && \ 244 for vers in $(VERSIONS); do \ 245 sed -e '/^<\/*plist/d' -e '/^<\/*array/d' -e 's/^/ /' $(OBJROOT)/$$vers/DSTROOT/$(PLIST) >> $(DSTROOT)/$(PLIST) || exit 1; \ 246 done 247 echo '</array>' >> $(DSTROOT)/$(PLIST) 248 echo '</plist>' >> $(DSTROOT)/$(PLIST) 249 chmod 644 $(DSTROOT)/$(PLIST) 250 251MERGEVERSIONSCONDITIONAL = \ 252 Developer/Applications 253MERGEVERSIONS = \ 254 Library \ 255 usr/include \ 256 usr/lib 257MERGEREVERSEVERSIONS = \ 258 System 259mergeversions: 260 @set -x && \ 261 for vers in $(VERSIONS); do \ 262 cd $(OBJROOT)/$$vers/DSTROOT && \ 263 rsync -Ra $(MERGEVERSIONS) $(DSTROOT) && \ 264 for c in $(MERGEVERSIONSCONDITIONAL); do \ 265 if [ -e "$$c" ]; then \ 266 rsync -Ra "$$c" $(DSTROOT); \ 267 fi || exit 1; \ 268 done || exit 1; \ 269 done 270 for vers in $(REVERSEVERS); do \ 271 cd $(OBJROOT)/$$vers/DSTROOT && \ 272 rsync -Ra $(MERGEREVERSEVERSIONS) $(DSTROOT) || exit 1; \ 273 done 274 275fixsmptd: 276 set -x && \ 277 cd $(DSTROOT)/usr/bin && \ 278 mv -f smtpd.py smtpd.py.bak && \ 279 cp -pf smtpd.py.bak smtpd.py && \ 280 rm -f smtpd.py.bak && \ 281 for i in smtpd*.py; do \ 282 ed - $$i < $(FIX)/smtpd.py.ed || exit 1; \ 283 done 284 285# We're symlinking 2.3 and 2.5 to 2.6 so apps that link against them don't crash on launch. 286# Yes this is a bad idea, but it's the least bad from the customer's perspective. 287legacySymLinks: 288 set -x && \ 289 fwdst=$(DSTROOT)/$(PYFRAMEWORKVERSIONS) && \ 290 cd $$fwdst && \ 291 ln -s 2.6 2.3 && \ 292 ln -s 2.6 2.5 && \ 293 set +x 294