Add missing library to OS X build.
[dcpomatic.git] / platform / osx / make_dmg.sh
1 #!/bin/bash
2 #
3 # Syntax: make_dmg.sh <environment> <builddir> <type> <apple-id> <apple-password>
4 # where <type> is universal or thin
5 #
6 # e.g. make_dmg.sh /Users/carl/osx-environment /Users/carl/cdist universal foo@bar.net opensesame
7
8 # Don't set -e here as egrep (used a few times) returns 1 if no matches
9 # were found.
10
11 version=`git describe --tags --abbrev=0 | sed -e "s/v//"`
12
13 # DMG size in megabytes
14 DMG_SIZE=256
15 ENV=$1
16 ROOT=$2
17 TYPE=$3
18 APPLE_ID=$4
19 APPLE_PASSWORD=$5
20
21 if [ "$TYPE" != "universal" -a "$TYPE" != "thin" ]; then
22     echo "Syntax: $0 <builddir> <type>"
23     echo "where <type> is universal or thin"
24     exit 1
25 fi
26
27 # This is our work area for making up the .dmgs
28 mkdir -p build/platform/osx
29 cd build/platform/osx
30
31 function copy {
32     case $TYPE in
33         universal)
34             for f in $1/32/$2; do
35                 if [ -h $f ]; then
36                     ln -s $(readlink $f) "$3/`basename $f`"
37                 else
38                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
39                     mkdir -p "$3"
40                     lipo -create $f $g -output "$3/`basename $f`"
41                 fi
42             done
43             ;;
44         thin)
45             if [ -h $1/$2 ]; then
46                 ln -s $(readlink $1/$2) "$3/`basename $f`"
47             else
48                 cp $1/$2 "$3"
49             fi
50             ;;
51     esac
52 }
53
54 function copy_lib_root {
55     case $TYPE in
56         universal)
57             for f in $ROOT/32/lib/$1*.dylib; do
58                 if [ -h $f ]; then
59                     ln -s $(readlink $f) "$2/`basename $f`"
60                 else
61                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
62                     mkdir -p "$2"
63                     lipo -create $f $g -output "$2/`basename $f`"
64                 fi
65             done
66             ;;
67         thin)
68             for f in $ROOT/lib/$1*.dylib; do
69                 if [ -h $f ]; then
70                     ln -s $(readlink $f) "$2/`basename $f`"
71                 else
72                     mkdir -p "$2"
73                     cp $f "$2"
74                 fi
75             done
76             ;;
77     esac
78     to_relink="$to_relink|$1"
79 }
80
81 function copy_lib_env {
82     case $TYPE in
83         universal)
84             for f in $ENV/32/lib/$1*.dylib; do
85                 if [ -h $f ]; then
86                     ln -s $(readlink $f) "$2/`basename $f`"
87                 else
88                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
89                     mkdir -p "$2"
90                     lipo -create $f $g -output "$2/`basename $f`"
91                 fi
92             done
93             ;;
94         thin)
95             for f in $ENV/64/lib/$1*.dylib; do
96                 if [ -h $f ]; then
97                     ln -s $(readlink $f) "$2/`basename $f`"
98                 else
99                     mkdir -p "$2"
100                     cp $f "$2"
101                 fi
102             done
103             ;;
104     esac
105     to_relink="$to_relink|$1"
106 }
107
108 # @param #1 directory to copy to
109 function copy_libs {
110     local dest="$1"
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 $ROOT src/dcpomatic/build/src/lib/libdcpomatic2.dylib "$dest"
126     copy $ROOT src/dcpomatic/build/src/wx/libdcpomatic2-wx.dylib "$dest"
127     copy_lib_env libboost_system "$dest"
128     copy_lib_env libboost_filesystem "$dest"
129     copy_lib_env libboost_thread "$dest"
130     copy_lib_env libboost_date_time "$dest"
131     copy_lib_env libboost_locale "$dest"
132     copy_lib_env libboost_regex "$dest"
133     copy_lib_env libxml++ "$dest"
134     copy_lib_env libxslt "$dest"
135     copy_lib_env libxml2 "$dest"
136     copy_lib_env libglibmm-2.4 "$dest"
137     copy_lib_env libgobject "$dest"
138     copy_lib_env libgthread "$dest"
139     copy_lib_env libgmodule "$dest"
140     copy_lib_env libsigc "$dest"
141     copy_lib_env libglib-2 "$dest"
142     copy_lib_env libintl "$dest"
143     copy_lib_env libsndfile "$dest"
144     copy_lib_env libssh "$dest"
145     copy_lib_env libwx "$dest"
146     copy_lib_env libfontconfig "$dest"
147     copy_lib_env libfreetype "$dest"
148     copy_lib_env libexpat "$dest"
149     copy_lib_env libltdl "$dest"
150     copy_lib_env libxmlsec1 "$dest"
151     copy_lib_env libcurl "$dest"
152     copy_lib_env libffi "$dest"
153     copy_lib_env libpango "$dest"
154     copy_lib_env libcairo "$dest"
155     copy_lib_env libpixman "$dest"
156     copy_lib_env libharfbuzz "$dest"
157     copy_lib_env libsamplerate "$dest"
158     copy_lib_env libicui18n "$dest"
159     copy_lib_env libicudata "$dest"
160     copy_lib_env libicuio "$dest"
161     copy_lib_env libicule "$dest"
162     copy_lib_env libiculx "$dest"
163     copy_lib_env libicutest "$dest"
164     copy_lib_env libicutu "$dest"
165     copy_lib_env libicuuc "$dest"
166     copy_lib_env libFLAC "$dest"
167     copy_lib_env libvorbis "$dest"
168     copy_lib_env libogg "$dest"
169     copy_lib_env libxerces-c "$dest"
170 }
171
172 # @param #1 directory to copy to
173 function copy_resources {
174     local dest="$1"
175     case $TYPE in
176         universal)
177             local prefix=$ROOT/32
178             ;;
179         thin)
180             local prefix=$ROOT
181             ;;
182     esac
183     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic_small.png "$dest"
184     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2.icns "$dest"
185     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_kdm.icns "$dest"
186     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_server.icns "$dest"
187     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_player.icns "$dest"
188     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_batch.icns "$dest"
189     cp $prefix/src/dcpomatic/graphics/osx/preferences/colour_conversions.png "$dest"
190     cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults.png "$dest"
191     cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest"
192     cp $prefix/src/dcpomatic/graphics/osx/preferences/email.png "$dest"
193     cp $prefix/src/dcpomatic/graphics/osx/preferences/servers.png "$dest"
194     cp $prefix/src/dcpomatic/graphics/osx/preferences/tms.png "$dest"
195     cp $prefix/src/dcpomatic/graphics/osx/preferences/keys.png "$dest"
196     cp $prefix/src/dcpomatic/graphics/osx/preferences/cover_sheet.png "$dest"
197     cp $prefix/src/dcpomatic/graphics/osx/preferences/notifications.png "$dest"
198     cp $prefix/src/dcpomatic/graphics/osx/preferences/accounts.png "$dest"
199     cp $prefix/src/dcpomatic/graphics/osx/preferences/locations.png "$dest"
200     cp $prefix/src/dcpomatic/fonts/LiberationSans-Regular.ttf "$dest"
201     cp $prefix/src/dcpomatic/fonts/LiberationSans-Italic.ttf "$dest"
202     cp $prefix/src/dcpomatic/fonts/LiberationSans-Bold.ttf "$dest"
203     cp $prefix/src/dcpomatic/fonts/fonts.conf.osx "$dest"/fonts.conf
204     cp $prefix/src/dcpomatic/graphics/splash.png "$dest"
205     cp $prefix/src/dcpomatic/graphics/zoom.png "$dest"
206     cp $prefix/src/dcpomatic/graphics/zoom_all.png "$dest"
207     cp $prefix/src/dcpomatic/graphics/select.png "$dest"
208     cp $prefix/src/dcpomatic/graphics/snap.png "$dest"
209     cp $prefix/src/dcpomatic/graphics/sequence.png "$dest"
210     cp $prefix/src/dcpomatic/graphics/me.jpg "$dest"
211     cp -r $prefix/share/libdcp/xsd "$dest"
212
213     # i18n: DCP-o-matic .mo files
214     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
215         mkdir -p "$dest/$lang/LC_MESSAGES"
216         cp $prefix/src/dcpomatic/build/src/lib/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
217         cp $prefix/src/dcpomatic/build/src/wx/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
218         cp $prefix/src/dcpomatic/build/src/tools/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
219     done
220
221     # i18n: wxWidgets .mo files
222     for lang in de es fr it sv nl ru pl da cs; do
223         mkdir "$dest/$lang"
224         cp $ENV/64/share/locale/$lang/LC_MESSAGES/wxstd.mo "$dest/$lang"
225     done
226 }
227
228 # param $1 list of things that link to other things
229 function relink {
230     to_relink=`echo $to_relink | sed -e "s/\+//g"`
231     local linkers=("$@")
232
233     for obj in "${linkers[@]}"; do
234         deps=`otool -L "$obj" | awk '{print $1}' | egrep "($to_relink)" | egrep "($ENV|$ROOT|boost|libicu)"`
235         changes=""
236         for dep in $deps; do
237             base=`basename $dep`
238             if [ "$TYPE" == "universal" ]; then
239                 # $dep will be a path within 64/; make a 32/ path too
240                 dep32=`echo $dep | sed -e "s/\/64\//\/32\//g"`
241                 changes="$changes -change $dep @executable_path/../Frameworks/$base -change $dep32 @executable_path/../Frameworks/$base"
242             else
243                 changes="$changes -change $dep @executable_path/../Frameworks/$base"
244             fi
245         done
246         if test "x$changes" != "x"; then
247             install_name_tool $changes -id `basename "$obj"` "$obj"
248         fi
249     done
250 }
251
252 # @param #1 .app directory
253 # @param #2 full name e.g. DCP-o-matic Batch Converter
254 # @param #3 bundle id e.g. com.dcpomatic.batch
255 function make_dmg {
256     local appdir="$1"
257     local full_name="$2"
258     local bundle_id="$3"
259     tmp_dmg=dcpomatic_tmp.dmg
260     dmg="$full_name $version.dmg"
261     vol_name=DCP-o-matic-$version
262
263     codesign --deep --force --verify --verbose --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$appdir"
264     if [ "$?" != "0" ]; then
265         echo "Failed to sign .app"
266         exit 1
267     fi
268
269     mkdir -p $vol_name
270     cp -a "$appdir" $vol_name
271     ln -s /Applications "$vol_name/Applications"
272     cat<<EOF > "$vol_name/READ ME.txt"
273 Welcome to DCP-o-matic!  The first time you run the program there may be
274 a long (several-minute) delay while OS X checks the code for viruses and
275 other malware.  Please be patient!
276 EOF
277     cat<<EOF > "$vol_name/READ ME.de_DE.txt"
278 Beim erstmaligen Start der DCP-o-matic Anwendungen kann ein längerer
279 Verifikationsvorgang auftreten.  Dies ist von der OS X Sicherheitsumgebung
280 'Gatekeeper' verursacht.  Dieser je nach Rechner teils minutenlange
281 Verifikationsvorgang ist gegenwärtig normal und nicht zu umgehen,
282 es ist kein Programmfehler.  Warten sie die Verifikation für jede der
283 DCP-o-matic Anwendungen ab, bei weiteren Programmstarts wird sie nicht
284 mehr auftreten.
285 EOF
286
287     rm -f $tmp_dmg "$dmg"
288     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
289     attach=$(hdiutil attach -readwrite -noverify -noautoopen $tmp_dmg)
290     device=`echo $attach | egrep '^/dev/' | sed 1q | awk '{print $5}'`
291     sleep 5
292
293     echo '
294   tell application "Finder"
295     tell disk "'$vol_name'"
296            open
297            set current view of container window to icon view
298            set toolbar visible of container window to false
299            set statusbar visible of container window to false
300            set the bounds of container window to {400, 200, 940, 300}
301            set theViewOptions to the icon view options of container window
302            set arrangement of theViewOptions to not arranged
303            set icon size of theViewOptions to 64
304            set position of item "'$appdir'" of container window to {90, 80}
305            set position of item "Applications" of container window to {265, 80}
306            set position of item "READ ME.txt" of container window to {430, 80}
307            set position of item "READ ME.de_DE.txt" of container window to {595, 80}
308            close
309            open
310            update without registering applications
311            delay 5
312      end tell
313    end tell
314 ' | osascript
315
316     chmod -Rf go-w /Volumes/"$vol_name"/"$appdir"
317     sync
318
319     hdiutil eject $device
320     hdiutil convert -format UDZO $tmp_dmg -imagekey zlib-level=9 -o "$dmg"
321     sips -i "$appdir/Contents/Resources/dcpomatic2.icns"
322     DeRez -only icns "$appdir/Contents/Resources/dcpomatic2.icns" > "$appdir/Contents/Resources/DCP-o-matic.rsrc"
323     Rez -append "$appdir/Contents/Resources/DCP-o-matic.rsrc" -o "$dmg"
324     SetFile -a C "$dmg"
325     xattr -c "$dmg"
326
327     set -e
328     codesign --verify --verbose --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$dmg"
329
330     # We only notarize thin builds, as if we're building universal binaries we must be on an OS
331     # sufficiently old that it can't notarize anyway
332     if [ "$TYPE" == "thin" ]; then
333
334         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")
335         N=0
336         while [ 1 ]; do
337             echo "Checking up on $id"
338             status=$(xcrun altool --notarization-info $id -u $APPLE_ID -p $APPLE_PASSWORD --output-format xml | grep -C1 "<key>Status</key>" | tail -n 1 | sed -e "s/   .//g")
339             echo "Got $status"
340             if [ "$status" == "<string>success</string>" ]; then
341                 break
342             fi
343             sleep 30
344             N=$((N+1))
345             if [ "$N" == "10" ]; then
346                 echo "Timed out waiting for notarization"
347                 exit 1
348             fi
349         done
350
351         xcrun stapler staple "$dmg"
352     fi
353     set +e
354
355     rm $tmp_dmg
356     rm -rf $vol_name
357 }
358
359 # @param #1 appdir
360 function setup {
361     appdir="$1"
362     approot="$appdir/Contents"
363     rm -rf "$appdir"
364     mkdir -p "$approot/MacOS"
365     mkdir -p "$approot/Frameworks"
366     mkdir -p "$approot/Resources"
367
368     to_relink="dcpomatic"
369     copy_libs "$approot/Frameworks"
370     copy_resources "$approot/Resources"
371 }
372
373 case $TYPE in
374     universal)
375         prefix=$ROOT/32
376         ;;
377     thin)
378         prefix=$ROOT
379         ;;
380 esac
381
382 # DCP-o-matic main
383 setup "DCP-o-matic 2.app"
384 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2 "$approot/MacOS"
385 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_cli "$approot/MacOS"
386 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_create "$approot/MacOS"
387 copy $ROOT bin/ffprobe "$approot/MacOS"
388 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
389 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2.Info.plist "$approot/Info.plist"
390 rl=("$approot/MacOS/dcpomatic2" "$approot/MacOS/dcpomatic2_cli" "$approot/MacOS/dcpomatic2_create" "$approot/MacOS/ffprobe" "$approot/Frameworks/"*.dylib)
391 relink "${rl[@]}"
392 make_dmg "$appdir" "DCP-o-matic" com.dcpomatic
393
394 # DCP-o-matic KDM Creator
395 setup "DCP-o-matic 2 KDM Creator.app"
396 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm "$approot/MacOS"
397 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm_cli "$approot/MacOS"
398 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
399 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_kdm.Info.plist "$approot/Info.plist"
400 rl=("$approot/MacOS/dcpomatic2_kdm" "$approot/MacOS/dcpomatic2_kdm_cli" "$approot/Frameworks/"*.dylib)
401 relink "${rl[@]}"
402 make_dmg "$appdir" "DCP-o-matic KDM Creator" com.dcpomatic.kdm
403
404 # DCP-o-matic Encode Server
405 setup "DCP-o-matic 2 Encode Server.app"
406 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server "$approot/MacOS"
407 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server_cli "$approot/MacOS"
408 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
409 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_server.Info.plist "$approot/Info.plist"
410 rl=("$approot/MacOS/dcpomatic2_server" "$approot/MacOS/dcpomatic2_server_cli" "$approot/Frameworks/"*.dylib)
411 relink "${rl[@]}"
412 make_dmg "$appdir" "DCP-o-matic Encode Server" com.dcpomatic.server
413
414 # DCP-o-matic Batch Converter
415 setup "DCP-o-matic 2 Batch converter.app"
416 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_batch "$approot/MacOS"
417 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
418 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_batch.Info.plist "$approot/Info.plist"
419 rl=("$approot/MacOS/dcpomatic2_batch" "$approot/Frameworks/"*.dylib)
420 relink "${rl[@]}"
421 make_dmg "$appdir" "DCP-o-matic Batch Converter" com.dcpomatic.batch
422
423 # DCP-o-matic Player
424 setup "DCP-o-matic 2 Player.app"
425 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_player "$approot/MacOS"
426 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
427 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_player.Info.plist "$approot/Info.plist"
428 rl=("$approot/MacOS/dcpomatic2_player" "$approot/Frameworks/"*.dylib)
429 relink "${rl[@]}"
430 make_dmg "$appdir" "DCP-o-matic Player" com.dcpomatic.player