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