Advertisement
Guest User

Untitled

a guest
Feb 15th, 2019
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 74.22 KB | None | 0 0
  1. #!/usr/bin/env python
  2. """\
  3. @file viewer_manifest.py
  4. @author Ryan Williams
  5. @brief Description of all installer viewer files, and methods for packaging
  6. them into installers for all supported platforms.
  7.  
  8. $LicenseInfo:firstyear=2006&license=viewerlgpl$
  9. Second Life Viewer Source Code
  10. Copyright (C) 2006-2014, Linden Research, Inc.
  11.  
  12. This library is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU Lesser General Public
  14. License as published by the Free Software Foundation;
  15. version 2.1 of the License only.
  16.  
  17. This library is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. Lesser General Public License for more details.
  21.  
  22. You should have received a copy of the GNU Lesser General Public
  23. License along with this library; if not, write to the Free Software
  24. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  25.  
  26. Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  27. $/LicenseInfo$
  28. """
  29. import sys
  30. import os
  31. import os.path
  32. import shutil
  33. import errno
  34. import json
  35. import plistlib
  36. import random
  37. import re
  38. import stat
  39. import subprocess
  40. import tarfile
  41. import time
  42.  
  43.  
  44. viewer_dir = os.path.dirname(__file__)
  45. # Add indra/lib/python to our path so we don't have to muck with PYTHONPATH.
  46. # Put it FIRST because some of our build hosts have an ancient install of
  47. # indra.util.llmanifest under their system Python!
  48. sys.path.insert(0, os.path.join(viewer_dir, os.pardir, "lib", "python"))
  49. from indra.util.llmanifest import LLManifest, main, proper_windows_path, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError
  50. try:
  51. from llbase import llsd
  52. except ImportError:
  53. from indra.base import llsd
  54.  
  55. class ViewerManifest(LLManifest):
  56. def is_packaging_viewer(self):
  57. # Some commands, files will only be included
  58. # if we are packaging the viewer on windows.
  59. # This manifest is also used to copy
  60. # files during the build (see copy_w_viewer_manifest
  61. # and copy_l_viewer_manifest targets)
  62. return 'package' in self.args['actions']
  63.  
  64. def package_skin(self, xml, skin_dir):
  65. self.path(xml)
  66. self.path(skin_dir + "/*")
  67. # include the entire textures directory recursively
  68. with self.prefix(src=skin_dir+"/textures"):
  69. self.path("*/*.tga")
  70. self.path("*/*.j2c")
  71. self.path("*/*.jpg")
  72. self.path("*/*.png")
  73. self.path("*.tga")
  74. self.path("*.j2c")
  75. self.path("*.jpg")
  76. self.path("*.png")
  77. self.path("textures.xml")
  78.  
  79. def construct(self):
  80. super(ViewerManifest, self).construct()
  81. self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
  82. self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
  83.  
  84. if True: #self.is_packaging_viewer():
  85. with self.prefix(src="app_settings"):
  86. self.exclude("logcontrol.xml")
  87. self.exclude("logcontrol-dev.xml")
  88. self.path("*.crt")
  89. self.path("*.ini")
  90. self.path("*.xml")
  91. self.path("*.db2")
  92.  
  93. # include the entire shaders directory recursively
  94. self.path("shaders")
  95.  
  96. # ... and the entire windlight directory
  97. self.path("windlight")
  98.  
  99. # ... and the included spell checking dictionaries
  100. self.path("dictionaries")
  101. self.path("ca-bundle.crt")
  102.  
  103. # include the extracted packages information (see BuildPackagesInfo.cmake)
  104. self.path(src=os.path.join(self.args['build'],"packages-info.txt"), dst="packages-info.txt")
  105.  
  106. with self.prefix(src="character"):
  107. self.path("*.llm")
  108. self.path("*.xml")
  109. self.path("*.tga")
  110.  
  111. # Include our fonts
  112. with self.prefix(src="fonts"):
  113. self.path("*.ttf")
  114. self.path("*.txt")
  115.  
  116. # skins
  117. with self.prefix(src="skins"):
  118. self.path("paths.xml")
  119. self.path("default/xui/*/*.xml")
  120. self.package_skin("Default.xml", "default")
  121. self.package_skin("dark.xml", "dark")
  122. self.package_skin("Gemini.xml", "gemini")
  123.  
  124. # Local HTML files (e.g. loading screen)
  125. with self.prefix(src="*/html"):
  126. self.path("*.png")
  127. self.path("*/*/*.html")
  128. self.path("*/*/*.gif")
  129.  
  130.  
  131. # local_assets dir (for pre-cached textures)
  132. with self.prefix(src="local_assets"):
  133. self.path("*.j2c")
  134. self.path("*.tga")
  135.  
  136. # File in the newview/ directory
  137. self.path("gpu_table.txt")
  138.  
  139. #summary.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems
  140. summary_dict = {"Type":"viewer","Version":'.'.join(self.args['version']),"Channel":self.channel_with_pkg_suffix()}
  141. with open(os.path.join(os.pardir,'summary.json'), 'w') as summary_handle:
  142. json.dump(summary_dict,summary_handle)
  143.  
  144. #we likely no longer need the test, since we will throw an exception above, but belt and suspenders and we get the
  145. #return code for free.
  146. if not self.path2basename(os.pardir, "summary.json"):
  147. print "No summary.json file"
  148.  
  149. def standalone(self):
  150. return self.args['standalone'] == "ON"
  151.  
  152. def grid(self):
  153. return self.args['grid']
  154.  
  155. def sdl2(self):
  156. return self.args['sdl2'] == "ON"
  157.  
  158. def viewer_branding_id(self):
  159. return self.args['branding_id']
  160.  
  161. def channel(self):
  162. return self.args['channel']
  163.  
  164. def channel_with_pkg_suffix(self):
  165. fullchannel=self.channel()
  166. if 'channel_suffix' in self.args and self.args['channel_suffix']:
  167. fullchannel+=' '+self.args['channel_suffix']
  168. return fullchannel
  169.  
  170. def channel_variant(self):
  171. global CHANNEL_VENDOR_BASE
  172. return self.channel().replace(CHANNEL_VENDOR_BASE, "").strip()
  173.  
  174. def channel_type(self): # returns 'release', 'beta', 'project', or 'test'
  175. global CHANNEL_VENDOR_BASE
  176. channel_qualifier=self.channel().replace(CHANNEL_VENDOR_BASE, "").lower().strip()
  177. if channel_qualifier.startswith('release'):
  178. channel_type='release'
  179. elif channel_qualifier.startswith('beta'):
  180. channel_type='beta'
  181. elif channel_qualifier.startswith('alpha'):
  182. channel_type='alpha'
  183. elif channel_qualifier.startswith('project'):
  184. channel_type='project'
  185. elif channel_qualifier.startswith('canary'):
  186. channel_type='canary'
  187. else:
  188. channel_type='test'
  189. return channel_type
  190.  
  191. def channel_variant_app_suffix(self):
  192. # get any part of the channel name after the CHANNEL_VENDOR_BASE
  193. suffix=self.channel_variant()
  194. # by ancient convention, we don't use Release in the app name
  195. if self.channel_type() == 'release':
  196. suffix=suffix.replace('Release', '').strip()
  197. # for the base release viewer, suffix will now be null - for any other, append what remains
  198. if len(suffix) > 0:
  199. suffix = "_"+ ("_".join(suffix.split()))
  200. # the additional_packages mechanism adds more to the installer name (but not to the app name itself)
  201. if 'channel_suffix' in self.args and self.args['channel_suffix']:
  202. suffix+='_'+("_".join(self.args['channel_suffix'].split()))
  203. return suffix
  204.  
  205. def installer_base_name(self):
  206. global CHANNEL_VENDOR_BASE
  207. # a standard map of strings for replacing in the templates
  208. substitution_strings = {
  209. 'channel_vendor_base' : '_'.join(CHANNEL_VENDOR_BASE.split()),
  210. 'channel_variant_underscores':self.channel_variant_app_suffix(),
  211. 'version_underscores' : '_'.join(self.args['version']),
  212. 'arch':self.args['arch']
  213. }
  214. return "%(channel_vendor_base)s%(channel_variant_underscores)s_%(version_underscores)s_%(arch)s" % substitution_strings
  215.  
  216. def app_name(self):
  217. global CHANNEL_VENDOR_BASE
  218. channel_type=self.channel_type()
  219. if channel_type == 'release':
  220. app_suffix=''
  221. else:
  222. app_suffix=self.channel_variant()
  223. return CHANNEL_VENDOR_BASE + ' ' + app_suffix
  224.  
  225. def app_name_oneword(self):
  226. return ''.join(self.app_name().split())
  227.  
  228. def icon_path(self):
  229. return "icons/" + ("default", "alpha")[self.channel_type() == "alpha"]
  230.  
  231. def extract_names(self,src):
  232. try:
  233. contrib_file = open(src,'r')
  234. except IOError:
  235. print "Failed to open '%s'" % src
  236. raise
  237. lines = contrib_file.readlines()
  238. contrib_file.close()
  239.  
  240. # All lines up to and including the first blank line are the file header; skip them
  241. lines.reverse() # so that pop will pull from first to last line
  242. while not re.match("\s*$", lines.pop()) :
  243. pass # do nothing
  244.  
  245. # A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names
  246. names = []
  247. for line in lines :
  248. if re.match("\S", line) :
  249. names.append(line.rstrip())
  250. # It's not fair to always put the same people at the head of the list
  251. random.shuffle(names)
  252. return ', '.join(names)
  253.  
  254. def relsymlinkf(self, src, dst=None, catch=True):
  255. """
  256. relsymlinkf() is just like symlinkf(), but instead of requiring the
  257. caller to pass 'src' as a relative pathname, this method expects 'src'
  258. to be absolute, and creates a symlink whose target is the relative
  259. path from 'src' to dirname(dst).
  260. """
  261. dstdir, dst = self._symlinkf_prep_dst(src, dst)
  262.  
  263. # Determine the relative path starting from the directory containing
  264. # dst to the intended src.
  265. src = self.relpath(src, dstdir)
  266.  
  267. self._symlinkf(src, dst, catch)
  268. return dst
  269.  
  270. def symlinkf(self, src, dst=None, catch=True):
  271. """
  272. Like ln -sf, but uses os.symlink() instead of running ln. This creates
  273. a symlink at 'dst' that points to 'src' -- see:
  274. https://docs.python.org/2/library/os.html#os.symlink
  275.  
  276. If you omit 'dst', this creates a symlink with basename(src) at
  277. get_dst_prefix() -- in other words: put a symlink to this pathname
  278. here at the current dst prefix.
  279.  
  280. 'src' must specifically be a *relative* symlink. It makes no sense to
  281. create an absolute symlink pointing to some path on the build machine!
  282.  
  283. Also:
  284. - We prepend 'dst' with the current get_dst_prefix(), so it has similar
  285. meaning to associated self.path() calls.
  286. - We ensure that the containing directory os.path.dirname(dst) exists
  287. before attempting the symlink.
  288.  
  289. If you pass catch=False, exceptions will be propagated instead of
  290. caught.
  291. """
  292. dstdir, dst = self._symlinkf_prep_dst(src, dst)
  293. self._symlinkf(src, dst, catch)
  294. return dst
  295.  
  296. def _symlinkf_prep_dst(self, src, dst):
  297. # helper for relsymlinkf() and symlinkf()
  298. if dst is None:
  299. dst = os.path.basename(src)
  300. dst = os.path.join(self.get_dst_prefix(), dst)
  301. # Seems silly to prepend get_dst_prefix() to dst only to call
  302. # os.path.dirname() on it again, but this works even when the passed
  303. # 'dst' is itself a pathname.
  304. dstdir = os.path.dirname(dst)
  305. self.cmakedirs(dstdir)
  306. return (dstdir, dst)
  307.  
  308. def _symlinkf(self, src, dst, catch):
  309. # helper for relsymlinkf() and symlinkf()
  310. # the passed src must be relative
  311. if os.path.isabs(src):
  312. raise ManifestError("Do not symlinkf(absolute %r, asis=True)" % src)
  313.  
  314. # The outer catch is the one that reports failure even after attempted
  315. # recovery.
  316. try:
  317. # At the inner layer, recovery may be possible.
  318. try:
  319. os.symlink(src, dst)
  320. except OSError as err:
  321. if err.errno != errno.EEXIST:
  322. raise
  323. # We could just blithely attempt to remove and recreate the target
  324. # file, but that strategy doesn't work so well if we don't have
  325. # permissions to remove it. Check to see if it's already the
  326. # symlink we want, which is the usual reason for EEXIST.
  327. elif os.path.islink(dst):
  328. if os.readlink(dst) == src:
  329. # the requested link already exists
  330. pass
  331. else:
  332. # dst is the wrong symlink; attempt to remove and recreate it
  333. os.remove(dst)
  334. os.symlink(src, dst)
  335. elif os.path.isdir(dst):
  336. print "Requested symlink (%s) exists but is a directory; replacing" % dst
  337. shutil.rmtree(dst)
  338. os.symlink(src, dst)
  339. elif os.path.exists(dst):
  340. print "Requested symlink (%s) exists but is a file; replacing" % dst
  341. os.remove(dst)
  342. os.symlink(src, dst)
  343. else:
  344. # out of ideas
  345. raise
  346. except Exception as err:
  347. # report
  348. print "Can't symlink %r -> %r: %s: %s" % \
  349. (dst, src, err.__class__.__name__, err)
  350. # if caller asked us not to catch, re-raise this exception
  351. if not catch:
  352. raise
  353.  
  354. def relpath(self, path, base=None, symlink=False):
  355. """
  356. Return the relative path from 'base' to the passed 'path'. If base is
  357. omitted, self.get_dst_prefix() is assumed. In other words: make a
  358. same-name symlink to this path right here in the current dest prefix.
  359.  
  360. Normally we resolve symlinks. To retain symlinks, pass symlink=True.
  361. """
  362. if base is None:
  363. base = self.get_dst_prefix()
  364.  
  365. # Since we use os.path.relpath() for this, which is purely textual, we
  366. # must ensure that both pathnames are absolute.
  367. if symlink:
  368. # symlink=True means: we know path is (or indirects through) a
  369. # symlink, don't resolve, we want to use the symlink.
  370. abspath = os.path.abspath
  371. else:
  372. # symlink=False means to resolve any symlinks we may find
  373. abspath = os.path.realpath
  374.  
  375. return os.path.relpath(abspath(path), abspath(base))
  376.  
  377.  
  378. class WindowsManifest(ViewerManifest):
  379. # We want the platform, per se, for every Windows build to be 'win'. The
  380. # VMP will concatenate that with the address_size.
  381. build_data_json_platform = 'win'
  382.  
  383. def is_win64(self):
  384. return self.args.get('arch') == "x86_64"
  385.  
  386. def final_exe(self):
  387. return self.app_name_oneword()+"Viewer.exe"
  388.  
  389. def construct(self):
  390. super(WindowsManifest, self).construct()
  391.  
  392. pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
  393. relpkgdir = os.path.join(pkgdir, "lib", "release")
  394. debpkgdir = os.path.join(pkgdir, "lib", "debug")
  395.  
  396. if True: #self.is_packaging_viewer():
  397. # Find singularity-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
  398. self.path(src='%s/%s-bin.exe' % (self.args['configuration'],self.viewer_branding_id()), dst=self.final_exe())
  399.  
  400. # Plugin host application
  401. self.path2basename(os.path.join(os.pardir,
  402. 'llplugin', 'slplugin', self.args['configuration']),
  403. "AlchemyPlugin.exe")
  404.  
  405. # Copy assets for sdl if needed
  406. if self.sdl2():
  407. self.path("res-sdl")
  408.  
  409. # Get shared libs from the shared libs staging directory
  410. with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
  411. dst=""):
  412.  
  413. # Get llcommon and deps. If missing assume static linkage and continue.
  414. try:
  415. self.path('llcommon.dll')
  416. self.path('libapr-1.dll')
  417. self.path('libaprutil-1.dll')
  418. self.path('libapriconv-1.dll')
  419.  
  420. except RuntimeError as err:
  421. print err.message
  422. print "Skipping llcommon.dll (assuming llcommon was linked statically)"
  423.  
  424. # Mesh 3rd party libs needed for auto LOD and collada reading
  425. try:
  426. self.path("glod.dll")
  427. except RuntimeError as err:
  428. print err.message
  429. print "Skipping GLOD library (assumming linked statically)"
  430.  
  431. # Get fmodstudio dll, continue if missing
  432. try:
  433. self.path("alut.dll")
  434. self.path("OpenAL32.dll")
  435. except:
  436. print "Skipping openal audio library(assuming other audio engine)"
  437.  
  438. # For textures
  439. if self.args['configuration'].lower() == 'debug':
  440. self.path("openjpegd.dll")
  441. else:
  442. self.path("openjpeg.dll")
  443.  
  444. # Vivox runtimes
  445. self.path("SLVoice.exe")
  446. if (self.address_size == 64):
  447. self.path("vivoxsdk_x64.dll")
  448. self.path("ortp_x64.dll")
  449. else:
  450. self.path("vivoxsdk.dll")
  451. self.path("ortp.dll")
  452. self.path("libsndfile-1.dll")
  453. self.path("vivoxoal.dll")
  454.  
  455. # Security
  456. if(self.address_size == 64):
  457. self.path("libcrypto-1_1-x64.dll")
  458. self.path("libssl-1_1-x64.dll")
  459. else:
  460. self.path("libcrypto-1_1.dll")
  461. self.path("libssl-1_1.dll")
  462.  
  463. # Hunspell
  464. self.path("libhunspell.dll")
  465.  
  466. # NGHttp2
  467. self.path("nghttp2.dll")
  468.  
  469. # SDL2
  470. if self.sdl2():
  471. self.path("SDL2.dll")
  472.  
  473. # For google-perftools tcmalloc allocator.
  474. try:
  475. if self.args['configuration'].lower() == 'debug':
  476. self.path('libtcmalloc_minimal-debug.dll')
  477. else:
  478. self.path('libtcmalloc_minimal.dll')
  479. except:
  480. print "Skipping libtcmalloc_minimal.dll"
  481.  
  482. self.path(src="licenses-win32.txt", dst="licenses.txt")
  483. self.path("featuretable.txt")
  484.  
  485. # Media plugins - CEF
  486. with self.prefix(src='../media_plugins/cef/%s' % self.args['configuration'], dst="llplugin"):
  487. self.path("media_plugin_cef.dll")
  488.  
  489. # Media plugins - LibVLC
  490. with self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"):
  491. self.path("media_plugin_libvlc.dll")
  492.  
  493. # Media plugins - Example (useful for debugging - not shipped with release viewer)
  494. if self.channel_type() != 'release':
  495. with self.prefix(src='../media_plugins/example/%s' % self.args['configuration'], dst="llplugin"):
  496. self.path("media_plugin_example.dll")
  497.  
  498. # CEF runtime files - debug
  499. # CEF runtime files - not debug (release, relwithdebinfo etc.)
  500. config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release'
  501. with self.prefix(src=os.path.join(pkgdir, 'bin', config), dst="llplugin"):
  502. self.path("chrome_elf.dll")
  503. self.path("d3dcompiler_47.dll")
  504. self.path("libcef.dll")
  505. self.path("libEGL.dll")
  506. self.path("libGLESv2.dll")
  507. self.path("dullahan_host.exe")
  508. self.path("natives_blob.bin")
  509. self.path("snapshot_blob.bin")
  510. self.path("v8_context_snapshot.bin")
  511. self.path("widevinecdmadapter.dll")
  512.  
  513. # CEF runtime files for software rendering - debug
  514. if self.args['configuration'].lower() == 'debug':
  515. with self.prefix(src=os.path.join(pkgdir, 'bin', 'debug', 'swiftshader'), dst=os.path.join("llplugin", 'swiftshader')):
  516. self.path("libEGL.dll")
  517. self.path("libGLESv2.dll")
  518. else:
  519. # CEF runtime files for software rendering - not debug (release, relwithdebinfo etc.)
  520. with self.prefix(src=os.path.join(pkgdir, 'bin', 'release', 'swiftshader'), dst=os.path.join("llplugin", 'swiftshader')):
  521. self.path("libEGL.dll")
  522. self.path("libGLESv2.dll")
  523.  
  524. # CEF files common to all configurations
  525. with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="llplugin"):
  526. self.path("cef.pak")
  527. self.path("cef_100_percent.pak")
  528. self.path("cef_200_percent.pak")
  529. self.path("cef_extensions.pak")
  530. self.path("devtools_resources.pak")
  531. self.path("icudtl.dat")
  532.  
  533. with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')):
  534. self.path("am.pak")
  535. self.path("ar.pak")
  536. self.path("bg.pak")
  537. self.path("bn.pak")
  538. self.path("ca.pak")
  539. self.path("cs.pak")
  540. self.path("da.pak")
  541. self.path("de.pak")
  542. self.path("el.pak")
  543. self.path("en-GB.pak")
  544. self.path("en-US.pak")
  545. self.path("es-419.pak")
  546. self.path("es.pak")
  547. self.path("et.pak")
  548. self.path("fa.pak")
  549. self.path("fi.pak")
  550. self.path("fil.pak")
  551. self.path("fr.pak")
  552. self.path("gu.pak")
  553. self.path("he.pak")
  554. self.path("hi.pak")
  555. self.path("hr.pak")
  556. self.path("hu.pak")
  557. self.path("id.pak")
  558. self.path("it.pak")
  559. self.path("ja.pak")
  560. self.path("kn.pak")
  561. self.path("ko.pak")
  562. self.path("lt.pak")
  563. self.path("lv.pak")
  564. self.path("ml.pak")
  565. self.path("mr.pak")
  566. self.path("ms.pak")
  567. self.path("nb.pak")
  568. self.path("nl.pak")
  569. self.path("pl.pak")
  570. self.path("pt-BR.pak")
  571. self.path("pt-PT.pak")
  572. self.path("ro.pak")
  573. self.path("ru.pak")
  574. self.path("sk.pak")
  575. self.path("sl.pak")
  576. self.path("sr.pak")
  577. self.path("sv.pak")
  578. self.path("sw.pak")
  579. self.path("ta.pak")
  580. self.path("te.pak")
  581. self.path("th.pak")
  582. self.path("tr.pak")
  583. self.path("uk.pak")
  584. self.path("vi.pak")
  585. self.path("zh-CN.pak")
  586. self.path("zh-TW.pak")
  587.  
  588. with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"):
  589. self.path("libvlc.dll")
  590. self.path("libvlccore.dll")
  591. self.path("plugins/")
  592.  
  593. if (self.address_size == 64):
  594. with self.prefix(src=os.path.join(pkgdir, 'bin', 'x64'), dst=""):
  595. self.path("api-ms-win-core-console-l1-1-0.dll")
  596. self.path("api-ms-win-core-datetime-l1-1-0.dll")
  597. self.path("api-ms-win-core-debug-l1-1-0.dll")
  598. self.path("api-ms-win-core-errorhandling-l1-1-0.dll")
  599. self.path("api-ms-win-core-file-l1-1-0.dll")
  600. self.path("api-ms-win-core-file-l1-2-0.dll")
  601. self.path("api-ms-win-core-file-l2-1-0.dll")
  602. self.path("api-ms-win-core-handle-l1-1-0.dll")
  603. self.path("api-ms-win-core-heap-l1-1-0.dll")
  604. self.path("api-ms-win-core-interlocked-l1-1-0.dll")
  605. self.path("api-ms-win-core-libraryloader-l1-1-0.dll")
  606. self.path("api-ms-win-core-localization-l1-2-0.dll")
  607. self.path("api-ms-win-core-memory-l1-1-0.dll")
  608. self.path("api-ms-win-core-namedpipe-l1-1-0.dll")
  609. self.path("api-ms-win-core-processenvironment-l1-1-0.dll")
  610. self.path("api-ms-win-core-processthreads-l1-1-0.dll")
  611. self.path("api-ms-win-core-processthreads-l1-1-1.dll")
  612. self.path("api-ms-win-core-profile-l1-1-0.dll")
  613. self.path("api-ms-win-core-rtlsupport-l1-1-0.dll")
  614. self.path("api-ms-win-core-string-l1-1-0.dll")
  615. self.path("api-ms-win-core-synch-l1-1-0.dll")
  616. self.path("api-ms-win-core-synch-l1-2-0.dll")
  617. self.path("api-ms-win-core-sysinfo-l1-1-0.dll")
  618. self.path("api-ms-win-core-timezone-l1-1-0.dll")
  619. self.path("api-ms-win-core-util-l1-1-0.dll")
  620. self.path("api-ms-win-crt-conio-l1-1-0.dll")
  621. self.path("api-ms-win-crt-convert-l1-1-0.dll")
  622. self.path("api-ms-win-crt-environment-l1-1-0.dll")
  623. self.path("api-ms-win-crt-filesystem-l1-1-0.dll")
  624. self.path("api-ms-win-crt-heap-l1-1-0.dll")
  625. self.path("api-ms-win-crt-locale-l1-1-0.dll")
  626. self.path("api-ms-win-crt-math-l1-1-0.dll")
  627. self.path("api-ms-win-crt-multibyte-l1-1-0.dll")
  628. self.path("api-ms-win-crt-private-l1-1-0.dll")
  629. self.path("api-ms-win-crt-process-l1-1-0.dll")
  630. self.path("api-ms-win-crt-runtime-l1-1-0.dll")
  631. self.path("api-ms-win-crt-stdio-l1-1-0.dll")
  632. self.path("api-ms-win-crt-string-l1-1-0.dll")
  633. self.path("api-ms-win-crt-time-l1-1-0.dll")
  634. self.path("api-ms-win-crt-utility-l1-1-0.dll")
  635. self.path("concrt140.dll")
  636. self.path("msvcp140.dll")
  637. self.path("msvcp140_1.dll")
  638. self.path("msvcp140_2.dll")
  639. self.path("ucrtbase.dll")
  640. self.path("vccorlib140.dll")
  641. self.path("vcruntime140.dll")
  642. else:
  643. with self.prefix(src=os.path.join(pkgdir, 'bin', 'x86'), dst=""):
  644. self.path("api-ms-win-core-console-l1-1-0.dll")
  645. self.path("api-ms-win-core-datetime-l1-1-0.dll")
  646. self.path("api-ms-win-core-debug-l1-1-0.dll")
  647. self.path("api-ms-win-core-errorhandling-l1-1-0.dll")
  648. self.path("api-ms-win-core-file-l1-1-0.dll")
  649. self.path("api-ms-win-core-file-l1-2-0.dll")
  650. self.path("api-ms-win-core-file-l2-1-0.dll")
  651. self.path("api-ms-win-core-handle-l1-1-0.dll")
  652. self.path("api-ms-win-core-heap-l1-1-0.dll")
  653. self.path("api-ms-win-core-interlocked-l1-1-0.dll")
  654. self.path("api-ms-win-core-libraryloader-l1-1-0.dll")
  655. self.path("api-ms-win-core-localization-l1-2-0.dll")
  656. self.path("api-ms-win-core-memory-l1-1-0.dll")
  657. self.path("api-ms-win-core-namedpipe-l1-1-0.dll")
  658. self.path("api-ms-win-core-processenvironment-l1-1-0.dll")
  659. self.path("api-ms-win-core-processthreads-l1-1-0.dll")
  660. self.path("api-ms-win-core-processthreads-l1-1-1.dll")
  661. self.path("api-ms-win-core-profile-l1-1-0.dll")
  662. self.path("api-ms-win-core-rtlsupport-l1-1-0.dll")
  663. self.path("api-ms-win-core-string-l1-1-0.dll")
  664. self.path("api-ms-win-core-synch-l1-1-0.dll")
  665. self.path("api-ms-win-core-synch-l1-2-0.dll")
  666. self.path("api-ms-win-core-sysinfo-l1-1-0.dll")
  667. self.path("api-ms-win-core-timezone-l1-1-0.dll")
  668. self.path("api-ms-win-core-util-l1-1-0.dll")
  669. self.path("api-ms-win-crt-conio-l1-1-0.dll")
  670. self.path("api-ms-win-crt-convert-l1-1-0.dll")
  671. self.path("api-ms-win-crt-environment-l1-1-0.dll")
  672. self.path("api-ms-win-crt-filesystem-l1-1-0.dll")
  673. self.path("api-ms-win-crt-heap-l1-1-0.dll")
  674. self.path("api-ms-win-crt-locale-l1-1-0.dll")
  675. self.path("api-ms-win-crt-math-l1-1-0.dll")
  676. self.path("api-ms-win-crt-multibyte-l1-1-0.dll")
  677. self.path("api-ms-win-crt-private-l1-1-0.dll")
  678. self.path("api-ms-win-crt-process-l1-1-0.dll")
  679. self.path("api-ms-win-crt-runtime-l1-1-0.dll")
  680. self.path("api-ms-win-crt-stdio-l1-1-0.dll")
  681. self.path("api-ms-win-crt-string-l1-1-0.dll")
  682. self.path("api-ms-win-crt-time-l1-1-0.dll")
  683. self.path("api-ms-win-crt-utility-l1-1-0.dll")
  684. self.path("concrt140.dll")
  685. self.path("msvcp140.dll")
  686. self.path("msvcp140_1.dll")
  687. self.path("msvcp140_2.dll")
  688. self.path("ucrtbase.dll")
  689. self.path("vccorlib140.dll")
  690. self.path("vcruntime140.dll")
  691.  
  692. # pull in the crash logger and updater from other projects
  693. # tag:"crash-logger" here as a cue to the exporter
  694. self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
  695. dst="win_crash_logger.exe")
  696.  
  697. if not self.is_packaging_viewer():
  698. self.package_file = "copied_deps"
  699.  
  700. def nsi_file_commands(self, install=True):
  701. def wpath(path):
  702. if path.endswith('/') or path.endswith(os.path.sep):
  703. path = path[:-1]
  704. path = path.replace('/', '\\')
  705. return path
  706.  
  707. result = ""
  708. dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
  709. # sort deepest hierarchy first
  710. dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
  711. dest_files.reverse()
  712. out_path = None
  713. for pkg_file in dest_files:
  714. rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
  715. installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
  716. pkg_file = wpath(os.path.normpath(pkg_file))
  717. if installed_dir != out_path:
  718. if install:
  719. out_path = installed_dir
  720. result += 'SetOutPath ' + out_path + '\n'
  721. if install:
  722. result += 'File ' + pkg_file + '\n'
  723. else:
  724. result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
  725.  
  726. # at the end of a delete, just rmdir all the directories
  727. if not install:
  728. deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
  729. # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
  730. deleted_dirs = []
  731. for d in deleted_file_dirs:
  732. deleted_dirs.extend(path_ancestors(d))
  733. # sort deepest hierarchy first
  734. deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
  735. deleted_dirs.reverse()
  736. prev = None
  737. for d in deleted_dirs:
  738. if d != prev: # skip duplicates
  739. result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
  740. prev = d
  741.  
  742. return result
  743.  
  744. def sign_command(self, *argv):
  745. return [
  746. "signtool.exe", "sign", "/v",
  747. "/n", self.args['signature'],
  748. "/p", os.environ['VIEWER_SIGNING_PWD'],
  749. "/d","%s" % self.channel(),
  750. "/t","http://timestamp.comodoca.com/authenticode"
  751. ] + list(argv)
  752.  
  753. def sign(self, *argv):
  754. subprocess.check_call(self.sign_command(*argv))
  755.  
  756. def package_finish(self):
  757. if 'signature' in self.args and 'VIEWER_SIGNING_PWD' in os.environ:
  758. try:
  759. self.sign(self.args['configuration']+"\\"+self.final_exe())
  760. self.sign(self.args['configuration']+"\\AlchemyPlugin.exe")
  761. self.sign(self.args['configuration']+"\\SLVoice.exe")
  762. except:
  763. print "Couldn't sign binaries. Tried to sign %s" % self.args['configuration'] + "\\" + self.final_exe()
  764.  
  765. # a standard map of strings for replacing in the templates
  766. substitution_strings = {
  767. 'version' : '.'.join(self.args['version']),
  768. 'version_short' : '.'.join(self.args['version'][:-1]),
  769. 'version_dashes' : '-'.join(self.args['version']),
  770. 'final_exe' : self.final_exe(),
  771. 'flags':'',
  772. 'app_name':self.app_name(),
  773. 'app_name_oneword':self.app_name_oneword()
  774. }
  775.  
  776. installer_file = self.installer_base_name() + '_Setup.exe'
  777. substitution_strings['installer_file'] = installer_file
  778.  
  779. version_vars = """
  780. !define INSTEXE "%(final_exe)s"
  781. !define VERSION "%(version_short)s"
  782. !define VERSION_LONG "%(version)s"
  783. !define VERSION_DASHES "%(version_dashes)s"
  784. """ % substitution_strings
  785.  
  786. if self.channel_type() == 'release':
  787. substitution_strings['caption'] = CHANNEL_VENDOR_BASE
  788. else:
  789. substitution_strings['caption'] = self.app_name() + ' ${VERSION}'
  790.  
  791. inst_vars_template = """
  792. !define INSTOUTFILE "%(installer_file)s"
  793. !define INSTEXE "%(final_exe)s"
  794. !define APPNAME "%(app_name)s"
  795. !define APPNAMEONEWORD "%(app_name_oneword)s"
  796. !define VERSION "%(version_short)s"
  797. !define VERSION_LONG "%(version)s"
  798. !define VERSION_DASHES "%(version_dashes)s"
  799. !define URLNAME "secondlife"
  800. !define CAPTIONSTR "%(caption)s"
  801. !define VENDORSTR "Singularity Viewer Project"
  802. """
  803.  
  804. tempfile = "%s_setup_tmp.nsi" % self.viewer_branding_id()
  805. # the following replaces strings in the nsi template
  806. # it also does python-style % substitution
  807. self.replace_in("installers/windows/installer_template.nsi", tempfile, {
  808. "%%VERSION%%":version_vars,
  809. "%%SOURCE%%":self.get_src_prefix(),
  810. "%%INST_VARS%%":inst_vars_template % substitution_strings,
  811. "%%INSTALL_FILES%%":self.nsi_file_commands(True),
  812. "%%DELETE_FILES%%":self.nsi_file_commands(False),
  813. "%%WIN64_BIN_BUILD%%":"!define WIN64_BIN_BUILD 1" if self.is_win64() else "",
  814. })
  815.  
  816. # We use the Unicode version of NSIS, available from
  817. # http://www.scratchpaper.com/
  818. try:
  819. import _winreg as reg
  820. NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS") + '\\makensis.exe'
  821. self.run_command([proper_windows_path(NSIS_path), self.dst_path_of(tempfile)])
  822. except:
  823. try:
  824. NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\makensis.exe'
  825. self.run_command([proper_windows_path(NSIS_path), self.dst_path_of(tempfile)])
  826. except:
  827. NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\makensis.exe'
  828. self.run_command([proper_windows_path(NSIS_path),self.dst_path_of(tempfile)])
  829.  
  830.  
  831. # self.remove(self.dst_path_of(tempfile))
  832. if 'signature' in self.args and 'VIEWER_SIGNING_PWD' in os.environ:
  833. try:
  834. self.sign(self.args['configuration'] + "\\" + substitution_strings['installer_file'])
  835. except:
  836. print "Couldn't sign windows installer. Tried to sign %s" % self.args['configuration'] + "\\" + substitution_strings['installer_file']
  837.  
  838. self.created_path(self.dst_path_of(installer_file))
  839. self.package_file = installer_file
  840.  
  841. def escape_slashes(self, path):
  842. return path.replace('\\', '\\\\\\\\')
  843.  
  844. class Windows_i686_Manifest(WindowsManifest):
  845. # Although we aren't literally passed ADDRESS_SIZE, we can infer it from
  846. # the passed 'arch', which is used to select the specific subclass.
  847. address_size = 32
  848. def construct(self):
  849. super(Windows_i686_Manifest, self).construct()
  850.  
  851. # Get shared libs from the shared libs staging directory
  852. if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
  853. dst=""):
  854.  
  855. # Get fmod studio dll, continue if missing
  856. try:
  857. if self.args['configuration'].lower() == 'debug':
  858. self.path("fmodL.dll")
  859. else:
  860. self.path("fmod.dll")
  861. except:
  862. print "Skipping fmodstudio audio library(assuming other audio engine)"
  863.  
  864. self.end_prefix()
  865.  
  866. if self.prefix(src=os.path.join(self.args['build'], os.pardir, 'packages', 'bin'), dst="redist"):
  867. self.path("vc_redist.x86.exe")
  868. self.end_prefix()
  869.  
  870.  
  871. class Windows_x86_64_Manifest(WindowsManifest):
  872. address_size = 64
  873. def construct(self):
  874. super(Windows_x86_64_Manifest, self).construct()
  875.  
  876. # Get shared libs from the shared libs staging directory
  877. if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
  878. dst=""):
  879.  
  880. # Get fmodstudio dll, continue if missing
  881. try:
  882. if self.args['configuration'].lower() == 'debug':
  883. self.path("fmodL64.dll")
  884. else:
  885. self.path("fmod64.dll")
  886. except:
  887. print "Skipping fmodstudio audio library(assuming other audio engine)"
  888.  
  889. self.end_prefix()
  890.  
  891. if self.prefix(src=os.path.join(self.args['build'], os.pardir, 'packages', 'bin'), dst="redist"):
  892. self.path("vc_redist.x64.exe")
  893. self.end_prefix()
  894.  
  895.  
  896. class DarwinManifest(ViewerManifest):
  897. build_data_json_platform = 'mac'
  898.  
  899. def finish_build_data_dict(self, build_data_dict):
  900. build_data_dict.update({'Bundle Id':self.args['bundleid']})
  901. return build_data_dict
  902.  
  903. def is_packaging_viewer(self):
  904. # darwin requires full app bundle packaging even for debugging.
  905. return True
  906.  
  907. def construct(self):
  908. # copy over the build result (this is a no-op if run within the xcode script)
  909. self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="")
  910.  
  911. pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
  912. relpkgdir = os.path.join(pkgdir, "lib", "release")
  913. debpkgdir = os.path.join(pkgdir, "lib", "debug")
  914. relbinpkgdir = os.path.join(pkgdir, "bin", "release")
  915.  
  916. with self.prefix(src="", dst="Contents"): # everything goes in Contents
  917. self.path("Info.plist", dst="Info.plist")
  918.  
  919. # copy additional libs in <bundle>/Contents/MacOS/
  920. self.path(os.path.join(relpkgdir, "libndofdev.dylib"), dst="Resources/libndofdev.dylib")
  921.  
  922. # Make a symlink to a nested app Frameworks directory that doesn't
  923. # yet exist. We shouldn't need this; the only things that need
  924. # Frameworks are nested apps under viewer_app, and they should
  925. # simply find its Contents/Frameworks by relative pathnames. But
  926. # empirically, we do: if we omit this symlink, CEF doesn't work --
  927. # the login splash screen doesn't even display. SIIIIGH.
  928. # We're passing a path that's already relative, hence symlinkf()
  929. # rather than relsymlinkf().
  930. self.symlinkf(os.path.join("Resources", "Frameworks"))
  931.  
  932. # most everything goes in the Resources directory
  933. with self.prefix(src="", dst="Resources"):
  934. super(DarwinManifest, self).construct()
  935.  
  936. with self.prefix("cursors_mac"):
  937. self.path("*.tif")
  938.  
  939. self.path("featuretable_mac.txt")
  940.  
  941. icon_path = self.icon_path()
  942. with self.prefix(src=icon_path, dst="") :
  943. self.path("%s.icns" % self.viewer_branding_id())
  944.  
  945. self.path("%s.nib" % self.viewer_branding_id())
  946.  
  947. # Translations
  948. self.path("English.lproj/language.txt")
  949. self.replace_in(src="English.lproj/InfoPlist.strings",
  950. dst="English.lproj/InfoPlist.strings",
  951. searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
  952. )
  953. self.path("German.lproj")
  954. self.path("Japanese.lproj")
  955. self.path("Korean.lproj")
  956. self.path("da.lproj")
  957. self.path("es.lproj")
  958. self.path("fr.lproj")
  959. self.path("hu.lproj")
  960. self.path("it.lproj")
  961. self.path("nl.lproj")
  962. self.path("pl.lproj")
  963. self.path("pt.lproj")
  964. self.path("ru.lproj")
  965. self.path("tr.lproj")
  966. self.path("uk.lproj")
  967. self.path("zh-Hans.lproj")
  968.  
  969. def path_optional(src, dst):
  970. """
  971. For a number of our self.path() calls, not only do we want
  972. to deal with the absence of src, we also want to remember
  973. which were present. Return either an empty list (absent)
  974. or a list containing dst (present). Concatenate these
  975. return values to get a list of all libs that are present.
  976. """
  977. # This was simple before we started needing to pass
  978. # wildcards. Fortunately, self.path() ends up appending a
  979. # (source, dest) pair to self.file_list for every expanded
  980. # file processed. Remember its size before the call.
  981. oldlen = len(self.file_list)
  982. self.path(src, dst)
  983. # The dest appended to self.file_list has been prepended
  984. # with self.get_dst_prefix(). Strip it off again.
  985. added = [os.path.relpath(d, self.get_dst_prefix())
  986. for s, d in self.file_list[oldlen:]]
  987. if not added:
  988. print "Skipping %s" % dst
  989. return added
  990.  
  991. # dylibs is a list of all the .dylib files we expect to need
  992. # in our bundled sub-apps. For each of these we'll create a
  993. # symlink from sub-app/Contents/Resources to the real .dylib.
  994. # Need to get the llcommon dll from any of the build directories as well.
  995. libfile = "libllcommon.dylib"
  996. dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir,
  997. "llcommon",
  998. self.args['configuration'],
  999. libfile),
  1000. os.path.join(relpkgdir, libfile)),
  1001. dst=libfile)
  1002.  
  1003. for libfile in (
  1004. "libapr-1.0.dylib",
  1005. "libaprutil-1.0.dylib",
  1006. "libexception_handler.dylib",
  1007. "libGLOD.dylib",
  1008. "libopenjpeg.dylib",
  1009. "libfreetype.6.dylib",
  1010. ):
  1011. dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
  1012.  
  1013. # SLVoice and vivox lols, no symlinks needed
  1014. for libfile in (
  1015. 'libortp.dylib',
  1016. 'libsndfile.dylib',
  1017. 'libvivoxoal.dylib',
  1018. 'libvivoxsdk.dylib',
  1019. 'libvivoxplatform.dylib',
  1020. 'SLVoice',
  1021. ):
  1022. self.path2basename(relpkgdir, libfile)
  1023.  
  1024. # dylibs that vary based on configuration
  1025. if self.args['configuration'].lower() == 'debug':
  1026. for libfile in (
  1027. "libfmodL.dylib",
  1028. ):
  1029. dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
  1030. else:
  1031. for libfile in (
  1032. "libfmod.dylib",
  1033. ):
  1034. dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
  1035.  
  1036. # our apps
  1037. for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
  1038. # plugin launcher
  1039. (os.path.join("llplugin", "slplugin"), "AlchemyPlugin.app"),
  1040. ):
  1041. self.path2basename(os.path.join(os.pardir,
  1042. app_bld_dir, self.args['configuration']),
  1043. app)
  1044.  
  1045. # our apps dependencies on shared libs
  1046. # for each app, for each dylib we collected in dylibs,
  1047. # create a symlink to the real copy of the dylib.
  1048. resource_path = self.dst_path_of(os.path.join(app, "Contents", "Resources"))
  1049. for libfile in dylibs:
  1050. src = os.path.join(os.pardir, os.pardir, os.pardir, libfile)
  1051. dst = os.path.join(resource_path, libfile)
  1052. try:
  1053. self.symlinkf(src, dst)
  1054. except OSError as err:
  1055. print "Can't symlink %s -> %s: %s" % (src, dst, err)
  1056.  
  1057. # Dullahan helper apps go inside AlchemyPlugin.app
  1058. with self.prefix(src="", dst="AlchemyPlugin.app/Contents/Frameworks"):
  1059. helperappfile = 'DullahanHelper.app'
  1060. self.path2basename(relbinpkgdir, helperappfile)
  1061.  
  1062. pluginframeworkpath = self.dst_path_of('Chromium Embedded Framework.framework');
  1063. # Putting a Frameworks directory under Contents/MacOS
  1064. # isn't canonical, but the path baked into Dullahan
  1065. # Helper.app/Contents/MacOS/DullahanHelper is:
  1066. # @executable_path/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework
  1067. # (notice, not @executable_path/../Frameworks/etc.)
  1068. # So we'll create a symlink (below) from there back to the
  1069. # Frameworks directory nested under SLPlugin.app.
  1070. helperframeworkpath = \
  1071. self.dst_path_of('DullahanHelper.app/Contents/MacOS/'
  1072. 'Frameworks/Chromium Embedded Framework.framework')
  1073.  
  1074. helperexecutablepath = self.dst_path_of('DullahanHelper.app/Contents/MacOS/DullahanHelper')
  1075. self.run_command(['install_name_tool', '-change',
  1076. '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework',
  1077. '@executable_path/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework', helperexecutablepath])
  1078.  
  1079.  
  1080. # SLPlugin plugins
  1081. with self.prefix(src="", dst="llplugin"):
  1082. self.path2basename("../media_plugins/cef/" + self.args['configuration'],
  1083. "media_plugin_cef.dylib")
  1084.  
  1085. # copy LibVLC plugin itself
  1086. self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
  1087. "media_plugin_libvlc.dylib")
  1088.  
  1089. # copy LibVLC dynamic libraries
  1090. with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'release' ), dst="lib"):
  1091. self.path( "libvlc*.dylib*" )
  1092.  
  1093. # copy LibVLC plugins folder
  1094. with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'release', 'plugins' ), dst="lib"):
  1095. self.path( "*.dylib" )
  1096. self.path( "plugins.dat" )
  1097.  
  1098. # do this install_name_tool *after* media plugin is copied over
  1099. dylibexecutablepath = self.dst_path_of('media_plugin_cef.dylib')
  1100. self.run_command(['install_name_tool', '-change',
  1101. '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework',
  1102. '@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework', dylibexecutablepath])
  1103.  
  1104.  
  1105. # CEF framework goes inside Alchemy.app/Contents/Frameworks
  1106. with self.prefix(src="", dst="Frameworks"):
  1107. frameworkfile="Chromium Embedded Framework.framework"
  1108. self.path2basename(relbinpkgdir, frameworkfile)
  1109.  
  1110. # This code constructs a relative path from the
  1111. # target framework folder back to the location of the symlink.
  1112. # It needs to be relative so that the symlink still works when
  1113. # (as is normal) the user moves the app bundle out of the DMG
  1114. # and into the /Applications folder. Note we also call 'raise'
  1115. # to terminate the process if we get an error since without
  1116. # this symlink, Second Life web media can't possibly work.
  1117. # Real Framework folder:
  1118. # Alchemy.app/Contents/Frameworks/Chromium Embedded Framework.framework/
  1119. # Location of symlink and why it's relative
  1120. # Alchemy.app/Contents/Resources/AlchemyPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework/
  1121. # Real Frameworks folder, with the symlink inside the bundled SLPlugin.app (and why it's relative)
  1122. # <top level>.app/Contents/Frameworks/Chromium Embedded Framework.framework/
  1123. # <top level>.app/Contents/Resources/AlchemyPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework ->
  1124. # It might seem simpler just to create a symlink Frameworks to
  1125. # the parent of Chromimum Embedded Framework.framework. But
  1126. # that would create a symlink cycle, which breaks our
  1127. # packaging step. So make a symlink from Chromium Embedded
  1128. # Framework.framework to the directory of the same name, which
  1129. # is NOT an ancestor of the symlink.
  1130. frameworkpath = os.path.join(os.pardir, os.pardir, os.pardir,
  1131. os.pardir, "Frameworks",
  1132. "Chromium Embedded Framework.framework")
  1133. try:
  1134. # from AlchemyPlugin.app/Contents/Frameworks/Chromium Embedded
  1135. # Framework.framework back to
  1136. # Alchemy.app/Contents/Frameworks/Chromium Embedded Framework.framework
  1137. origin, target = pluginframeworkpath, frameworkpath
  1138. self.symlinkf(target, origin)
  1139. # from AlchemyPlugin.app/Contents/Frameworks/Dullahan
  1140. # Helper.app/Contents/MacOS/Frameworks/Chromium Embedded
  1141. # Framework.framework back to
  1142. # AlchemyPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
  1143. self.cmakedirs(os.path.dirname(helperframeworkpath))
  1144. origin = helperframeworkpath
  1145. target = os.path.join(os.pardir, frameworkpath)
  1146. self.symlinkf(target, origin)
  1147. except OSError as err:
  1148. print "Can't symlink %s -> %s: %s" % (origin, target, err)
  1149. raise
  1150.  
  1151.  
  1152. # NOTE: the -S argument to strip causes it to keep enough info for
  1153. # annotated backtraces (i.e. function names in the crash log). 'strip' with no
  1154. # arguments yields a slightly smaller binary but makes crash logs mostly useless.
  1155. # This may be desirable for the final release. Or not.
  1156. if ("package" in self.args['actions'] or
  1157. "unpacked" in self.args['actions']):
  1158. self.run_command(['strip', '-S', self.dst_path_of('Contents/MacOS/%s' % self.viewer_branding_id())])
  1159.  
  1160. def copy_finish(self):
  1161. # Force executable permissions to be set for scripts
  1162. # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
  1163. pass
  1164. # for script in 'Contents/MacOS/update_install.py',:
  1165. # self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
  1166.  
  1167. def package_finish(self):
  1168. global CHANNEL_VENDOR_BASE
  1169. # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning.
  1170. # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick.
  1171.  
  1172. volname=CHANNEL_VENDOR_BASE+" Installer" # DO NOT CHANGE without understanding comment above
  1173.  
  1174. imagename = self.installer_base_name()
  1175.  
  1176. sparsename = imagename + ".sparseimage"
  1177. finalname = imagename + ".dmg"
  1178. # make sure we don't have stale files laying about
  1179. self.remove(sparsename, finalname)
  1180.  
  1181. self.run_command(['hdiutil', 'create', sparsename,
  1182. '-volname', volname, '-fs', 'HFS+',
  1183. '-type', 'SPARSE', '-megabytes', '1300',
  1184. '-layout', 'SPUD'])
  1185.  
  1186. # mount the image and get the name of the mount point and device node
  1187. try:
  1188. hdi_output = subprocess.check_output(['hdiutil', 'attach', '-private', sparsename])
  1189. except subprocess.CalledProcessError as err:
  1190. sys.exit("failed to mount image at '%s'" % sparsename)
  1191.  
  1192. try:
  1193. devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
  1194. volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
  1195.  
  1196. if devfile != '/dev/disk1':
  1197. # adding more debugging info based upon nat's hunches to the
  1198. # logs to help track down 'SetFile -a V' failures -brad
  1199. print "WARNING: 'SetFile -a V' command below is probably gonna fail"
  1200.  
  1201. # Copy everything in to the mounted .dmg
  1202.  
  1203. app_name = self.app_name()
  1204.  
  1205. # Hack:
  1206. # Because there is no easy way to coerce the Finder into positioning
  1207. # the app bundle in the same place with different app names, we are
  1208. # adding multiple .DS_Store files to svn. There is one for release,
  1209. # one for release candidate and one for first look. Any other channels
  1210. # will use the release .DS_Store, and will look broken.
  1211. # - Ambroff 2008-08-20
  1212. dmg_template = os.path.join(
  1213. 'installers', 'darwin', '%s-dmg' % self.channel_type())
  1214.  
  1215. if not os.path.exists (self.src_path_of(dmg_template)):
  1216. dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
  1217.  
  1218. for s,d in {self.get_dst_prefix():app_name + ".app",
  1219. os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
  1220. os.path.join(dmg_template, "background.jpg"): "background.jpg",
  1221. os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
  1222. print "Copying to dmg", s, d
  1223. self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
  1224.  
  1225. # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
  1226. for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store":
  1227. pathname = os.path.join(volpath, f)
  1228. # We've observed mysterious "no such file" failures of the SetFile
  1229. # command, especially on the first file listed above -- yet
  1230. # subsequent inspection of the target directory confirms it's
  1231. # there. Timing problem with copy command? Try to handle.
  1232. for x in xrange(3):
  1233. if os.path.exists(pathname):
  1234. print "Confirmed existence: %r" % pathname
  1235. break
  1236. print "Waiting for %s copy command to complete (%s)..." % (f, x+1)
  1237. sys.stdout.flush()
  1238. time.sleep(1)
  1239. # If we fall out of the loop above without a successful break, oh
  1240. # well, possibly we've mistaken the nature of the problem. In any
  1241. # case, don't hang up the whole build looping indefinitely, let
  1242. # the original problem manifest by executing the desired command.
  1243. self.run_command(['SetFile', '-a', 'V', pathname])
  1244.  
  1245. # Create the alias file (which is a resource file) from the .r
  1246. self.run_command(
  1247. ['Rez', self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"),
  1248. '-o', os.path.join(volpath, "Applications")])
  1249.  
  1250. # Set the alias file's alias and custom icon bits
  1251. self.run_command(['SetFile', '-a', 'AC', os.path.join(volpath, "Applications")])
  1252.  
  1253. # Set the disk image root's custom icon bit
  1254. self.run_command(['SetFile', '-a', 'C', volpath])
  1255.  
  1256. # Sign the app if requested;
  1257. # do this in the copy that's in the .dmg so that the extended attributes used by
  1258. # the signature are preserved; moving the files using python will leave them behind
  1259. # and invalidate the signatures.
  1260. if 'signature' in self.args:
  1261. app_in_dmg=os.path.join(volpath,self.app_name()+".app")
  1262. print "Attempting to sign '%s'" % app_in_dmg
  1263. identity = self.args['signature']
  1264. if identity == '':
  1265. identity = 'Developer ID Application'
  1266.  
  1267. # Look for an environment variable set via build.sh when running in Team City.
  1268. try:
  1269. build_secrets_checkout = os.environ['build_secrets_checkout']
  1270. except KeyError:
  1271. pass
  1272. else:
  1273. # variable found so use it to unlock keychain followed by codesign
  1274. home_path = os.environ['HOME']
  1275. keychain_pwd_path = os.path.join(build_secrets_checkout,'code-signing-osx','password.txt')
  1276. keychain_pwd = open(keychain_pwd_path).read().rstrip()
  1277.  
  1278. # Note: As of macOS Sierra, keychains are created with names postfixed with '-db' so for example, the
  1279. # SL Viewer keychain would by default be found in ~/Library/Keychains/viewer.keychain-db instead of
  1280. # just ~/Library/Keychains/viewer.keychain in earlier versions.
  1281. #
  1282. # Because we have old OS files from previous versions of macOS on the build hosts, the configurations
  1283. # are different on each host. Some have viewer.keychain, some have viewer.keychain-db and some have both.
  1284. # As you can see in the line below, this script expects the Linden Developer cert/keys to be in viewer.keychain.
  1285. #
  1286. # To correctly sign builds you need to make sure ~/Library/Keychains/viewer.keychain exists on the host
  1287. # and that it contains the correct cert/key. If a build host is set up with a clean version of macOS Sierra (or later)
  1288. # then you will need to change this line (and the one for 'codesign' command below) to point to right place or else
  1289. # pull in the cert/key into the default viewer keychain 'viewer.keychain-db' and export it to 'viewer.keychain'
  1290. viewer_keychain = os.path.join(home_path, 'Library',
  1291. 'Keychains', 'viewer.keychain')
  1292. self.run_command(['security', 'unlock-keychain',
  1293. '-p', keychain_pwd, viewer_keychain])
  1294. signed=False
  1295. sign_attempts=3
  1296. sign_retry_wait=15
  1297. while (not signed) and (sign_attempts > 0):
  1298. try:
  1299. sign_attempts-=1;
  1300. self.run_command(
  1301. # Note: See blurb above about names of keychains
  1302. ['codesign', '--verbose', '--deep', '--force',
  1303. '--keychain', viewer_keychain, '--sign', identity,
  1304. app_in_dmg])
  1305. signed=True # if no exception was raised, the codesign worked
  1306. except ManifestError as err:
  1307. if sign_attempts:
  1308. print >> sys.stderr, "codesign failed, waiting %d seconds before retrying" % sign_retry_wait
  1309. time.sleep(sign_retry_wait)
  1310. sign_retry_wait*=2
  1311. else:
  1312. print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
  1313. raise
  1314. self.run_command(['spctl', '-a', '-texec', '-vv', app_in_dmg])
  1315.  
  1316. imagename= self.app_name() + "_" + '_'.join(self.args['version'])
  1317.  
  1318.  
  1319. finally:
  1320. # Unmount the image even if exceptions from any of the above
  1321. self.run_command(['hdiutil', 'detach', '-force', devfile])
  1322.  
  1323. print "Converting temp disk image to final disk image"
  1324. self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO',
  1325. '-imagekey', 'zlib-level=9', '-o', finalname])
  1326. self.run_command(['hdiutil', 'internet-enable', '-yes', finalname])
  1327. # get rid of the temp file
  1328. self.package_file = finalname
  1329. self.remove(sparsename)
  1330.  
  1331.  
  1332. class Darwin_i386_Manifest(DarwinManifest):
  1333. address_size = 32
  1334.  
  1335.  
  1336. class Darwin_i686_Manifest(DarwinManifest):
  1337. """alias in case arch is passed as i686 instead of i386"""
  1338. pass
  1339.  
  1340.  
  1341. class Darwin_x86_64_Manifest(DarwinManifest):
  1342. address_size = 64
  1343.  
  1344.  
  1345. class LinuxManifest(ViewerManifest):
  1346. build_data_json_platform = 'lnx'
  1347.  
  1348. def is_packaging_viewer(self):
  1349. super(LinuxManifest, self).is_packaging_viewer()
  1350. return True # We always want a packaged viewer even without archive.
  1351.  
  1352. def do(self, *actions):
  1353. super(LinuxManifest, self).do(*actions)
  1354. if not 'package' in self.actions:
  1355. self.package_finish() # Always finish the package.
  1356. else:
  1357. # package_finish() was called by super.do() so just create the TAR.
  1358. self.create_archive()
  1359. return self.file_list
  1360.  
  1361. def construct(self):
  1362. import shutil
  1363. shutil.rmtree("./packaged/app_settings/shaders", ignore_errors=True);
  1364. super(LinuxManifest, self).construct()
  1365.  
  1366. self.path("licenses-linux.txt","licenses.txt")
  1367.  
  1368. pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
  1369. relpkgdir = os.path.join(pkgdir, "lib", "release")
  1370. debpkgdir = os.path.join(pkgdir, "lib", "debug")
  1371.  
  1372. with self.prefix("linux_tools", dst=""):
  1373. self.path("client-readme.txt","README-linux.txt")
  1374. self.path("client-readme-voice.txt","README-linux-voice.txt")
  1375. self.path("client-readme-joystick.txt","README-linux-joystick.txt")
  1376. self.path("wrapper.sh",self.viewer_branding_id())
  1377. with self.prefix(src="", dst="etc"):
  1378. self.path("handle_secondlifeprotocol.sh")
  1379. self.path("register_secondlifeprotocol.sh")
  1380. self.path("refresh_desktop_app_entry.sh")
  1381. self.path("launch_url.sh")
  1382. self.path("install.sh")
  1383.  
  1384. with self.prefix(src="", dst="bin"):
  1385. self.path("%s-bin"%self.viewer_branding_id(),"do-not-directly-run-%s-bin"%self.viewer_branding_id())
  1386. self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
  1387. self.path2basename("../llplugin/slplugin", "AlchemyPlugin")
  1388.  
  1389. # recurses, packaged again
  1390. self.path("res-sdl")
  1391.  
  1392. # Get the icons based on the channel type
  1393. icon_path = self.icon_path()
  1394. print "DEBUG: icon_path '%s'" % icon_path
  1395. with self.prefix(src=icon_path, dst="") :
  1396. self.path("viewer.png","viewer_icon.png")
  1397. with self.prefix(src="",dst="res-sdl") :
  1398. self.path("viewer_256.BMP","viewer_icon.BMP")
  1399.  
  1400. # plugins
  1401. with self.prefix(src="", dst="bin/llplugin"):
  1402. self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
  1403. self.path("../media_plugins/libvlc/libmedia_plugin_libvlc.so", "libmedia_plugin_libvlc.so")
  1404. self.path("../media_plugins/cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so")
  1405.  
  1406. with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"):
  1407. self.path( "plugins.dat" )
  1408. self.path( "*/*.so" )
  1409.  
  1410. with self.prefix(src=os.path.join(os.pardir, 'packages', 'lib' ), dst="lib"):
  1411. self.path( "libvlc*.so*" )
  1412.  
  1413. # CEF files
  1414. with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="bin"):
  1415. self.path("chrome-sandbox")
  1416. self.path("dullahan_host")
  1417. self.path("natives_blob.bin")
  1418. self.path("snapshot_blob.bin")
  1419. self.path("v8_context_snapshot.bin")
  1420.  
  1421. with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="bin"):
  1422. self.path("cef.pak")
  1423. self.path("cef_extensions.pak")
  1424. self.path("cef_100_percent.pak")
  1425. self.path("cef_200_percent.pak")
  1426. self.path("devtools_resources.pak")
  1427. self.path("icudtl.dat")
  1428.  
  1429. with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('bin', 'locales')):
  1430. self.path("am.pak")
  1431. self.path("ar.pak")
  1432. self.path("bg.pak")
  1433. self.path("bn.pak")
  1434. self.path("ca.pak")
  1435. self.path("cs.pak")
  1436. self.path("da.pak")
  1437. self.path("de.pak")
  1438. self.path("el.pak")
  1439. self.path("en-GB.pak")
  1440. self.path("en-US.pak")
  1441. self.path("es.pak")
  1442. self.path("es-419.pak")
  1443. self.path("et.pak")
  1444. self.path("fa.pak")
  1445. self.path("fi.pak")
  1446. self.path("fil.pak")
  1447. self.path("fr.pak")
  1448. self.path("gu.pak")
  1449. self.path("he.pak")
  1450. self.path("hi.pak")
  1451. self.path("hr.pak")
  1452. self.path("hu.pak")
  1453. self.path("id.pak")
  1454. self.path("it.pak")
  1455. self.path("ja.pak")
  1456. self.path("kn.pak")
  1457. self.path("ko.pak")
  1458. self.path("lt.pak")
  1459. self.path("lv.pak")
  1460. self.path("ml.pak")
  1461. self.path("mr.pak")
  1462. self.path("ms.pak")
  1463. self.path("nb.pak")
  1464. self.path("nl.pak")
  1465. self.path("pl.pak")
  1466. self.path("pt-BR.pak")
  1467. self.path("pt-PT.pak")
  1468. self.path("ro.pak")
  1469. self.path("ru.pak")
  1470. self.path("sk.pak")
  1471. self.path("sl.pak")
  1472. self.path("sr.pak")
  1473. self.path("sv.pak")
  1474. self.path("sw.pak")
  1475. self.path("ta.pak")
  1476. self.path("te.pak")
  1477. self.path("th.pak")
  1478. self.path("tr.pak")
  1479. self.path("uk.pak")
  1480. self.path("vi.pak")
  1481. self.path("zh-CN.pak")
  1482. self.path("zh-TW.pak")
  1483.  
  1484. # llcommon
  1485. if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"):
  1486. print "Skipping llcommon.so (assuming llcommon was linked statically)"
  1487.  
  1488. self.path("featuretable_linux.txt")
  1489.  
  1490. def package_finish(self):
  1491. installer_name = self.installer_base_name()
  1492.  
  1493. self.strip_binaries()
  1494.  
  1495. # Fix access permissions
  1496. self.run_command(['find', self.get_dst_prefix(),
  1497. '-type', 'd', '-exec', 'chmod', '755', '{}', ';'])
  1498. for old, new in ('0700', '0755'), ('0500', '0555'), ('0600', '0644'), ('0400', '0444'):
  1499. self.run_command(['find', self.get_dst_prefix(),
  1500. '-type', 'f', '-perm', old,
  1501. '-exec', 'chmod', new, '{}', ';'])
  1502.  
  1503. def create_archive(self):
  1504. # temporarily move directory tree so that it has the right
  1505. # name in the tarfile
  1506. installer_name = self.installer_base_name()
  1507. realname = self.get_dst_prefix()
  1508. tempname = self.build_path_of(installer_name)
  1509. self.run_command(['mv', realname, tempname])
  1510. try:
  1511. # --numeric-owner hides the username of the builder for
  1512. # security etc.
  1513. self.run_command(['tar', '-C', self.get_build_prefix(),
  1514. '--numeric-owner', '-cjf',
  1515. tempname + '.tar.xz', installer_name])
  1516. finally:
  1517. self.run_command(['mv', tempname, realname])
  1518. self.package_file = installer_name + '.tar.xz'
  1519.  
  1520. def strip_binaries(self):
  1521. # makes some small assumptions about our packaged dir structure
  1522. #self.run_command(r"find %(d)r/lib %(d)r/lib32 %(d)r/lib64 -type f \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} )
  1523. #self.run_command(r"find %(d)r/bin -executable -type f \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} )
  1524. try:
  1525. self.run_command(
  1526. ["find"] +
  1527. [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib', 'lib32', 'lib64')] +
  1528. ['-executable', '-type', 'f', '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';'])
  1529. except ManifestError as err:
  1530. print err.message
  1531. pass
  1532.  
  1533. class Linux_i686_Manifest(LinuxManifest):
  1534. address_size = 32
  1535.  
  1536. def construct(self):
  1537. super(Linux_i686_Manifest, self).construct()
  1538.  
  1539. pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
  1540. relpkgdir = os.path.join(pkgdir, "lib", "release")
  1541. debpkgdir = os.path.join(pkgdir, "lib", "debug")
  1542.  
  1543. with self.prefix(relpkgdir, dst="lib"):
  1544. self.path("libapr-1.so")
  1545. self.path("libapr-1.so.0")
  1546. self.path("libapr-1.so.0.5.2")
  1547. self.path("libaprutil-1.so")
  1548. self.path("libaprutil-1.so.0")
  1549. self.path("libaprutil-1.so.0.5.4")
  1550. self.path("libcef.so")
  1551. self.path("libexpat.so.*")
  1552. self.path("libGLOD.so")
  1553. self.path("libSDL-1.2.so.*")
  1554. self.path("libopenjpeg.so*")
  1555. self.path("libhunspell-1.6.so*")
  1556.  
  1557.  
  1558. self.path("libtcmalloc_minimal.so.0")
  1559. self.path("libtcmalloc_minimal.so.0.2.2")
  1560.  
  1561. # Vivox runtimes
  1562. with self.prefix(src=relpkgdir, dst="bin"):
  1563. self.path("SLVoice")
  1564. with self.prefix(src=relpkgdir, dst="lib"):
  1565. self.path("libortp.so")
  1566. self.path("libsndfile.so.1")
  1567. self.path("libvivoxoal.so.1")
  1568. self.path("libvivoxsdk.so")
  1569. self.path("libvivoxplatform.so")
  1570.  
  1571.  
  1572.  
  1573. class Linux_x86_64_Manifest(LinuxManifest):
  1574. address_size = 64
  1575.  
  1576. def construct(self):
  1577. super(Linux_x86_64_Manifest, self).construct()
  1578.  
  1579. pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
  1580. relpkgdir = os.path.join(pkgdir, "lib", "release")
  1581. debpkgdir = os.path.join(pkgdir, "lib", "debug")
  1582.  
  1583. if (not self.standalone()) and self.prefix(relpkgdir, dst="lib64"):
  1584. self.path("libapr-1.so*")
  1585. self.path("libaprutil-1.so*")
  1586. self.path("libexpat.so*")
  1587. self.path("libGLOD.so")
  1588. self.path("libSDL-1.2.so.*")
  1589. self.path("libopenjpeg.so*")
  1590. self.path("libhunspell-1.6.so*")
  1591. self.path("libalut.so*")
  1592. self.path("libopenal.so*")
  1593. #self.path("libfreetype.so*")
  1594.  
  1595. try:
  1596. self.path("libtcmalloc.so*") #formerly called google perf tools
  1597. pass
  1598. except:
  1599. print "tcmalloc files not found, skipping"
  1600. pass
  1601.  
  1602. try:
  1603. self.path("libfmod.so*")
  1604. pass
  1605. except:
  1606. print "Skipping libfmod.so - not found"
  1607. pass
  1608.  
  1609. self.end_prefix("lib64")
  1610.  
  1611. # Vivox runtimes
  1612. with self.prefix(src=relpkgdir, dst="bin"):
  1613. self.path("SLVoice")
  1614.  
  1615. with self.prefix(src=relpkgdir, dst="lib32"):
  1616. self.path("libortp.so")
  1617. self.path("libsndfile.so.1")
  1618. self.path("libvivoxoal.so.1")
  1619. self.path("libvivoxsdk.so")
  1620. self.path("libvivoxplatform.so")
  1621.  
  1622. # plugin runtime
  1623. with self.prefix(src=relpkgdir, dst="lib64"):
  1624. self.path("libcef.so")
  1625.  
  1626.  
  1627. ################################################################
  1628.  
  1629. if __name__ == "__main__":
  1630. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement