3 SYNTAX="make_dmg.sh <environment> <builddir> <type> <apple-id> <apple-password>"
4 # where <type> is universal or thin
6 # e.g. make_dmg.sh /Users/carl/osx-environment /Users/carl/cdist universal foo@bar.net opensesame
8 # Don't set -e here as egrep (used a few times) returns 1 if no matches
11 version=`git describe --tags --abbrev=0 | sed -e "s/v//"`
13 # DMG size in megabytes
21 if [ "$TYPE" != "universal" -a "$TYPE" != "thin" ]; then
23 echo "where <type> is universal or thin"
27 # This is our work area for making up the .dmgs
28 mkdir -p build/platform/osx
36 ln -s $(readlink $f) "$3/`basename $f`"
38 g=`echo $f | sed -e "s/\/32\//\/64\//g"`
40 lipo -create $f $g -output "$3/`basename $f`"
46 ln -s $(readlink $1/$2) "$3/`basename $f`"
54 function copy_lib_root {
57 for f in $ROOT/32/lib/$1*.dylib; do
59 ln -s $(readlink $f) "$2/`basename $f`"
61 g=`echo $f | sed -e "s/\/32\//\/64\//g"`
63 lipo -create $f $g -output "$2/`basename $f`"
68 for f in $ROOT/lib/$1*.dylib; do
70 ln -s $(readlink $f) "$2/`basename $f`"
78 to_relink="$to_relink|$1"
81 function copy_lib_env {
84 for f in $ENV/32/lib/$1*.dylib; do
86 ln -s $(readlink $f) "$2/`basename $f`"
88 g=`echo $f | sed -e "s/\/32\//\/64\//g"`
90 lipo -create $f $g -output "$2/`basename $f`"
95 for f in $ENV/64/lib/$1*.dylib; do
97 ln -s $(readlink $f) "$2/`basename $f`"
105 to_relink="$to_relink|$1"
108 # @param #1 directory to copy to
111 copy_lib_root libcxml "$dest"
112 copy_lib_root libdcp-1.0 "$dest"
113 copy_lib_root libasdcp-carl "$dest"
114 copy_lib_root libkumu-carl "$dest"
115 copy_lib_root libsub "$dest"
116 copy_lib_root libopenjp2 "$dest"
117 copy_lib_root libavdevice "$dest"
118 copy_lib_root libavformat "$dest"
119 copy_lib_root libavfilter "$dest"
120 copy_lib_root libavutil "$dest"
121 copy_lib_root libavcodec "$dest"
122 copy_lib_root libswscale "$dest"
123 copy_lib_root libpostproc "$dest"
124 copy_lib_root libswresample "$dest"
125 copy_lib_root liblwext4 "$dest"
126 copy_lib_root libblockdev "$dest"
127 copy $ROOT src/dcpomatic/build/src/lib/libdcpomatic2.dylib "$dest"
128 copy $ROOT src/dcpomatic/build/src/wx/libdcpomatic2-wx.dylib "$dest"
129 copy_lib_env libboost_system "$dest"
130 copy_lib_env libboost_filesystem "$dest"
131 copy_lib_env libboost_thread "$dest"
132 copy_lib_env libboost_date_time "$dest"
133 copy_lib_env libboost_locale "$dest"
134 copy_lib_env libboost_regex "$dest"
135 copy_lib_env libxml++ "$dest"
136 copy_lib_env libxslt "$dest"
137 copy_lib_env libxml2 "$dest"
138 copy_lib_env libglibmm-2.4 "$dest"
139 copy_lib_env libgobject "$dest"
140 copy_lib_env libgthread "$dest"
141 copy_lib_env libgmodule "$dest"
142 copy_lib_env libsigc "$dest"
143 copy_lib_env libglib-2 "$dest"
144 copy_lib_env libintl "$dest"
145 copy_lib_env libsndfile "$dest"
146 copy_lib_env libssh "$dest"
147 copy_lib_env libwx "$dest"
148 copy_lib_env libfontconfig "$dest"
149 copy_lib_env libfreetype "$dest"
150 copy_lib_env libexpat "$dest"
151 copy_lib_env libltdl "$dest"
152 copy_lib_env libxmlsec1 "$dest"
153 copy_lib_env libcurl "$dest"
154 copy_lib_env libffi "$dest"
155 copy_lib_env libpango "$dest"
156 copy_lib_env libcairo "$dest"
157 copy_lib_env libpixman "$dest"
158 copy_lib_env libharfbuzz "$dest"
159 copy_lib_env libsamplerate "$dest"
160 copy_lib_env libicui18n "$dest"
161 copy_lib_env libicudata "$dest"
162 copy_lib_env libicuio "$dest"
163 copy_lib_env libicule "$dest"
164 copy_lib_env libiculx "$dest"
165 copy_lib_env libicutest "$dest"
166 copy_lib_env libicutu "$dest"
167 copy_lib_env libicuuc "$dest"
168 copy_lib_env libFLAC "$dest"
169 copy_lib_env libvorbis "$dest"
170 copy_lib_env libogg "$dest"
171 copy_lib_env libxerces-c "$dest"
174 # @param #1 directory to copy to
175 function copy_resources {
179 local prefix=$ROOT/32
185 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic_small.png "$dest"
186 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2.icns "$dest"
187 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_kdm.icns "$dest"
188 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_server.icns "$dest"
189 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_player.icns "$dest"
190 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_batch.icns "$dest"
191 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_playlist.icns "$dest"
192 cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_disk.icns "$dest"
193 cp $prefix/src/dcpomatic/graphics/osx/preferences/colour_conversions.png "$dest"
194 cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults.png "$dest"
195 cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest"
196 cp $prefix/src/dcpomatic/graphics/osx/preferences/email.png "$dest"
197 cp $prefix/src/dcpomatic/graphics/osx/preferences/servers.png "$dest"
198 cp $prefix/src/dcpomatic/graphics/osx/preferences/tms.png "$dest"
199 cp $prefix/src/dcpomatic/graphics/osx/preferences/keys.png "$dest"
200 cp $prefix/src/dcpomatic/graphics/osx/preferences/cover_sheet.png "$dest"
201 cp $prefix/src/dcpomatic/graphics/osx/preferences/notifications.png "$dest"
202 cp $prefix/src/dcpomatic/graphics/osx/preferences/locations.png "$dest"
203 cp $prefix/src/dcpomatic/graphics/osx/preferences/sound.png "$dest"
204 cp $prefix/src/dcpomatic/fonts/LiberationSans-Regular.ttf "$dest"
205 cp $prefix/src/dcpomatic/fonts/LiberationSans-Italic.ttf "$dest"
206 cp $prefix/src/dcpomatic/fonts/LiberationSans-Bold.ttf "$dest"
207 cp $prefix/src/dcpomatic/fonts/fonts.conf.osx "$dest"/fonts.conf
208 cp $prefix/src/dcpomatic/graphics/splash.png "$dest"
209 cp $prefix/src/dcpomatic/graphics/zoom.png "$dest"
210 cp $prefix/src/dcpomatic/graphics/zoom_all.png "$dest"
211 cp $prefix/src/dcpomatic/graphics/select.png "$dest"
212 cp $prefix/src/dcpomatic/graphics/snap.png "$dest"
213 cp $prefix/src/dcpomatic/graphics/sequence.png "$dest"
214 cp $prefix/src/dcpomatic/graphics/me.jpg "$dest"
215 cp -r $prefix/share/libdcp/xsd "$dest"
217 # i18n: DCP-o-matic .mo files
218 for lang in de_DE es_ES fr_FR it_IT sv_SE nl_NL ru_RU pl_PL da_DK pt_PT pt_BR sk_SK cs_CZ uk_UA zh_CN tr_TR; do
219 mkdir -p "$dest/$lang/LC_MESSAGES"
220 cp $prefix/src/dcpomatic/build/src/lib/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
221 cp $prefix/src/dcpomatic/build/src/wx/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
222 cp $prefix/src/dcpomatic/build/src/tools/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
225 # i18n: wxWidgets .mo files
226 for lang in de es fr it sv nl ru pl da cs; do
228 cp $ENV/64/share/locale/$lang/LC_MESSAGES/wxstd.mo "$dest/$lang"
232 # param $1 list of things that link to other things
233 function relink_relative {
234 to_relink=`echo $to_relink | sed -e "s/\+//g"`
237 for obj in "${linkers[@]}"; do
238 deps=`otool -L "$obj" | awk '{print $1}' | egrep "($to_relink)" | egrep "($ENV|$ROOT|boost|libicu)"`
242 if [ "$TYPE" == "universal" ]; then
243 # $dep will be a path within 64/; make a 32/ path too
244 dep32=`echo $dep | sed -e "s/\/64\//\/32\//g"`
245 changes="$changes -change $dep @executable_path/../Frameworks/$base -change $dep32 @executable_path/../Frameworks/$base"
247 changes="$changes -change $dep @executable_path/../Frameworks/$base"
250 if test "x$changes" != "x"; then
251 install_name_tool $changes -id `basename "$obj"` "$obj"
256 # param $1 directory things should be relinked into
257 # $2 list of things that link to other things
258 function relink_absolute {
259 to_relink=`echo $to_relink | sed -e "s/\+//g"`
264 for obj in "${linkers[@]}"; do
265 deps=`otool -L "$obj" | awk '{print $1}' | egrep "($to_relink)" | egrep "($ENV|$ROOT|boost|libicu)"`
268 install_name_tool -change "$dep" "$target"/$base -id `basename "$obj"` "$obj"
274 codesign --deep --force --verify --verbose --options runtime --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$1"
275 if [ "$?" != "0" ]; then
276 echo "Failed to sign $1"
282 # @param #1 .app directory
283 # @param #2 .pkg or ""
284 # @param #3 full name e.g. DCP-o-matic Batch Converter
285 # @param #4 bundle id e.g. com.dcpomatic.batch
291 tmp_dmg=dcpomatic_tmp.dmg
292 dmg="$full_name $version.dmg"
293 vol_name=DCP-o-matic-$version
297 if [ "$pkg" != "" ]; then
298 productsign --sign "Developer ID Installer: Carl Hetherington (R82DXSR997)" "$pkg" "signed_temp.pkg"
299 if [ "$?" != "0" ]; then
300 echo "Failed to sign .pkg"
303 mv signed_temp.pkg "$pkg"
307 cp -a "$appdir" $vol_name
308 if [ "$pkg" != "" ]; then
309 cp -a "$pkg" $vol_name
311 ln -s /Applications "$vol_name/Applications"
312 cat<<EOF > "$vol_name/READ ME.txt"
313 Welcome to DCP-o-matic! The first time you run the program there may be
314 a long (several-minute) delay while OS X checks the code for viruses and
315 other malware. Please be patient!
317 cat<<EOF > "$vol_name/READ ME.de_DE.txt"
318 Beim erstmaligen Start der DCP-o-matic Anwendungen kann ein längerer
319 Verifikationsvorgang auftreten. Dies ist von der OS X Sicherheitsumgebung
320 'Gatekeeper' verursacht. Dieser je nach Rechner teils minutenlange
321 Verifikationsvorgang ist gegenwärtig normal und nicht zu umgehen,
322 es ist kein Programmfehler. Warten sie die Verifikation für jede der
323 DCP-o-matic Anwendungen ab, bei weiteren Programmstarts wird sie nicht
327 if [ "$pkg" != "" ]; then
328 cat<<EOF > "$vol_name/READ ME.txt"
330 To run this software successfully you must install $pkg before running
335 if [ "$pkg" != "" ]; then
336 cat<<EOF > "$vol_name/READ ME.de_DE.txt"
338 To run this software successfully you must install $pkg before running
343 rm -f $tmp_dmg "$dmg"
344 hdiutil create -srcfolder $vol_name -volname $vol_name -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size $DMG_SIZE $tmp_dmg
345 attach=$(hdiutil attach -readwrite -noverify -noautoopen $tmp_dmg)
346 device=`echo $attach | egrep '^/dev/' | sed 1q | awk '{print $5}'`
350 tell application "Finder"
351 tell disk "'$vol_name'"
353 set current view of container window to icon view
354 set toolbar visible of container window to false
355 set statusbar visible of container window to false
356 set the bounds of container window to {400, 200, 1160, 600}
357 set the bounds of container window to {400, 200, 1160, 600}
358 set the bounds of container window to {400, 200, 1160, 600}
359 set theViewOptions to the icon view options of container window
360 set arrangement of theViewOptions to not arranged
361 set icon size of theViewOptions to 64
362 set position of item "'$appdir'" of container window to {90, 80}
363 set position of item "Applications" of container window to {265, 80}
364 set position of item "READ ME.txt" of container window to {430, 80}
365 set position of item "READ ME.de_DE.txt" of container window to {595, 80}
366 set position of item "DCP-o-matic Disk Writer.pkg" of container window to {90, 255}
369 update without registering applications
375 chmod -Rf go-w /Volumes/"$vol_name"/"$appdir"
378 hdiutil eject $device
379 hdiutil convert -format UDZO $tmp_dmg -imagekey zlib-level=9 -o "$dmg"
380 sips -i "$appdir/Contents/Resources/dcpomatic2.icns"
381 DeRez -only icns "$appdir/Contents/Resources/dcpomatic2.icns" > "$appdir/Contents/Resources/DCP-o-matic.rsrc"
382 Rez -append "$appdir/Contents/Resources/DCP-o-matic.rsrc" -o "$dmg"
387 codesign --verify --verbose --options runtime --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$dmg"
389 # We only notarize thin builds, as if we're building universal binaries we must be on an OS
390 # sufficiently old that it can't notarize anyway
391 if [ "$TYPE" == "thin" ]; then
393 id=$(xcrun altool --notarize-app -t osx -f "$dmg" --primary-bundle-id $bundle_id -u $APPLE_ID -p $APPLE_PASSWORD --output-format xml | grep -C1 RequestUUID | tail -n 1 | sed -e "s/<string>//g" | sed -e "s/<\/string>//g")
396 echo "Checking up on $id"
397 status=$(xcrun altool --notarization-info $id -u $APPLE_ID -p $APPLE_PASSWORD --output-format xml)
398 summary=$(echo "$status" | grep -C1 "<key>Status</key>" | tail -n 1 | sed -e "s/ .//g")
400 if [ "$summary" == "<string>invalid</string>" ]; then
401 echo "Notarization failed."
405 if [ "$summary" == "<string>success</string>" ]; then
410 if [ "$N" == "30" ]; then
411 echo "Timed out waiting for notarization"
416 xcrun stapler staple "$dmg"
427 approot="$appdir/Contents"
429 mkdir -p "$approot/MacOS"
430 mkdir -p "$approot/Frameworks"
431 mkdir -p "$approot/Resources"
433 to_relink="dcpomatic"
434 copy_libs "$approot/Frameworks"
435 copy_resources "$approot/Resources"
448 setup "DCP-o-matic 2.app"
449 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2 "$approot/MacOS"
450 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_cli "$approot/MacOS"
451 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_create "$approot/MacOS"
452 copy $ROOT bin/ffprobe "$approot/MacOS"
453 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
454 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2.Info.plist "$approot/Info.plist"
455 rl=("$approot/MacOS/dcpomatic2" "$approot/MacOS/dcpomatic2_cli" "$approot/MacOS/dcpomatic2_create" "$approot/MacOS/ffprobe" "$approot/Frameworks/"*.dylib)
456 relink_relative "${rl[@]}"
457 make_dmg "$appdir" "" "DCP-o-matic" com.dcpomatic
459 # DCP-o-matic KDM Creator
460 setup "DCP-o-matic 2 KDM Creator.app"
461 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm "$approot/MacOS"
462 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm_cli "$approot/MacOS"
463 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
464 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_kdm.Info.plist "$approot/Info.plist"
465 rl=("$approot/MacOS/dcpomatic2_kdm" "$approot/MacOS/dcpomatic2_kdm_cli" "$approot/Frameworks/"*.dylib)
466 relink_relative "${rl[@]}"
467 make_dmg "$appdir" "" "DCP-o-matic KDM Creator" com.dcpomatic.kdm
469 # DCP-o-matic Encode Server
470 setup "DCP-o-matic 2 Encode Server.app"
471 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server "$approot/MacOS"
472 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server_cli "$approot/MacOS"
473 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
474 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_server.Info.plist "$approot/Info.plist"
475 rl=("$approot/MacOS/dcpomatic2_server" "$approot/MacOS/dcpomatic2_server_cli" "$approot/Frameworks/"*.dylib)
476 relink_relative "${rl[@]}"
477 make_dmg "$appdir" "" "DCP-o-matic Encode Server" com.dcpomatic.server
479 # DCP-o-matic Batch Converter
480 setup "DCP-o-matic 2 Batch converter.app"
481 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_batch "$approot/MacOS"
482 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
483 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_batch.Info.plist "$approot/Info.plist"
484 rl=("$approot/MacOS/dcpomatic2_batch" "$approot/Frameworks/"*.dylib)
485 relink_relative "${rl[@]}"
486 make_dmg "$appdir" "" "DCP-o-matic Batch Converter" com.dcpomatic.batch
489 setup "DCP-o-matic 2 Player.app"
490 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_player "$approot/MacOS"
491 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
492 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_player.Info.plist "$approot/Info.plist"
493 rl=("$approot/MacOS/dcpomatic2_player" "$approot/Frameworks/"*.dylib)
494 relink_relative "${rl[@]}"
495 make_dmg "$appdir" "" "DCP-o-matic Player" com.dcpomatic.player
497 # DCP-o-matic Playlist Editor
498 setup "DCP-o-matic 2 Playlist Editor.app"
499 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_playlist "$approot/MacOS"
500 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
501 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_playlist.Info.plist "$approot/Info.plist"
502 rl=("$approot/MacOS/dcpomatic2_playlist" "$approot/Frameworks/"*.dylib)
503 relink_relative "${rl[@]}"
504 make_dmg "$appdir" "" "DCP-o-matic Playlist Editor" com.dcpomatic.playlist
506 # DCP-o-matic Disk Writer .app
507 setup "DCP-o-matic 2 Disk Writer.app"
508 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_disk "$approot/MacOS"
509 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_disk.Info.plist "$approot/Info.plist"
510 rl=("$approot/MacOS/dcpomatic2_disk" "$approot/Frameworks/"*.dylib)
511 relink_relative "${rl[@]}"
513 # DCP-o-matic Disk Writer daemon .pkg
515 pkgbase=tmp-disk-writer
519 pkgroot=$pkgbase/root
521 mkdir -p $pkgroot/Library/LaunchDaemons
522 cat > $pkgroot/Library/LaunchDaemons/com.dcpomatic.disk.writer.plist <<EOF
523 <?xml version="1.0" encoding="UTF-8"?>
524 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
525 <plist version="1.0">
528 <string>com.dcpomatic.disk.writer</string>
529 <key>ProgramArguments</key>
531 <string>/Library/Application Support/com.dcpomatic/dcpomatic2_disk_writer</string>
533 <key>EnvironmentVariables</key>
535 <key>DYLD_LIBRARY_PATH</key>
536 <string><![CDATA[/Library/Application Support/com.dcpomatic]]></string>
544 <key>StandardOutPath</key>
545 <string>/Users/carl/damon.out.log</string>
546 <key>StandardErrorPath</key>
547 <string>/Users/carl/damon.err.log</string>
552 # Get the binaries together in $pkgbin then move them to the
553 # place with spaces in the filename to avoid some of the pain of escaping
556 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_disk_writer "$pkgbin"
559 rl=("$pkgbin/dcpomatic2_disk_writer" "$pkgbin/"*.dylib)
560 relink_absolute "/Library/Application Support/com.dcpomatic" "${rl[@]}"
562 mkdir $pkgbase/scripts
563 cat > $pkgbase/scripts/postinstall <<EOF
565 /bin/launchctl load "/Library/LaunchDaemons/com.dcpomatic.disk.writer.plist"
568 chmod gou+x $pkgbase/scripts/postinstall
570 find "$pkgbin" -iname "*.dylib" -print0 | while IFS= read -r -d '' f; do
573 sign "$pkgbin/dcpomatic2_disk_writer"
575 mkdir -p "$pkgroot/Library/Application Support/com.dcpomatic"
576 mv $pkgbin/* "$pkgroot/Library/Application Support/com.dcpomatic/"
577 pkgbuild --root $pkgroot --identifier com.dcpomatic.disk.writer --scripts $pkgbase/scripts "DCP-o-matic Disk Writer.pkg"
579 make_dmg "$appdir" "DCP-o-matic Disk Writer.pkg" "DCP-o-matic Disk Writer" com.dcpomatic.disk