from __future__ import print_function import os def start_menu_shortcut_folder(variant): return 'DCP-o-matic 2' def long_name(variant): return 'DCP-o-matic 2' def short_name(variant): return 'DCP-o-matic' def kdm_creator_name(variant): return 'KDM Creator' def player_name(variant): return 'Player' def verifier_name(variant): return 'Verifier' def tool_name(variant, debug, tool): name = 'DCP-o-matic 2 %s' % tool if debug: name += ' debug' return name static_deps = ( "libintl-8.dll", "libgio-2.0-0.dll", "libglib-2.0-0.dll", "libgobject-2.0-0.dll", "libiconv-2.dll", "libjpeg-9.dll", "libpng16-16.dll", "libsigc-2.0-0.dll", "libsndfile-1.dll", "libssh.dll", "libstdc++-6.dll", "zlib1.dll", "libjpeg-9.dll", "wxbase317u_gcc_custom.dll", "wxmsw317u_core_gcc_custom.dll", "wxmsw317u_adv_gcc_custom.dll", "wxmsw317u_richtext_gcc_custom.dll", "wxmsw317u_html_gcc_custom.dll", "wxmsw317u_gl_gcc_custom.dll", "wxmsw317u_propgrid_gcc_custom.dll", "wxbase317u_xml_gcc_custom.dll", "libcairo-2.dll", "libfreetype-6.dll", "libgthread-2.0-0.dll", "libpango-1.0-0.dll", "libgmodule-2.0-0.dll", "libpangocairo-1.0-0.dll", "libpangowin32-1.0-0.dll", "libpangoft2-1.0-0.dll", "libtiff-6.dll", "libglibmm-2.4-1.dll", "libxml++-2.6-2.dll", "libxml2-2.dll", "libpixman-1-0.dll", "libfontconfig-1.dll", "libexpat-1.dll", "libbz2.dll", "libxmlsec1.dll", "libxmlsec1-openssl.dll", "libexslt-0.dll", "libxslt-1.dll", "libffi-7.dll", "openssl.exe", "libcurl-4.dll", "libzip.dll", "libcairomm-1.0-1.dll", "libpangomm-1.4-1.dll", "libsamplerate-0.dll", "libnettle-8.dll", "icuuc66.dll", "icudt66.dll", "icuin66.dll", "liblzma-5.dll", "libpcre-1.dll", "libharfbuzz-0.dll", "libwinpthread-1.dll", "libgnutls-30.dll", "libgmp-10.dll", "libhogweed-6.dll", "libidn2-0.dll", "libunistring-2.dll", "libssh2-1.dll", "libgcrypt-20.dll", "libgpg-error-0.dll", "libx264-155.dll", "libwebp-7.dll", "GLEW.dll", "libdav1d.dll", "libbrotlidec.dll", "libbrotlicommon.dll", "libfribidi-0.dll", "libsharpyuv-0.dll", "libsqlite3-0.dll", "libfmt.dll", "libhpdf.dll", "libltdl-7.dll", "libdl.dll", ) fonts = ( "LiberationSans-Regular.ttf", "LiberationSans-Italic.ttf", "LiberationSans-Bold.ttf", ) graphics = ( "splash.png", "zoom_white.png", "zoom_black.png", "zoom_all_white.png", "zoom_all_black.png", "select_white.png", "select_black.png", "snap_white.png", "snap_black.png", "sequence_white.png", "sequence_black.png", "me.jpg", "link_white.png", "link_black.png", "add_black.png", "add_white.png", "pause_black.png", "pause_white.png", ) xsds = ( "DCDMSubtitle-2010.xsd", "DCDMSubtitle-2014.xsd", "DCSubtitle.v1.mattsson.xsd", "Dolby-2012-AD.xsd", "isdcf-mca.xsd", "Main-Stereo-Picture-CPL.xsd", "PROTO-ASDCP-AM-20040311.xsd", "PROTO-ASDCP-CC-CPL-20070926.xsd", "PROTO-ASDCP-CPL-20040511.xsd", "PROTO-ASDCP-PKL-20040311.xsd", "SMPTE-335-2012.xsd", "SMPTE-395-2014-13-1-aaf.xsd", "SMPTE-429-10-2008.xsd", "SMPTE-429-12-2008.xsd", "SMPTE-429-16.xsd", "SMPTE-429-7-2006-CPL.xsd", "SMPTE-429-8-2006-PKL.xsd", "SMPTE-429-9-2007-AM.xsd", "xlink.xsd", "xmldsig-core-schema.xsd", "XMLSchema.dtd", "XMLSchema.xsd", "xml.xsd", ) tags = ( "extlang", "language", "region", "script", "variant", "dcnc", ) def write_installer(bits, dcpomatic_version, debug, disk, variant): long_name_with_debug = long_name(variant) short_name_with_debug = short_name(variant) if debug: long_name_with_debug += ' debug' short_name_with_debug += ' debug' tools = [ ('kdm', kdm_creator_name(variant)), ('player', player_name(variant)), ('verifier', verifier_name(variant)), ('batch', 'Batch Converter'), ('kdm_cli', 'KDM Creator CLI'), ('cli', 'CLI'), ('create', 'Creator'), ('playlist', 'Playlist Editor'), ('combiner', 'Combiner'), ('editor', 'Editor'), ('map', 'Map'), ('server', 'Encode Server'), ] if disk: tools.append(('disk', 'Disk Writer')) # It would be nice to use exist_ok here but it requires quite a new python try: os.makedirs('build/platform/windows') except: pass filename = 'build/platform/windows/installer.%d.nsi' % bits f = open(filename, 'w') def macro(name, value=None): padded_value = f' {value}' if value else '' print(f"!insertmacro {name}{padded_value}", file=f) def define(key, value=None): padded_value = f' {value}' if value else '' print(f"!define {key}{padded_value}", file=f) def desktop_shortcut(target, source): print(f'IfFileExists "{source}" 0 +2', file=f) print(f'CreateShortCut "$DESKTOP\\{target}" "{source}" ""', file=f) def start_menu_shortcut(link, target, variant, debug=False): folder = start_menu_shortcut_folder(variant) if debug: folder += ' debug' print('CreateShortCut "$SMPROGRAMS\\%s\\%s.lnk" "$INSTDIR\\%s"' % (folder, link, target), file=f) class Section: def __init__(self, file, name, required=False, default_on=True, exe=False): self._file = file self._name = name self._required = required self._default_on = default_on self._exe = exe def __enter__(self): flag = '/o ' if not self._default_on else '' suffix = ' (required)' if self._required else '' print(f'Section {flag}"{self._name}{suffix}"', file=self._file) if self._required: print("SectionIn RO", file=self._file) if self._exe: print('SetOutPath "$INSTDIR\\bin"', file=self._file) print("SetShellVarContext all", file=self._file) print(f'CreateDirectory "$SMPROGRAMS\\{long_name_with_debug}"', file=self._file) return self def __exit__(self, type, value, traceback): print("SectionEnd", file=self._file) return True print('!include "MUI2.nsh"', file=f) if bits == 64: print('!include "x64.nsh"', file=f) print('Name "%s"' % short_name_with_debug, file=f) print('RequestExecutionLevel admin', file=f) print('Unicode true', file=f) outfile = '%s %s %d-bit Installer.exe' % (short_name_with_debug, dcpomatic_version, bits) print('outFile "%s"' % outfile, file=f) define("MUI_ICON", '"%graphics%/windows/dcpomatic2.ico"') define("MUI_UNICON", '"%graphics%/windows/dcpomatic2.ico"') define("MUI_SPECIALBITMAP", '"%graphics%/windows/dcpomatic.bmp"') print('!include "Sections.nsh"', file=f) if bits == 64: program_files = "$PROGRAMFILES64" else: program_files = "$PROGRAMFILES" print('InstallDir "%s\\%s"' % (program_files, long_name_with_debug), file=f) macro("MUI_PAGE_WELCOME") macro("MUI_PAGE_LICENSE", '"%docs%/COPYING"') macro("MUI_PAGE_DIRECTORY") define("MUI_COMPONENTSPAGE_NODESC") macro("MUI_PAGE_COMPONENTS") # --- COMMON FILES --- with Section(f, "Common files", required=True): if bits == 64: # Disable registry redirection (enable access to 64-bit portion of registry) print('SetRegView 64', file=f) print('SetOutPath "$INSTDIR\\bin"', file=f) print('WriteUninstaller "$INSTDIR\\Uninstall.exe"', file=f) for lib in ['chrono', 'filesystem', 'system', 'thread', 'date_time', 'locale', 'regex']: print('File "%%static_deps%%/bin/libboost_%s-mt-x%d.dll"' % (lib, bits), file=f) for dep in static_deps: print(f'File "%static_deps%/bin/{dep}"', file=f) if bits == 32: print('File "%static_deps%/bin/libgcc_s_sjlj-1.dll"', file=f) print('File "%static_deps%/bin/libcrypto-3.dll"', file=f) else: print('File "%static_deps%/bin/libgcc_s_seh-1.dll"', file=f) print('File "%static_deps%/bin/libcrypto-3-x64.dll"', file=f) if disk: print('File "%static_deps%/bin/libnanomsg.dll"', file=f) if debug: print('File "%static_deps%/bin/libtermcap.dll"', file=f) print('File "%static_deps%/bin/libreadline8.dll"', file=f) print('File "%static_deps%/bin/libmman.dll"', file=f) print('File /oname=dcpomatic2_verify_cli.exe "%cdist_deps%/bin/dcpverify.exe"', file=f) print('File /oname=dcpomatic2_kdm_inspect.exe "%cdist_deps%/bin/dcpkdm.exe"', file=f) print('File "%cdist_deps%/bin/leqm_nrt.dll"', file=f) print('File "%cdist_deps%/bin/asdcp-dcpomatic.dll"', file=f) print('File "%cdist_deps%/bin/kumu-dcpomatic.dll"', file=f) if disk: print('File "%cdist_deps%/lib/libblockdev.dll"', file=f) print('File "%cdist_deps%/lib/liblwext4.dll"', file=f) print('File "%cdist_deps%/bin/avcodec-61.dll"', file=f) print('File "%cdist_deps%/bin/avfilter-10.dll"', file=f) print('File "%cdist_deps%/bin/avformat-61.dll"', file=f) print('File "%cdist_deps%/bin/avutil-59.dll"', file=f) print('File "%cdist_deps%/bin/avdevice-61.dll"', file=f) print('File "%cdist_deps%/bin/postproc-58.dll"', file=f) print('File "%cdist_deps%/bin/swresample-5.dll"', file=f) print('File "%cdist_deps%/bin/swscale-8.dll"', file=f) print('File "%cdist_deps%/bin/dcp-1.0.dll"', file=f) print('File "%cdist_deps%/bin/cxml-0.dll"', file=f) print('File "%cdist_deps%/bin/sub-1.0.dll"', file=f) print('File "%cdist_deps%/bin/ttf-1.0.dll"', file=f) print('File "%cdist_deps%/bin/ffprobe.exe"', file=f) print('File "%cdist_deps%/src/openssl/apps/openssl.exe"', file=f) print('File "%cdist_deps%/bin/libopenjp2.dll"', file=f) if debug: print('File "%resources%/gdb_script"', file=f) print('File "%resources%/dcpomatic2_debug.bat"', file=f) print('File "%mingw%/bin/gdb.exe"', file=f) for s, l in tools: print('File "%%resources%%/dcpomatic2_%s_debug.bat"' % s, file=f) else: print('File "%binaries%/src/wx/dcpomatic2-wx.dll"', file=f) print('File "%binaries%/src/lib/dcpomatic2.dll"', file=f) print('SetOutPath "$INSTDIR\\bin"', file=f) def language(language, country, wx=True, full=False): lc = f"{language}_{country}" if full else language print(f'SetOutPath "$INSTDIR\\locale\\{lc}\\LC_MESSAGES"', file=f) print(f'File "%binaries%/src/lib/mo/{language}_{country}/libdcpomatic2.mo"', file=f) print(f'File "%binaries%/src/wx/mo/{language}_{country}/libdcpomatic2-wx.mo"', file=f) print(f'File "%binaries%/src/tools/mo/{language}_{country}/dcpomatic2.mo"', file=f) if wx: print(f'File "%static_deps%/share/locale/{lc}/LC_MESSAGES/wxstd-3.1.mo"', file=f) language('fr', 'FR') language('it', 'IT') language('ko', 'KR', wx=False) language('es', 'ES') language('sv', 'SE') language('de', 'DE') language('el', 'GR') language('nl', 'NL') language('ru', 'RU') language('pl', 'PL') language('da', 'DK') language('pt', 'PT', wx=False, full=True) language('pt', 'BR', wx=False, full=True) language('sk', 'SK', wx=False) language('cs', 'CZ') language('uk', 'UA', wx=False) language('zh', 'CN', wx=False, full=True) language('tr', 'TR', wx=False, full=True) language('sl', 'SI', wx=False, full=True) language('hu', 'HU', wx=False, full=True) language('ja', 'JP', wx=False, full=True) language('fa', 'IR', wx=False, full=True) print('File /oname=wxstd-3.1.mo "%binaries%/src/wx/mo/fa_IR/wxstd.mo"', file=f) print('SetOutPath "$INSTDIR"', file=f) for font in fonts: print(f'File "%resources%/../../fonts/{font}"', file=f) print('File /oname=fonts.conf "%resources%/../../fonts/fonts.conf.windows"', file=f) for graphic in graphics: print(f'File "%graphics%/{graphic}"', file=f) print('SetOutPath "$INSTDIR\\web"', file=f) print('File "%web%/index.html"', file=f) print('SetOutPath "$INSTDIR\\xsd"', file=f) for xsd in xsds: print(f'File "%cdist_deps%/share/libdcp/xsd/{xsd}"', file=f) print('SetOutPath "$INSTDIR\\tags"', file=f) for tag in tags: print(f'File "%cdist_deps%/share/libdcp/tags/{tag}"', file=f) print('SetOutPath "$INSTDIR"', file=f) print('File "%cdist_deps%/share/libdcp/ratings"', file=f) def setup_uninstall(long_name_with_debug, debug): start_menu_shortcut(f'Uninstall {long_name_with_debug}', 'Uninstall.exe', variant, debug=debug) print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" "DisplayName" "%s (remove only)"' % (long_name_with_debug, long_name_with_debug), file=f) print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" "DisplayVersion" "%s"' % (long_name_with_debug, dcpomatic_version), file=f) print('WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" "UninstallString" "$INSTDIR\\Uninstall.exe"' % long_name_with_debug, file=f) # --- DCP-O-MATIC --- suffix = '_debug.bat' if debug else '.exe' with Section(f, long_name_with_debug, exe=True): print('File "%binaries%/src/tools/dcpomatic2.exe"', file=f) start_menu_shortcut(long_name_with_debug, f'bin\\dcpomatic2{suffix}', variant, debug=debug) setup_uninstall(long_name_with_debug, debug) # --- PLAYER --- with Section(f, "Player", exe=True): print('File "%binaries%/src/tools/dcpomatic2_player.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, player_name(variant)), f'bin\\dcpomatic2_player{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- VERIFIER --- with Section(f, "Verifier", exe=True): print('File "%binaries%/src/tools/dcpomatic2_verifier.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, verifier_name(variant)), f'bin\\dcpomatic2_verifier{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- DISK WRITER --- if disk: with Section(f, "Disk Writer", exe=True): print('File "%binaries%/src/tools/dcpomatic2_disk.exe"', file=f) print('File "%binaries%/src/tools/dcpomatic2_disk_writer.exe"', file=f) print('File "%binaries%/src/tools/dcpomatic2_disk_writer.exe.manifest"', file=f) start_menu_shortcut(tool_name(variant, debug, 'Disk Writer'), f'bin\\dcpomatic2_disk{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- KDM CREATOR --- with Section(f, "KDM Creator", exe=True): print('File "%binaries%/src/tools/dcpomatic2_kdm.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, kdm_creator_name(variant)), f'bin\\dcpomatic2_kdm{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- BATCH CONVERTER --- with Section(f, "Batch Converter", exe=True): print('File "%binaries%/src/tools/dcpomatic2_batch.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, 'Batch Converter'), f'bin\\dcpomatic2_batch{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- CLI TOOLS --- with Section(f, "Command-line tools", exe=True): print(f'File "%binaries%/src/tools/dcpomatic2_kdm_cli{suffix}"', file=f) print(f'File "%binaries%/src/tools/dcpomatic2_cli{suffix}"', file=f) print(f'File "%binaries%/src/tools/dcpomatic2_create{suffix}"', file=f) print(f'File "%binaries%/src/tools/dcpomatic2_server_cli{suffix}"', file=f) setup_uninstall(long_name_with_debug, debug) # --- ENCODE SERVER --- with Section(f, "Encode server", exe=True): print('File "%binaries%/src/tools/dcpomatic2_server.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, 'Encode Server'), f'bin\\dcpomatic2_server{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- PLAYLIST EDITOR --- with Section(f, "Playlist Editor", exe=True): print('File "%binaries%/src/tools/dcpomatic2_playlist.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, 'Playlist Editor'), f'bin\\dcpomatic2_playlist{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- MANIPULATION TOOLS --- with Section(f, "Manipulation tools (combiner, editor, map)", exe=True): print('File "%binaries%/src/tools/dcpomatic2_combiner.exe"', file=f) print('File "%binaries%/src/tools/dcpomatic2_editor.exe"', file=f) print('File "%binaries%/src/tools/dcpomatic2_map.exe"', file=f) start_menu_shortcut(tool_name(variant, debug, 'Combiner'), f'bin\\dcpomatic2_combiner{suffix}', variant) start_menu_shortcut(tool_name(variant, debug, 'Editor'), f'bin\\dcpomatic2_editor{suffix}', variant) start_menu_shortcut(tool_name(variant, debug, 'Map'), f'bin\\dcpomatic2_map{suffix}', variant) setup_uninstall(long_name_with_debug, debug) # --- DESKTOP SHORTCUTS --- with Section(f, "Desktop shortcuts", default_on=False): print("SetShellVarContext all", file=f) desktop_shortcut(f'{long_name_with_debug}.lnk', f'$INSTDIR\\bin\\dcpomatic2{suffix}') for s, l in tools: desktop_shortcut(f'{tool_name(variant, debug, l)}.lnk', f'$INSTDIR\\bin\\dcpomatic2_{s}{suffix}') macro("MUI_PAGE_INSTFILES") # --- UNINSTALL --- macro("MUI_UNPAGE_WELCOME") macro("MUI_UNPAGE_CONFIRM") macro("MUI_UNPAGE_INSTFILES") macro("MUI_LANGUAGE", '"English"') with Section(f, "Uninstall"): print('SetShellVarContext all', file=f) print('RMDir /r "$INSTDIR"', file=f) if debug: print('Delete "$DESKTOP\\DCP-o-matic 2 debug.lnk"', file=f) for s, l in tools: print('Delete "$DESKTOP\\DCP-o-matic 2 %s debug.lnk"' % l, file=f) print('RmDir /r "$SMPROGRAMS\\DCP-o-matic 2 debug"', file=f) if bits == 64: print("SetRegView 64", file=f) print('DeleteRegKey HKLM "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2 debug"', file=f) else: print('Delete "$DESKTOP\\DCP-o-matic 2.lnk"', file=f) for s, l in tools: print('Delete "$DESKTOP\\DCP-o-matic 2 %s.lnk"' % l, file=f) print('RmDir /r "$SMPROGRAMS\\DCP-o-matic 2"', file=f) if bits == 64: print("SetRegView 64", file=f) print('DeleteRegKey HKLM "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\DCP-o-matic 2"', file=f) def build(bld): write_installer(32, bld.env.VERSION, bld.env.DEBUG, bld.env.ENABLE_DISK, bld.env.VARIANT) write_installer(64, bld.env.VERSION, bld.env.DEBUG, bld.env.ENABLE_DISK, bld.env.VARIANT)