1# Dali Clock for MacOS X, Copyright (c) 2005-2014 by Jamie Zawinski.
2
3XCODE_APP = /Applications/Xcode.app
4
5# To build savers that will run on MacOS 10.6 and 10.7, Xcode 5.0.2 must
6# be used (as that's the latest version of Xcode that ships with a version
7# of clang that implements "-fobjc-gc").  However, Xcode 5.0.2 will not
8# launch on MacOS 10.11 or later.
9#
10# XCODE_APP = /Applications/Xcode-5.0.2.app
11
12TARGETS    = -target DaliClock \
13	     -target DaliClockStore \
14	     -target DaliClockSaver \
15	     -target DaliClockWidget
16#ARCH      = -arch i386 -arch x86_64 ONLY_ACTIVE_ARCH=NO
17XCODEBUILD = $(XCODE_APP)/Contents/Developer/usr/bin/xcodebuild
18SETFILE    = $(XCODE_APP)/Contents/Developer/Tools/SetFile
19SETICON    = ./seticon.pl
20
21default: release
22all: debug release
23
24clean:
25	-rm -rf build
26#	$(XCODEBUILD) $(TARGETS) clean
27
28distclean:
29	-rm -f config.status config.cache config.log \
30	  *.bak *.rej TAGS *~ "#"*
31	-rm -rf autom4te*.cache
32	-rm -rf build Sparkle.framework
33
34distdepend:: Sparkle.framework
35distdepend:: update_plist_version
36distdepend:: update_bindist_version
37
38debug: distdepend
39	$(XCODEBUILD) $(ARCH) $(TARGETS) -configuration Debug   build
40
41release:: distdepend
42	$(XCODEBUILD) $(ARCH) $(TARGETS) -configuration Release build
43	spctl --assess --type execute build/Release/*.app
44
45release:: check_versions
46#release:: enable_gc
47
48Sparkle.framework:
49	rm -rf bin sparkle-bin
50	tar -vxjf ../archive/Sparkle-1.21.2.tar.bz2 \
51	  --exclude CHANGELOG \
52	  --exclude LICENSE \
53	  --exclude SampleAppcast.xml \
54	  --exclude Sparkle.framework.dSYM \
55	  --exclude Sparkle\ Test\ App\*
56	mv bin sparkle-bin
57
58
59# See comment at the top of xscreensaver/OSX/enable_gc.c
60enable_gc:
61	../../xscreensaver/OSX/build/Debug/enable_gc \
62	build/Release/DaliClock.saver/Contents/MacOS/DaliClock
63
64check_gc:
65	@\
66  DIR="build/Release" ;							\
67  RESULT=0 ;								\
68  for S in "$$DIR/"*.saver ; do						\
69   SS=`echo "$$S" | sed -e 's@^.*/@@' -e 's/.saver$$//'` ;		\
70   D="$$S/Contents/MacOS/$$SS" ;					\
71   V=`otool -s __DATA __objc_imageinfo "$$D"				\
72      | grep ' 00 02 00 '` ;						\
73   if [ -z "$$V" ]; then						\
74     echo "$$S does not have GC enabled" ;				\
75     RESULT=1 ;								\
76   fi ;									\
77  done ;								\
78  if [ "$$RESULT" = 0 ]; then echo "GC enabled" ; fi ;			\
79  exit $$RESULT
80
81
82check_versions:
83	@\
84  U=../version.h ;							\
85  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		\
86  DIR=build/Release ;							\
87  RESULT=0 ;								\
88  for P in `find $$DIR -name Info.plist |				\
89	    grep -v Sparkle.framework` ; do				\
90     V2=`perl -0000 -n -e						\
91	'm@<key>CFBundleVersion</key>\s*<string>(.*?)</string>@si 	\
92	 && print $$1' < $$P` ;						\
93     if [ "$$V2" != "$$V" ] ; then					\
94       echo "Wrong version: $$P ($$V2)" ;				\
95       RESULT=1 ;							\
96     fi ;								\
97  done ;								\
98  if [ "$$RESULT" = 0 ]; then echo "Versions match ($$V2)" ; fi ;	\
99  exit $$RESULT
100
101
102echo_tarfiles:
103	@echo `find . \
104	  \( \( -name '.??*' -o -name build -o -name CVS -o -name '*~*' \
105	     -o -name 'jwz.*' -o -name '*.widgetplugin' \
106	     -o -name '*.psd' -o -name '*.ai' \) \
107	     -prune \) \
108	  -o \( -type f -o -type l \) -print \
109	| sed 's@^\./@@' \
110	| sort`
111
112update_plist_version:
113	@								      \
114  SS="AppInfo.plist SaverInfo.plist PluginInfo.plist iPhoneInfo.plist *.wdgt/Info.plist" ;   \
115  SRC=../version.h ;							      \
116  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ]*\).*/\1/p' $$SRC` ;		      \
117  Y=`date +%Y` ;							      \
118  T=/tmp/xs.$$$$ ;							      \
119  for S in $$SS ; do							      \
120    /bin/echo -n "Updating version number in $$S to \"$$V\"... " ;	      \
121    KEYS1="CFBundleVersion|CFBundleShortVersionString" ;		      \
122    KEYS2="NSHumanReadableCopyright|CFBundleLongVersionString|CFBundleGetInfoString" ; \
123    perl -0777 -pne							      \
124      "s@(<key>($$KEYS1)</key>\s*<string>)[^<>]+(</string>)@\$${1}$$V\$${3}@g; \
125       s@(<key>($$KEYS2)</key>\s*<string>[^\d]+)[\d.]+(.*?</string>)@\$${1}$$V\$${3}@gs; \
126       s@(<key>($$KEYS2)</key>\s*<string>.*?1991-)\d\d\d\d(.*?</string>)@\$${1}$$Y\$${3}@gs" \
127    < $$S > $$T ;							    \
128   if cmp -s $$S $$T ; then						    \
129     echo "unchanged." ;						    \
130   else									    \
131    cat $$T > $$S ;							    \
132    echo "done." ;							    \
133   fi ;									    \
134   rm $$T ;								    \
135  done
136
137
138update_bindist_version:
139	@								    \
140  SS="bindist.rtf Credits.html" ;					    \
141  U=../version.h ;							    \
142  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		    \
143  D=`date '+%d-%b-%Y'` ;						    \
144  Y=`date '+%Y'` ;							    \
145  for S in $$SS ; do							    \
146   T=/tmp/xs.$$$$ ;							    \
147   sed -e "s/\(.*version \)[0-9][0-9]*\.[0-9]*[ab]*[0-9]*\(.*\)/\1$$V\2/"   \
148       -e "s/\(1991-\)[0-9][0-9][0-9][0-9]/\1$$Y/"			    \
149       -e "s/\([0-9][0-9]-[A-Z][a-z][a-z]-[0-9][0-9][0-9]*\)/$$D/"	    \
150      < $$S > $$T ;							    \
151   if cmp -s $$S $$T ; then						    \
152    true ;								    \
153   else									    \
154    cat $$T > $$S ;							    \
155    echo "updated $$S to $$V $$D" ;					    \
156   fi ;									    \
157  done ;								    \
158  rm $$T
159
160
161updates.xml::
162	./updates.pl DaliClock ../README ../archive ~/www/xdaliclock
163	@$(MAKE) test_sig
164
165test_sig::
166	@								    \
167  U=../version.h ;							    \
168  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		    \
169  V2="$$V" ;								      \
170  V=`echo $$V | sed 's/\.//g'` ;					    \
171  ZIP="../archive/DaliClock-$$V.dmg" ;					    \
172  OV=`sed -n 's/^.*<title>Version \([^<>]*\).*/\1/p' updates.xml | head -1`;\
173  if [ "x$$V2" != "x$$OV" ] ; then					    \
174    echo "updates.xml: file version is $$OV instead of $$V2" 2>&2 ;	    \
175    exit 1 ; 								    \
176  fi ;									    \
177  SIG=`sed -n 's/^.*dsaSignature="\(.*\)".*/\1/p' updates.xml` ;	    \
178  PUB="sparkle_dsa_pub.pem" ;						    \
179  NN="t.$$$$" ;								    \
180  SIGB=/tmp/$$NN.sig ;							    \
181  HASH=/tmp/$$NN.hash ;							    \
182  rm -f "$$SIGB" "$$HASH" ;						    \
183  echo "$$SIG " | base64 -D  > "$$SIGB" ;				    \
184  set -e ;								    \
185  for OPENSSL in /usr/bin/openssl /opt/local/bin/openssl ; do		    \
186    $$OPENSSL dgst -sha1 -binary  < "$$ZIP"  > "$$HASH" ;		    \
187    /bin/echo -n "$$OPENSSL	`$$OPENSSL version`:	" ;		    \
188    $$OPENSSL dgst -dss1 -verify "$$PUB" -signature "$$SIGB" "$$HASH" ;	    \
189  done ;								    \
190  rm -f "$$SIGB" "$$HASH" ;						    \
191
192
193
194# Can no longer do: ${TARGET_BUILD_DIR}/DaliClock.wdgt
195# It causes code-signing to fail with "a sealed resource is missing or
196# invalid", and if we set the icon before signing (with a build phase on
197# DaliClockWidget) then signing fails with "resource fork, Finder
198# information, or similar detritus not allowed".
199
200
201# -format UDBZ saves 4% over UDZO, but that's only 8KB.
202# check_gc
203dmg:: distdepend check_versions _dmg notarize
204
205_dmg::
206	@								      \
207  set -e ;								      \
208  SRC=../version.h ;							      \
209  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
210  V2="$$V" ;								      \
211  V=`echo $$V | sed 's/\.//g'` ;					      \
212  TMPDIR="build" ;							      \
213  SRC="build/Release" ;							      \
214  BASE="DaliClock-$$V" ;						      \
215  OUTDIR="../archive" ;							      \
216  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
217  TMPDMG="$$TMPDIR/tmp.dmg" ;						      \
218  VOLNAME="DaliClock $$V2" ;						      \
219  STAGE="$$TMPDIR/dmg_stage" ;						      \
220  rm -f "$$DMG" ;							      \
221  rm -rf "$$STAGE" ;							      \
222  echo + mkdir "$$STAGE" ;						      \
223         mkdir "$$STAGE" ;						      \
224  FILES="$$SRC/*.app $$SRC/*.saver $$SRC/*.wdgt" ;			      \
225  echo + cp -pR $$FILES "$$STAGE" ;					      \
226         cp -pR $$FILES "$$STAGE" ;					      \
227  set -x ;								      \
228  cp -p bindist.rtf "$$STAGE/ READ ME.rtf" ;				      \
229  cp -p bindist-DS_Store "$$STAGE/.DS_Store" ;				      \
230  cp -p bindist.webloc "$$STAGE/DaliClock for iOS.webloc" ;		      \
231  cp -p bindist2.webloc "$$STAGE/DaliClock for Android.webloc" ;	      \
232  ${SETFILE} -a E "$$STAGE/ READ ME.rtf" ;				      \
233  ${SETFILE} -a e $$STAGE/*.saver ;					      \
234  ${SETFILE} -a e $$STAGE/*.wdgt ;					      \
235  ${SETFILE} -a E $$STAGE/*.webloc ;					      \
236  $(SETICON) -d daliclockSaver.icns $$STAGE/*.saver ;			      \
237  $(SETICON) -d weblociOS.icns $$STAGE/*iOS*.webloc ;			      \
238  $(SETICON) -d weblocAndroid.icns $$STAGE/*Android*.webloc ;		      \
239									      \
240  spctl --assess --type execute "$$STAGE/"*.app ;			      \
241  spctl --assess --type install "$$STAGE/"*.{saver,wdgt} ;		      \
242									      \
243  hdiutil makehybrid -quiet -ov -hfs -hfs-volume-name "$$VOLNAME"	      \
244    -hfs-openfolder "$$STAGE" "$$STAGE" -o "$$TMPDMG" ;			      \
245  rm -rf "$$STAGE" ;							      \
246									      \
247  hdiutil convert -quiet -ov -format UDZO -imagekey zlib-level=9	      \
248    "$$TMPDMG" -o "$$DMG" ;						      \
249  xattr -w com.apple.quarantine "0000;00000000;;" "$$DMG" ;		      \
250  rm -f "$$TMPDMG" ;							      \
251  ls -ldhgF "$$DMG" ;							      \
252
253dmg2:: staple updates.xml
254
255
256# Adding this is cute:
257#    hdiutil internet-enable -yes -quiet "$$DMG"
258# but means that nobody will ever see the display settings I used!
259# When finder copies the .dmg to a folder, it doesn't preserve them.
260
261
262# To set up notarization:
263#  - Log in on https://appleid.apple.com/
264#  - Generate App-Specific Password, "altool-notarizer"
265#  - Keychain Access / New
266#  - Name: "altool-notarizer", Account: "jwz@jwz.org",
267#    Pass: the one you just generated.
268#
269# "make notarize", which will upload the DMG (slow).
270# A response will be emailed back in about an hour.
271# When that arrives, "make staple".
272#
273# https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/customizing_the_notarization_workflow?language=objc
274#
275# Note that if Sparkle.framework/.../Autoupdate.app is not independently
276# signed, it won't pass. I had to add a build phase for that.
277#
278notarize::
279	@								      \
280  set -e ;								      \
281  SRC=../version.h ;							      \
282  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
283  V=`echo $$V | sed 's/\.//g'` ;					      \
284  BASE="DaliClock-$$V" ;						      \
285  OUTDIR="../archive" ;							      \
286  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
287  set -x ;								      \
288  xcrun altool --notarize-app --primary-bundle-id "org.jwz.xscreensaver"      \
289    --file "$$DMG" -u "jwz@jwz.org" -p "@keychain:altool-notarizer" ;	      \
290  echo "" ;								      \
291  echo "After notarization succeeds, make dmg2"
292
293
294staple::
295	@								      \
296  set -e ;								      \
297  SRC=../version.h ;							      \
298  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
299  V=`echo $$V | sed 's/\.//g'` ;					      \
300  BASE="DaliClock-$$V" ;						      \
301  OUTDIR="../archive" ;							      \
302  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
303  set -x ;								      \
304  xcrun stapler staple "$$DMG"
305
306notarization_history::
307	xcrun altool --notarization-history 0 \
308	-u "jwz@jwz.org" -p "@keychain:altool-notarizer"
309	@echo 'now do: xcrun altool --notarization-info <UUID> ...' ; \
310	echo 'and wget the LogFileURL'
311