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