merge of '7515f43924dd61866be5833ca02d8cc7252e7ebc'
[vuplus_openembedded] / classes / package.bbclass
1 #
2 # General packaging help functions
3 #
4
5 PKGDEST = "${WORKDIR}/install"
6
7 def legitimize_package_name(s):
8         """
9         Make sure package names are legitimate strings
10         """
11         import re
12
13         def fixutf(m):
14                 cp = m.group(1)
15                 if cp:
16                         return ('\u%s' % cp).decode('unicode_escape').encode('utf-8')
17
18         # Handle unicode codepoints encoded as <U0123>, as in glibc locale files.
19         s = re.sub('<U([0-9A-Fa-f]{1,4})>', fixutf, s)
20
21         # Remaining package name validity fixes
22         return s.lower().replace('_', '-').replace('@', '+').replace(',', '+').replace('/', '-')
23
24 def do_split_packages(d, root, file_regex, output_pattern, description, postinst=None, recursive=False, hook=None, extra_depends=None, aux_files_pattern=None, postrm=None, allow_dirs=False, prepend=False, match_path=False, aux_files_pattern_verbatim=None):
25         """
26         Used in .bb files to split up dynamically generated subpackages of a 
27         given package, usually plugins or modules.
28         """
29         import os, os.path, bb
30
31         dvar = bb.data.getVar('D', d, 1)
32         if not dvar:
33                 bb.error("D not defined")
34                 return
35
36         packages = bb.data.getVar('PACKAGES', d, 1).split()
37
38         if postinst:
39                 postinst = '#!/bin/sh\n' + postinst + '\n'
40         if postrm:
41                 postrm = '#!/bin/sh\n' + postrm + '\n'
42         if not recursive:
43                 objs = os.listdir(dvar + root)
44         else:
45                 objs = []
46                 for walkroot, dirs, files in os.walk(dvar + root):
47                         for file in files:
48                                 relpath = os.path.join(walkroot, file).replace(dvar + root + '/', '', 1)
49                                 if relpath:
50                                         objs.append(relpath)
51
52         if extra_depends == None:
53                 # This is *really* broken
54                 mainpkg = packages[0]
55                 # At least try and patch it up I guess...
56                 if mainpkg.find('-dbg'):
57                         mainpkg = mainpkg.replace('-dbg', '')
58                 if mainpkg.find('-dev'):
59                         mainpkg = mainpkg.replace('-dev', '')
60                 extra_depends = mainpkg
61
62         for o in objs:
63                 import re, stat
64                 if match_path:
65                         m = re.match(file_regex, o)
66                 else:
67                         m = re.match(file_regex, os.path.basename(o))
68                 
69                 if not m:
70                         continue
71                 f = os.path.join(dvar + root, o)
72                 mode = os.lstat(f).st_mode
73                 if not (stat.S_ISREG(mode) or (allow_dirs and stat.S_ISDIR(mode))):
74                         continue
75                 on = legitimize_package_name(m.group(1))
76                 pkg = output_pattern % on
77                 if not pkg in packages:
78                         if prepend:
79                                 packages = [pkg] + packages
80                         else:
81                                 packages.append(pkg)
82                         the_files = [os.path.join(root, o)]
83                         if aux_files_pattern:
84                                 if type(aux_files_pattern) is list:
85                                         for fp in aux_files_pattern:
86                                                 the_files.append(fp % on)       
87                                 else:
88                                         the_files.append(aux_files_pattern % on)
89                         if aux_files_pattern_verbatim:
90                                 if type(aux_files_pattern_verbatim) is list:
91                                         for fp in aux_files_pattern_verbatim:
92                                                 the_files.append(fp % m.group(1))       
93                                 else:
94                                         the_files.append(aux_files_pattern_verbatim % m.group(1))
95                         bb.data.setVar('FILES_' + pkg, " ".join(the_files), d)
96                         if extra_depends != '':
97                                 the_depends = bb.data.getVar('RDEPENDS_' + pkg, d, 1)
98                                 if the_depends:
99                                         the_depends = '%s %s' % (the_depends, extra_depends)
100                                 else:
101                                         the_depends = extra_depends
102                                 bb.data.setVar('RDEPENDS_' + pkg, the_depends, d)
103                         bb.data.setVar('DESCRIPTION_' + pkg, description % on, d)
104                         if postinst:
105                                 bb.data.setVar('pkg_postinst_' + pkg, postinst, d)
106                         if postrm:
107                                 bb.data.setVar('pkg_postrm_' + pkg, postrm, d)
108                 else:
109                         oldfiles = bb.data.getVar('FILES_' + pkg, d, 1)
110                         if not oldfiles:
111                                 bb.fatal("Package '%s' exists but has no files" % pkg)
112                         bb.data.setVar('FILES_' + pkg, oldfiles + " " + os.path.join(root, o), d)
113                 if callable(hook):
114                         hook(f, pkg, file_regex, output_pattern, m.group(1))
115
116         bb.data.setVar('PACKAGES', ' '.join(packages), d)
117
118 PACKAGE_DEPENDS += "file-native"
119
120 python () {
121     import bb
122     if bb.data.getVar('PACKAGES', d, True) != '':
123         deps = bb.data.getVarFlag('do_package', 'depends', d) or ""
124         for dep in (bb.data.getVar('PACKAGE_DEPENDS', d, True) or "").split():
125             deps += " %s:do_populate_staging" % dep
126         bb.data.setVarFlag('do_package', 'depends', deps, d)
127
128         deps = (bb.data.getVarFlag('do_package', 'deptask', d) or "").split()
129         # shlibs requires any DEPENDS to have already packaged for the *.list files
130         deps.append("do_package")
131         bb.data.setVarFlag('do_package', 'deptask', " ".join(deps), d)
132 }
133
134 def runstrip(file, d):
135     # Function to strip a single file, called from populate_packages below
136     # A working 'file' (one which works on the target architecture)
137     # is necessary for this stuff to work, hence the addition to do_package[depends]
138
139     import bb, os, commands, stat
140
141     pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, 1)
142
143     ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, file))
144
145     if ret:
146         bb.error("runstrip: 'file %s' failed (forced strip)" % file)
147
148     if "not stripped" not in result:
149         bb.debug(1, "runstrip: skip %s" % file)
150         return 0
151
152     strip = bb.data.getVar("STRIP", d, 1)
153     objcopy = bb.data.getVar("OBJCOPY", d, 1)
154
155     newmode = None
156     if not os.access(file, os.W_OK):
157         origmode = os.stat(file)[stat.ST_MODE]
158         newmode = origmode | stat.S_IWRITE
159         os.chmod(file, newmode)
160
161     extraflags = ""
162     if ".so" in file and "shared" in result:
163         extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded"
164     elif "shared" in result or "executable" in result:
165         extraflags = "--remove-section=.comment --remove-section=.note"
166
167     bb.mkdirhier(os.path.join(os.path.dirname(file), ".debug"))
168     debugfile=os.path.join(os.path.dirname(file), ".debug", os.path.basename(file))
169
170     stripcmd = "'%s' %s '%s'" % (strip, extraflags, file)
171     bb.debug(1, "runstrip: %s" % stripcmd)
172
173     os.system("%s'%s' --only-keep-debug '%s' '%s'" % (pathprefix, objcopy, file, debugfile))
174     ret = os.system("%s%s" % (pathprefix, stripcmd))
175     os.system("%s'%s' --add-gnu-debuglink='%s' '%s'" % (pathprefix, objcopy, debugfile, file))
176
177     if newmode:
178         os.chmod(file, origmode)
179
180     if ret:
181         bb.error("runstrip: '%s' strip command failed" % stripcmd)
182
183     return 1
184
185 #
186 # Package data handling routines
187 #
188
189 def get_package_mapping (pkg, d):
190         import bb, os
191
192         data = read_subpkgdata(pkg, d)
193         key = "PKG_%s" % pkg
194
195         if key in data:
196                 return data[key]
197
198         return pkg
199
200 def runtime_mapping_rename (varname, d):
201         import bb, os
202
203         #bb.note("%s before: %s" % (varname, bb.data.getVar(varname, d, 1)))    
204
205         new_depends = []
206         for depend in explode_deps(bb.data.getVar(varname, d, 1) or ""):
207                 # Have to be careful with any version component of the depend
208                 split_depend = depend.split(' (')
209                 new_depend = get_package_mapping(split_depend[0].strip(), d)
210                 if len(split_depend) > 1:
211                         new_depends.append("%s (%s" % (new_depend, split_depend[1]))
212                 else:
213                         new_depends.append(new_depend)
214
215         bb.data.setVar(varname, " ".join(new_depends) or None, d)
216
217         #bb.note("%s after: %s" % (varname, bb.data.getVar(varname, d, 1)))
218
219 #
220 # Package functions suitable for inclusion in PACKAGEFUNCS
221 #
222
223 python package_do_split_locales() {
224         import os
225
226         if (bb.data.getVar('PACKAGE_NO_LOCALE', d, 1) == '1'):
227                 bb.debug(1, "package requested not splitting locales")
228                 return
229
230         packages = (bb.data.getVar('PACKAGES', d, 1) or "").split()
231
232         datadir = bb.data.getVar('datadir', d, 1)
233         if not datadir:
234                 bb.note("datadir not defined")
235                 return
236
237         dvar = bb.data.getVar('D', d, 1)
238         if not dvar:
239                 bb.error("D not defined")
240                 return
241
242         pn = bb.data.getVar('PN', d, 1)
243         if not pn:
244                 bb.error("PN not defined")
245                 return
246
247         if pn + '-locale' in packages:
248                 packages.remove(pn + '-locale')
249
250         localedir = os.path.join(dvar + datadir, 'locale')
251
252         if not os.path.isdir(localedir):
253                 bb.debug(1, "No locale files in this package")
254                 return
255
256         locales = os.listdir(localedir)
257
258         # This is *really* broken
259         mainpkg = packages[0]
260         # At least try and patch it up I guess...
261         if mainpkg.find('-dbg'):
262                 mainpkg = mainpkg.replace('-dbg', '')
263         if mainpkg.find('-dev'):
264                 mainpkg = mainpkg.replace('-dev', '')
265
266         for l in locales:
267                 ln = legitimize_package_name(l)
268                 pkg = pn + '-locale-' + ln
269                 packages.append(pkg)
270                 bb.data.setVar('FILES_' + pkg, os.path.join(datadir, 'locale', l), d)
271                 bb.data.setVar('RDEPENDS_' + pkg, '%s virtual-locale-%s' % (mainpkg, ln), d)
272                 bb.data.setVar('RPROVIDES_' + pkg, '%s-locale %s-translation' % (pn, ln), d)
273                 bb.data.setVar('DESCRIPTION_' + pkg, '%s translation for %s' % (l, pn), d)
274
275         bb.data.setVar('PACKAGES', ' '.join(packages), d)
276
277         # Disabled by RP 18/06/07
278         # Wildcards aren't supported in debian
279         # They break with ipkg since glibc-locale* will mean that 
280         # glibc-localedata-translit* won't install as a dependency
281         # for some other package which breaks meta-toolchain
282         # Probably breaks since virtual-locale- isn't provided anywhere
283         #rdep = (bb.data.getVar('RDEPENDS_%s' % mainpkg, d, 1) or bb.data.getVar('RDEPENDS', d, 1) or "").split()
284         #rdep.append('%s-locale*' % pn)
285         #bb.data.setVar('RDEPENDS_%s' % mainpkg, ' '.join(rdep), d)
286 }
287
288 def copyfile(src,dest,newmtime=None,sstat=None):
289     """
290     Copies a file from src to dest, preserving all permissions and
291     attributes; mtime will be preserved even when moving across
292     filesystems.  Returns true on success and false on failure.
293     """
294     import os, stat, shutil, commands
295
296     #print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")"
297     try:
298         if not sstat:
299             sstat=os.lstat(src)
300     except Exception, e:
301         print "copyfile: Stating source file failed...", e
302         return False
303
304     destexists=1
305     try:
306         dstat=os.lstat(dest)
307     except:
308         dstat=os.lstat(os.path.dirname(dest))
309         destexists=0
310
311     if destexists:
312         if stat.S_ISLNK(dstat[stat.ST_MODE]):
313             try:
314                 os.unlink(dest)
315                 destexists=0
316             except Exception, e:
317                 pass
318
319     if stat.S_ISLNK(sstat[stat.ST_MODE]):
320         try:
321             target=os.readlink(src)
322             if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
323                 os.unlink(dest)
324             os.symlink(target,dest)
325             #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
326             return os.lstat(dest)
327         except Exception, e:
328             print "copyfile: failed to properly create symlink:", dest, "->", target, e
329             return False
330
331     if stat.S_ISREG(sstat[stat.ST_MODE]):
332             try: # For safety copy then move it over.
333                 shutil.copyfile(src,dest+"#new")
334                 os.rename(dest+"#new",dest)
335             except Exception, e:
336                 print 'copyfile: copy', src, '->', dest, 'failed.', e
337                 return False
338     else:
339             #we don't yet handle special, so we need to fall back to /bin/mv
340             a=commands.getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'")
341             if a[0]!=0:
342                 print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a
343                 return False # failure
344     try:
345         os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
346         os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
347     except Exception, e:
348         print "copyfile: Failed to chown/chmod/unlink", dest, e
349         return False
350
351     if newmtime:
352         os.utime(dest,(newmtime,newmtime))
353     else:
354         os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
355         newmtime=sstat[stat.ST_MTIME]
356     return newmtime
357
358 python populate_packages () {
359         import glob, stat, errno, re
360
361         workdir = bb.data.getVar('WORKDIR', d, 1)
362         if not workdir:
363                 bb.error("WORKDIR not defined, unable to package")
364                 return
365
366         import os # path manipulations
367         outdir = bb.data.getVar('DEPLOY_DIR', d, 1)
368         if not outdir:
369                 bb.error("DEPLOY_DIR not defined, unable to package")
370                 return
371         bb.mkdirhier(outdir)
372
373         dvar = bb.data.getVar('D', d, 1)
374         if not dvar:
375                 bb.error("D not defined, unable to package")
376                 return
377         bb.mkdirhier(dvar)
378
379         packages = bb.data.getVar('PACKAGES', d, 1)
380
381         pn = bb.data.getVar('PN', d, 1)
382         if not pn:
383                 bb.error("PN not defined")
384                 return
385
386         os.chdir(dvar)
387
388         def isexec(path):
389                 try:
390                         s = os.stat(path)
391                 except (os.error, AttributeError):
392                         return 0
393                 return (s[stat.ST_MODE] & stat.S_IEXEC)
394
395         # Sanity check PACKAGES for duplicates - should be moved to 
396         # sanity.bbclass once we have the infrastucture
397         package_list = []
398         for pkg in packages.split():
399                 if pkg in package_list:
400                         bb.error("-------------------")
401                         bb.error("%s is listed in PACKAGES multiple times, this leads to packaging errors." % pkg)
402                         bb.error("Please fix the metadata/report this as bug to OE bugtracker.")
403                         bb.error("-------------------")
404                 else:
405                         package_list.append(pkg)
406
407         if (bb.data.getVar('INHIBIT_PACKAGE_STRIP', d, 1) != '1'):
408                 for root, dirs, files in os.walk(dvar):
409                         for f in files:
410                                 file = os.path.join(root, f)
411                                 if not os.path.islink(file) and not os.path.isdir(file) and isexec(file):
412                                         runstrip(file, d)
413
414         pkgdest = bb.data.getVar('PKGDEST', d, 1)
415         os.system('rm -rf %s' % pkgdest)
416
417         seen = []
418
419         for pkg in package_list:
420                 localdata = bb.data.createCopy(d)
421                 root = os.path.join(pkgdest, pkg)
422                 bb.mkdirhier(root)
423
424                 bb.data.setVar('PKG', pkg, localdata)
425                 overrides = bb.data.getVar('OVERRIDES', localdata, 1)
426                 if not overrides:
427                         raise bb.build.FuncFailed('OVERRIDES not defined')
428                 bb.data.setVar('OVERRIDES', overrides + ':' + pkg, localdata)
429                 bb.data.update_data(localdata)
430
431                 filesvar = bb.data.getVar('FILES', localdata, 1) or ""
432                 files = filesvar.split()
433                 for file in files:
434                         if os.path.isabs(file):
435                                 file = '.' + file
436                         if not os.path.islink(file):
437                                 if os.path.isdir(file):
438                                         newfiles =  [ os.path.join(file,x) for x in os.listdir(file) ]
439                                         if newfiles:
440                                                 files += newfiles
441                                                 continue
442                         globbed = glob.glob(file)
443                         if globbed:
444                                 if [ file ] != globbed:
445                                         files += globbed
446                                         continue
447                         if (not os.path.islink(file)) and (not os.path.exists(file)):
448                                 continue
449                         if file in seen:
450                                 continue
451                         seen.append(file)
452                         if os.path.isdir(file) and not os.path.islink(file):
453                                 bb.mkdirhier(os.path.join(root,file))
454                                 os.chmod(os.path.join(root,file), os.stat(file).st_mode)
455                                 continue
456                         fpath = os.path.join(root,file)
457                         dpath = os.path.dirname(fpath)
458                         bb.mkdirhier(dpath)
459                         ret = copyfile(file, fpath)
460                         if ret is False or ret == 0:
461                                 raise bb.build.FuncFailed("File population failed")
462                 del localdata
463         os.chdir(workdir)
464
465         unshipped = []
466         for root, dirs, files in os.walk(dvar):
467                 for f in files:
468                         path = os.path.join(root[len(dvar):], f)
469                         if ('.' + path) not in seen:
470                                 unshipped.append(path)
471
472         if unshipped != []:
473                 bb.note("the following files were installed but not shipped in any package:")
474                 for f in unshipped:
475                         bb.note("  " + f)
476
477         bb.build.exec_func("package_name_hook", d)
478
479         for pkg in package_list:
480                 pkgname = bb.data.getVar('PKG_%s' % pkg, d, 1)
481                 if pkgname is None:
482                         bb.data.setVar('PKG_%s' % pkg, pkg, d)
483
484         dangling_links = {}
485         pkg_files = {}
486         for pkg in package_list:
487                 dangling_links[pkg] = []
488                 pkg_files[pkg] = []
489                 inst_root = os.path.join(pkgdest, pkg)
490                 for root, dirs, files in os.walk(inst_root):
491                         for f in files:
492                                 path = os.path.join(root, f)
493                                 rpath = path[len(inst_root):]
494                                 pkg_files[pkg].append(rpath)
495                                 try:
496                                         s = os.stat(path)
497                                 except OSError, (err, strerror):
498                                         if err != errno.ENOENT:
499                                                 raise
500                                         target = os.readlink(path)
501                                         if target[0] != '/':
502                                                 target = os.path.join(root[len(inst_root):], target)
503                                         dangling_links[pkg].append(os.path.normpath(target))
504
505         for pkg in package_list:
506                 rdepends = explode_deps(bb.data.getVar('RDEPENDS_' + pkg, d, 1) or bb.data.getVar('RDEPENDS', d, 1) or "")
507                 for l in dangling_links[pkg]:
508                         found = False
509                         bb.debug(1, "%s contains dangling link %s" % (pkg, l))
510                         for p in package_list:
511                                 for f in pkg_files[p]:
512                                         if f == l:
513                                                 found = True
514                                                 bb.debug(1, "target found in %s" % p)
515                                                 if p == pkg:
516                                                         break
517                                                 if not p in rdepends:
518                                                         rdepends.append(p)
519                                                 break
520                         if found == False:
521                                 bb.note("%s contains dangling symlink to %s" % (pkg, l))
522                 bb.data.setVar('RDEPENDS_' + pkg, " " + " ".join(rdepends), d)
523 }
524 populate_packages[dirs] = "${D}"
525
526 python emit_pkgdata() {
527         from glob import glob
528
529         def write_if_exists(f, pkg, var):
530                 def encode(str):
531                         import codecs
532                         c = codecs.getencoder("string_escape")
533                         return c(str)[0]
534
535                 val = bb.data.getVar('%s_%s' % (var, pkg), d, 1)
536                 if val:
537                         f.write('%s_%s: %s\n' % (var, pkg, encode(val)))
538
539         packages = bb.data.getVar('PACKAGES', d, 1)
540
541         data_file = bb.data.expand("${PKGDATA_DIR}/${PN}", d)
542         f = open(data_file, 'w')
543         f.write("PACKAGES: %s\n" % packages)
544         f.close()
545
546         workdir = bb.data.getVar('WORKDIR', d, 1)
547
548         for pkg in packages.split():
549                 subdata_file = bb.data.expand("${PKGDATA_DIR}/runtime/%s" % pkg, d)
550                 sf = open(subdata_file, 'w')
551                 write_if_exists(sf, pkg, 'DESCRIPTION')
552                 write_if_exists(sf, pkg, 'RDEPENDS')
553                 write_if_exists(sf, pkg, 'RPROVIDES')
554                 write_if_exists(sf, pkg, 'RRECOMMENDS')
555                 write_if_exists(sf, pkg, 'RSUGGESTS')
556                 write_if_exists(sf, pkg, 'RPROVIDES')
557                 write_if_exists(sf, pkg, 'RREPLACES')
558                 write_if_exists(sf, pkg, 'RCONFLICTS')
559                 write_if_exists(sf, pkg, 'PKG')
560                 write_if_exists(sf, pkg, 'ALLOW_EMPTY')
561                 write_if_exists(sf, pkg, 'FILES')
562                 write_if_exists(sf, pkg, 'pkg_postinst')
563                 write_if_exists(sf, pkg, 'pkg_postrm')
564                 write_if_exists(sf, pkg, 'pkg_preinst')
565                 write_if_exists(sf, pkg, 'pkg_prerm')
566                 sf.close()
567
568                 allow_empty = bb.data.getVar('ALLOW_EMPTY_%s' % pkg, d, 1)
569                 if not allow_empty:
570                         allow_empty = bb.data.getVar('ALLOW_EMPTY', d, 1)
571                 root = "%s/install/%s" % (workdir, pkg)
572                 os.chdir(root)
573                 g = glob('*')
574                 if g or allow_empty == "1":
575                         file(bb.data.expand('${PKGDATA_DIR}/runtime/%s.packaged' % pkg, d), 'w').close()
576 }
577 emit_pkgdata[dirs] = "${PKGDATA_DIR}/runtime"
578
579 ldconfig_postinst_fragment() {
580 if [ x"$D" = "x" ]; then
581         ldconfig
582 fi
583 }
584
585 python package_do_shlibs() {
586         import os, re, os.path
587
588         exclude_shlibs = bb.data.getVar('EXCLUDE_FROM_SHLIBS', d, 0)
589         if exclude_shlibs:
590                 bb.note("not generating shlibs")
591                 return
592                 
593         lib_re = re.compile("^lib.*\.so")
594         libdir_re = re.compile(".*/lib$")
595
596         packages = bb.data.getVar('PACKAGES', d, 1)
597
598         workdir = bb.data.getVar('WORKDIR', d, 1)
599         if not workdir:
600                 bb.error("WORKDIR not defined")
601                 return
602
603         staging = bb.data.getVar('STAGING_DIR', d, 1)
604         if not staging:
605                 bb.error("STAGING_DIR not defined")
606                 return
607
608         ver = bb.data.getVar('PV', d, 1)
609         if not ver:
610                 bb.error("PV not defined")
611                 return
612
613         target_sys = bb.data.getVar('TARGET_SYS', d, 1)
614         if not target_sys:
615                 bb.error("TARGET_SYS not defined")
616                 return
617
618         pkgdest = bb.data.getVar('PKGDEST', d, 1)
619
620         shlibs_dir = os.path.join(staging, target_sys, "shlibs")
621         old_shlibs_dir = os.path.join(staging, "shlibs")
622         bb.mkdirhier(shlibs_dir)
623
624         needed = {}
625         private_libs = bb.data.getVar('PRIVATE_LIBS', d, 1)
626         for pkg in packages.split():
627                 needs_ldconfig = False
628                 bb.debug(2, "calculating shlib provides for %s" % pkg)
629
630                 needed[pkg] = []
631                 sonames = list()
632                 top = os.path.join(pkgdest, pkg)
633                 for root, dirs, files in os.walk(top):
634                         for file in files:
635                                 soname = None
636                                 path = os.path.join(root, file)
637                                 if os.access(path, os.X_OK) or lib_re.match(file):
638                                         cmd = bb.data.getVar('OBJDUMP', d, 1) + " -p " + path + " 2>/dev/null"
639                                         cmd = "PATH=\"%s\" %s" % (bb.data.getVar('PATH', d, 1), cmd)
640                                         fd = os.popen(cmd)
641                                         lines = fd.readlines()
642                                         fd.close()
643                                         for l in lines:
644                                                 m = re.match("\s+NEEDED\s+([^\s]*)", l)
645                                                 if m:
646                                                         needed[pkg].append(m.group(1))
647                                                 m = re.match("\s+SONAME\s+([^\s]*)", l)
648                                                 if m and not m.group(1) in sonames:
649                                                         # if library is private (only used by package) then do not build shlib for it
650                                                         if not private_libs or -1 == private_libs.find(m.group(1)):
651                                                                 sonames.append(m.group(1))
652                                                 if m and libdir_re.match(root):
653                                                         needs_ldconfig = True
654                 shlibs_file = os.path.join(shlibs_dir, pkg + ".list")
655                 if os.path.exists(shlibs_file):
656                         os.remove(shlibs_file)
657                 shver_file = os.path.join(shlibs_dir, pkg + ".ver")
658                 if os.path.exists(shver_file):
659                         os.remove(shver_file)
660                 if len(sonames):
661                         fd = open(shlibs_file, 'w')
662                         for s in sonames:
663                                 fd.write(s + '\n')
664                         fd.close()
665                         fd = open(shver_file, 'w')
666                         fd.write(ver + '\n')
667                         fd.close()
668                 if needs_ldconfig:
669                         bb.debug(1, 'adding ldconfig call to postinst for %s' % pkg)
670                         postinst = bb.data.getVar('pkg_postinst_%s' % pkg, d, 1) or bb.data.getVar('pkg_postinst', d, 1)
671                         if not postinst:
672                                 postinst = '#!/bin/sh\n'
673                         postinst += bb.data.getVar('ldconfig_postinst_fragment', d, 1)
674                         bb.data.setVar('pkg_postinst_%s' % pkg, postinst, d)
675
676         shlib_provider = {}
677         list_re = re.compile('^(.*)\.list$')
678         for dir in [old_shlibs_dir, shlibs_dir]: 
679                 if not os.path.exists(dir):
680                         continue
681                 for file in os.listdir(dir):
682                         m = list_re.match(file)
683                         if m:
684                                 dep_pkg = m.group(1)
685                                 fd = open(os.path.join(dir, file))
686                                 lines = fd.readlines()
687                                 fd.close()
688                                 ver_file = os.path.join(dir, dep_pkg + '.ver')
689                                 lib_ver = None
690                                 if os.path.exists(ver_file):
691                                         fd = open(ver_file)
692                                         lib_ver = fd.readline().rstrip()
693                                         fd.close()
694                                 for l in lines:
695                                         shlib_provider[l.rstrip()] = (dep_pkg, lib_ver)
696
697         assumed_libs = bb.data.getVar('ASSUME_SHLIBS', d, 1)
698         if assumed_libs:
699             for e in assumed_libs.split():
700                 l, dep_pkg = e.split(":")
701                 lib_ver = None
702                 dep_pkg = dep_pkg.rsplit("_", 1)
703                 if len(dep_pkg) == 2:
704                     lib_ver = dep_pkg[1]
705                 dep_pkg = dep_pkg[0]
706                 shlib_provider[l] = (dep_pkg, lib_ver)
707
708         for pkg in packages.split():
709                 bb.debug(2, "calculating shlib requirements for %s" % pkg)
710
711                 deps = list()
712                 for n in needed[pkg]:
713                         if n in shlib_provider.keys():
714                                 (dep_pkg, ver_needed) = shlib_provider[n]
715
716                                 if dep_pkg == pkg:
717                                         continue
718
719                                 if ver_needed:
720                                         dep = "%s (>= %s)" % (dep_pkg, ver_needed)
721                                 else:
722                                         dep = dep_pkg
723                                 if not dep in deps:
724                                         deps.append(dep)
725                         else:
726                                 bb.note("Couldn't find shared library provider for %s" % n)
727
728                 deps_file = os.path.join(pkgdest, pkg + ".shlibdeps")
729                 if os.path.exists(deps_file):
730                         os.remove(deps_file)
731                 if len(deps):
732                         fd = open(deps_file, 'w')
733                         for dep in deps:
734                                 fd.write(dep + '\n')
735                         fd.close()
736 }
737
738 python package_do_pkgconfig () {
739         import re, os
740
741         packages = bb.data.getVar('PACKAGES', d, 1)
742
743         workdir = bb.data.getVar('WORKDIR', d, 1)
744         if not workdir:
745                 bb.error("WORKDIR not defined")
746                 return
747
748         staging = bb.data.getVar('STAGING_DIR', d, 1)
749         if not staging:
750                 bb.error("STAGING_DIR not defined")
751                 return
752
753         target_sys = bb.data.getVar('TARGET_SYS', d, 1)
754         if not target_sys:
755                 bb.error("TARGET_SYS not defined")
756                 return
757
758         pkgdest = bb.data.getVar('PKGDEST', d, 1)
759
760         shlibs_dir = os.path.join(staging, target_sys, "shlibs")
761         old_shlibs_dir = os.path.join(staging, "shlibs")
762         bb.mkdirhier(shlibs_dir)
763
764         pc_re = re.compile('(.*)\.pc$')
765         var_re = re.compile('(.*)=(.*)')
766         field_re = re.compile('(.*): (.*)')
767
768         pkgconfig_provided = {}
769         pkgconfig_needed = {}
770         for pkg in packages.split():
771                 pkgconfig_provided[pkg] = []
772                 pkgconfig_needed[pkg] = []
773                 top = os.path.join(pkgdest, pkg)
774                 for root, dirs, files in os.walk(top):
775                         for file in files:
776                                 m = pc_re.match(file)
777                                 if m:
778                                         pd = bb.data.init()
779                                         name = m.group(1)
780                                         pkgconfig_provided[pkg].append(name)
781                                         path = os.path.join(root, file)
782                                         if not os.access(path, os.R_OK):
783                                                 continue
784                                         f = open(path, 'r')
785                                         lines = f.readlines()
786                                         f.close()
787                                         for l in lines:
788                                                 m = var_re.match(l)
789                                                 if m:
790                                                         name = m.group(1)
791                                                         val = m.group(2)
792                                                         bb.data.setVar(name, bb.data.expand(val, pd), pd)
793                                                         continue
794                                                 m = field_re.match(l)
795                                                 if m:
796                                                         hdr = m.group(1)
797                                                         exp = bb.data.expand(m.group(2), pd)
798                                                         if hdr == 'Requires':
799                                                                 pkgconfig_needed[pkg] += exp.replace(',', ' ').split()
800
801         for pkg in packages.split():
802                 pkgs_file = os.path.join(shlibs_dir, pkg + ".pclist")
803                 if os.path.exists(pkgs_file):
804                         os.remove(pkgs_file)
805                 if pkgconfig_provided[pkg] != []:
806                         f = open(pkgs_file, 'w')
807                         for p in pkgconfig_provided[pkg]:
808                                 f.write('%s\n' % p)
809                         f.close()
810
811         for dir in [old_shlibs_dir, shlibs_dir]:
812                 if not os.path.exists(dir):
813                         continue
814                 for file in os.listdir(dir):
815                         m = re.match('^(.*)\.pclist$', file)
816                         if m:
817                                 pkg = m.group(1)
818                                 fd = open(os.path.join(dir, file))
819                                 lines = fd.readlines()
820                                 fd.close()
821                                 pkgconfig_provided[pkg] = []
822                                 for l in lines:
823                                         pkgconfig_provided[pkg].append(l.rstrip())
824
825         for pkg in packages.split():
826                 deps = []
827                 for n in pkgconfig_needed[pkg]:
828                         found = False
829                         for k in pkgconfig_provided.keys():
830                                 if n in pkgconfig_provided[k]:
831                                         if k != pkg and not (k in deps):
832                                                 deps.append(k)
833                                         found = True
834                         if found == False:
835                                 bb.note("couldn't find pkgconfig module '%s' in any package" % n)
836                 deps_file = os.path.join(pkgdest, pkg + ".pcdeps")
837                 if os.path.exists(deps_file):
838                         os.remove(deps_file)
839                 if len(deps):
840                         fd = open(deps_file, 'w')
841                         for dep in deps:
842                                 fd.write(dep + '\n')
843                         fd.close()
844 }
845
846 python read_shlibdeps () {
847         packages = bb.data.getVar('PACKAGES', d, 1).split()
848         for pkg in packages:
849                 rdepends = explode_deps(bb.data.getVar('RDEPENDS_' + pkg, d, 0) or bb.data.getVar('RDEPENDS', d, 0) or "")
850                 for extension in ".shlibdeps", ".pcdeps", ".clilibdeps":
851                         depsfile = bb.data.expand("${PKGDEST}/" + pkg + extension, d)
852                         if os.access(depsfile, os.R_OK):
853                                 fd = file(depsfile)
854                                 lines = fd.readlines()
855                                 fd.close()
856                                 for l in lines:
857                                         rdepends.append(l.rstrip())
858                 bb.data.setVar('RDEPENDS_' + pkg, " " + " ".join(rdepends), d)
859 }
860
861 python package_depchains() {
862         """
863         For a given set of prefix and postfix modifiers, make those packages
864         RRECOMMENDS on the corresponding packages for its RDEPENDS.
865
866         Example:  If package A depends upon package B, and A's .bb emits an
867         A-dev package, this would make A-dev Recommends: B-dev.
868
869         If only one of a given suffix is specified, it will take the RRECOMMENDS
870         based on the RDEPENDS of *all* other packages. If more than one of a given 
871         suffix is specified, its will only use the RDEPENDS of the single parent 
872         package.
873         """
874
875         packages  = bb.data.getVar('PACKAGES', d, 1)
876         postfixes = (bb.data.getVar('DEPCHAIN_POST', d, 1) or '').split()
877         prefixes  = (bb.data.getVar('DEPCHAIN_PRE', d, 1) or '').split()
878
879         def pkg_addrrecs(pkg, base, suffix, getname, rdepends, d):
880         #bb.note('rdepends for %s is %s' % (base, rdepends))
881
882                 rreclist = explode_deps(bb.data.getVar('RRECOMMENDS_' + pkg, d, 1) or bb.data.getVar('RRECOMMENDS', d, 1) or "")
883
884                 for depend in rdepends:
885                         pkgname = getname(depend, suffix)
886                         if not pkgname in rreclist and packaged(pkgname, d):
887                                 rreclist.append(pkgname)
888
889                 #bb.note('setting: RRECOMMENDS_%s=%s' % (pkg, ' '.join(rreclist)))
890                 bb.data.setVar('RRECOMMENDS_%s' % pkg, ' '.join(rreclist), d)
891
892         def add_dep(list, dep):
893                 dep = dep.split(' (')[0].strip()
894                 if dep not in list:
895                         list.append(dep)
896
897         rdepends = []
898         for dep in explode_deps(bb.data.getVar('RDEPENDS', d, 1) or ""):
899                 add_dep(rdepends, dep)
900
901         for pkg in packages.split():
902                 for dep in explode_deps(bb.data.getVar('RDEPENDS_' + pkg, d, 1) or ""):
903                         add_dep(rdepends, dep)
904
905         #bb.note('rdepends is %s' % rdepends)
906
907         def post_getname(name, suffix):
908                 return '%s%s' % (name, suffix)
909         def pre_getname(name, suffix):
910                 return '%s%s' % (suffix, name)
911
912         pkgs = {}
913         for pkg in packages.split():
914                 for postfix in postfixes:
915                         if pkg.endswith(postfix):
916                                 if not postfix in pkgs:
917                                         pkgs[postfix] = {}
918                                 pkgs[postfix][pkg] = (pkg[:-len(postfix)], post_getname)
919
920                 for prefix in prefixes:
921                         if pkg.startswith(prefix):
922                                 if not prefix in pkgs:
923                                         pkgs[prefix] = {}
924                                 pkgs[prefix][pkg] = (pkg[:-len(prefix)], pre_getname)
925
926         for suffix in pkgs:
927                 for pkg in pkgs[suffix]:
928                         (base, func) = pkgs[suffix][pkg]
929                         if len(pkgs[suffix]) == 1:
930                                 pkg_addrrecs(pkg, base, suffix, func, rdepends, d)
931                         else:
932                                 rdeps = []
933                                 for dep in explode_deps(bb.data.getVar('RDEPENDS_' + base, d, 1) or bb.data.getVar('RDEPENDS', d, 1) or ""):
934                                         add_dep(rdeps, dep)
935                                 pkg_addrrecs(pkg, base, suffix, func, rdeps, d)
936 }
937
938
939 PACKAGEFUNCS ?= "package_do_split_locales \
940                 populate_packages \
941                 package_do_shlibs \
942                 package_do_pkgconfig \
943                 read_shlibdeps \
944                 package_depchains \
945                 emit_pkgdata"
946
947 python package_do_package () {
948         packages = (bb.data.getVar('PACKAGES', d, 1) or "").split()
949         if len(packages) < 1:
950                 bb.debug(1, "No packages to build, skipping do_package")
951                 return
952
953         for f in (bb.data.getVar('PACKAGEFUNCS', d, 1) or '').split():
954                 bb.build.exec_func(f, d)
955 }
956 do_package[dirs] = "${D}"
957 addtask package before do_build after do_install
958
959 # Dummy task to mark when all packaging is complete
960 do_package_write () {
961         :
962 }
963 addtask package_write before do_build after do_package
964
965 EXPORT_FUNCTIONS do_package do_package_write
966
967 #
968 # Helper functions for the package writing classes
969 #
970
971 python package_mapping_rename_hook () {
972         """
973         Rewrite variables to account for package renaming in things
974         like debian.bbclass or manual PKG variable name changes
975         """
976         runtime_mapping_rename("RDEPENDS", d)
977         runtime_mapping_rename("RRECOMMENDS", d)
978         runtime_mapping_rename("RSUGGESTS", d)
979         runtime_mapping_rename("RPROVIDES", d)
980         runtime_mapping_rename("RREPLACES", d)
981         runtime_mapping_rename("RCONFLICTS", d)
982 }
983
984 EXPORT_FUNCTIONS mapping_rename_hook