summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Riebeling <Dominik.Riebeling@gmail.com>2010-08-30 17:51:53 +0000
committerDominik Riebeling <Dominik.Riebeling@gmail.com>2010-08-30 17:51:53 +0000
commit4756a77b47cc4a0c86315d8949468b347268c8eb (patch)
tree0d88c08afd0e5a1ad710d7922f41817cd09bd190
parent811877e5b3ae95b70e285b786bb7cc9d73d333e0 (diff)
downloadrockbox-4756a77b47cc4a0c86315d8949468b347268c8eb.tar.gz
rockbox-4756a77b47cc4a0c86315d8949468b347268c8eb.zip
Support resolving of DLLs when running on Windows.
Resolve the DLLs required by the built executable and try to add the required DLL files that are not recognized as system libraries to the resulting zip / NSIS installer. This means that it's now possible to easily build both Theme Editor and Rockbox Utility as dynamically linked binary without the risk of missing required DLLs in the package. The major advantage of this is that it's not necessary anymore to have a statically built Qt installation for building releases. The drawback is that the created binaries will rely on additional DLL files, so it's no longer a single-run binary. Binary release of Rockbox Utility should still be statically build. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27945 a1c6a512-1295-4272-9138-f99709370657
-rwxr-xr-xutils/common/deploy.py110
1 files changed, 97 insertions, 13 deletions
diff --git a/utils/common/deploy.py b/utils/common/deploy.py
index 662a104e34..9912bfc2ca 100755
--- a/utils/common/deploy.py
+++ b/utils/common/deploy.py
@@ -82,6 +82,25 @@ useupx = False
82# OS X: files to copy into the bundle. Workaround for out-of-tree builds. 82# OS X: files to copy into the bundle. Workaround for out-of-tree builds.
83bundlecopy = { } 83bundlecopy = { }
84 84
85# DLL files to ignore when searching for required DLL files.
86systemdlls = ['advapi32.dll',
87 'comdlg32.dll',
88 'gdi32.dll',
89 'imm32.dll',
90 'kernel32.dll',
91 'msvcrt.dll',
92 'msvcrt.dll',
93 'netapi32.dll',
94 'ole32.dll',
95 'oleaut32.dll',
96 'setupapi.dll',
97 'shell32.dll',
98 'user32.dll',
99 'winmm.dll',
100 'winspool.drv',
101 'ws2_32.dll']
102
103
85# == Functions == 104# == Functions ==
86def usage(myself): 105def usage(myself):
87 print "Usage: %s [options]" % myself 106 print "Usage: %s [options]" % myself
@@ -238,19 +257,22 @@ def upxfile(wd="."):
238 return 0 257 return 0
239 258
240 259
241def runnsis(versionstring, nsis, srcfolder): 260def runnsis(versionstring, nsis, script, srcfolder):
242 # run script through nsis to create installer. 261 # run script through nsis to create installer.
243 print "Running NSIS ..." 262 print "Running NSIS ..."
263
244 # Assume the generated installer gets placed in the same folder the nsi 264 # Assume the generated installer gets placed in the same folder the nsi
245 # script lives in. This seems to be a valid assumption unless the nsi 265 # script lives in. This seems to be a valid assumption unless the nsi
246 # script specifies a path. NSIS expects files relative to source folder so 266 # script specifies a path. NSIS expects files relative to source folder so
247 # copy the relevant binaries. 267 # copy progexe. Additional files are injected into the nsis script.
248 for f in programfiles: 268
249 b = srcfolder + "/" + os.path.dirname(nsisscript) + "/" + os.path.dirname(f) 269 # FIXME: instead of copying binaries around copy the NSI file and inject
250 if not os.path.exists(b): 270 # the correct paths.
251 os.mkdir(b) 271 b = srcfolder + "/" + os.path.dirname(script) + "/" + os.path.dirname(progexe)
252 shutil.copy(srcfolder + "/" + f, b) 272 if not os.path.exists(b):
253 output = subprocess.Popen([nsis, srcfolder + "/" + nsisscript], stdout=subprocess.PIPE) 273 os.mkdir(b)
274 shutil.copy(srcfolder + "/" + progexe, b)
275 output = subprocess.Popen([nsis, srcfolder + "/" + script], stdout=subprocess.PIPE)
254 output.communicate() 276 output.communicate()
255 if not output.returncode == 0: 277 if not output.returncode == 0:
256 print "NSIS failed!" 278 print "NSIS failed!"
@@ -258,16 +280,70 @@ def runnsis(versionstring, nsis, srcfolder):
258 setupfile = program + "-" + versionstring + "-setup.exe" 280 setupfile = program + "-" + versionstring + "-setup.exe"
259 # find output filename in nsis script file 281 # find output filename in nsis script file
260 nsissetup = "" 282 nsissetup = ""
261 for line in open(srcfolder + "/" + nsisscript): 283 for line in open(srcfolder + "/" + script):
262 if re.match(r'^[^;]*OutFile\s+', line) != None: 284 if re.match(r'^[^;]*OutFile\s+', line) != None:
263 nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip() 285 nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip()
264 if nsissetup == "": 286 if nsissetup == "":
265 print "Could not retrieve output file name!" 287 print "Could not retrieve output file name!"
266 return -1 288 return -1
267 shutil.copy(srcfolder + "/" + os.path.dirname(nsisscript) + "/" + nsissetup, setupfile) 289 shutil.copy(srcfolder + "/" + os.path.dirname(script) + "/" + nsissetup, setupfile)
268 return 0 290 return 0
269 291
270 292
293def nsisfileinject(nsis, outscript, filelist):
294 '''Inject files in filelist into NSIS script file after the File line
295 containing the main binary. This assumes that the main binary is present
296 in the NSIS script and that all additiona files (dlls etc) to get placed
297 into $INSTDIR.'''
298 output = open(outscript, "w")
299 for line in open(nsis, "r"):
300 output.write(line)
301 # inject files after the progexe binary. Match the basename only to avoid path mismatches.
302 if re.match(r'^\s*File\s*.*' + os.path.basename(progexe), line, re.IGNORECASE):
303 for f in filelist:
304 injection = " File /oname=$INSTDIR\\" + os.path.basename(f) + " " + os.path.normcase(f) + "\n"
305 output.write(injection)
306 output.write(" ; end of injected files\n")
307 output.close()
308
309
310def finddlls(program, extrapaths = []):
311 '''Check program for required DLLs. Find all required DLLs except ignored
312 ones and return a list of DLL filenames (including path).'''
313 # ask objdump about dependencies.
314 output = subprocess.Popen(["objdump", "-x", program], stdout=subprocess.PIPE)
315 cmdout = output.communicate()
316
317 # create list of used DLLs. Store as lower case as W32 is case-insensitive.
318 dlls = []
319 for line in cmdout[0].split('\n'):
320 if re.match(r'\s*DLL Name', line) != None:
321 dll = re.sub(r'^\s*DLL Name:\s+([a-zA-Z_\-0-9\.]+).*$', r'\1', line)
322 dlls.append(dll.lower())
323
324 # find DLLs in extrapaths and PATH environment variable.
325 dllpaths = []
326 for file in dlls:
327 if file in systemdlls:
328 print file + ": System DLL"
329 continue
330 dllpath = ""
331 for path in extrapaths:
332 if os.path.exists(path + "/" + file):
333 dllpath = re.sub(r"\\", r"/", path + "/" + file)
334 print file + ": found at " + dllpath
335 dllpaths.append(dllpath)
336 break
337 if dllpath == "":
338 try:
339 dllpath = re.sub(r"\\", r"/", which.which(file))
340 print file + ": found at " + dllpath
341 dllpaths.append(dllpath)
342 except:
343 print file + ": NOT FOUND."
344 return dllpaths
345
346
271def zipball(versionstring, buildfolder): 347def zipball(versionstring, buildfolder):
272 '''package created binary''' 348 '''package created binary'''
273 print "Creating binary zipball." 349 print "Creating binary zipball."
@@ -278,7 +354,10 @@ def zipball(versionstring, buildfolder):
278 os.mkdir(outfolder) 354 os.mkdir(outfolder)
279 # move program files to output folder 355 # move program files to output folder
280 for f in programfiles: 356 for f in programfiles:
281 shutil.copy(buildfolder + "/" + f, outfolder) 357 if re.match(r'^(/|[a-zA-Z]:)', f) != None:
358 shutil.copy(f, outfolder)
359 else:
360 shutil.copy(buildfolder + "/" + f, outfolder)
282 # create zipball from output folder 361 # create zipball from output folder
283 zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED) 362 zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED)
284 for root, dirs, files in os.walk(outfolder): 363 for root, dirs, files in os.walk(outfolder):
@@ -503,15 +582,20 @@ def deploy():
503 if not upxfile(sourcefolder) == 0: 582 if not upxfile(sourcefolder) == 0:
504 tempclean(workfolder, cleanup and not keeptemp) 583 tempclean(workfolder, cleanup and not keeptemp)
505 sys.exit(1) 584 sys.exit(1)
585 dllfiles = finddlls(sourcefolder + "/" + progexe, [os.path.dirname(qm)])
586 if dllfiles.count > 0:
587 programfiles.extend(dllfiles)
506 archive = zipball(ver, sourcefolder) 588 archive = zipball(ver, sourcefolder)
589 # only when running native right now.
590 if nsisscript != "" and makensis != "":
591 nsisfileinject(sourcefolder + "/" + nsisscript, sourcefolder + "/" + nsisscript + ".tmp", dllfiles)
592 runnsis(ver, makensis, nsisscript + ".tmp", sourcefolder)
507 elif sys.platform == "darwin": 593 elif sys.platform == "darwin":
508 archive = macdeploy(ver, sourcefolder) 594 archive = macdeploy(ver, sourcefolder)
509 else: 595 else:
510 if os.uname()[4].endswith("64"): 596 if os.uname()[4].endswith("64"):
511 ver += "-64bit" 597 ver += "-64bit"
512 archive = tarball(ver, sourcefolder) 598 archive = tarball(ver, sourcefolder)
513 if nsisscript != "" and makensis != "":
514 runnsis(ver, makensis, sourcefolder)
515 599
516 # remove temporary files 600 # remove temporary files
517 tempclean(workfolder, cleanup) 601 tempclean(workfolder, cleanup)