The attached patch makes rpm create debuginfo subpackage for each
subpackage that contains files with debug data.

This is pretty much a complete rewrite of the old SUSE patch,
so this needs a review. As this is off by default it can't break
anything.

Cheers,
  Michael.

-- 
Michael Schroeder                                   m...@suse.de
SUSE LINUX GmbH,           GF Jeff Hawn, HRB 16746 AG Nuernberg
main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);}
>From 86a3bb4918b6fefff5f8ded6c462015cf8217b55 Mon Sep 17 00:00:00 2001
From: Michael Schroeder <m...@suse.de>
Date: Fri, 24 Mar 2017 15:35:23 +0100
Subject: [PATCH 2/2] Support debuginfo subpackages

We do this by filtering the debuginfo files generated by find-debuginfo.sh
with the files from the (sub)packages.
---
 build/files.c             | 276 +++++++++++++++++++++++++++++++++++++++++++++-
 build/parseSpec.c         |   2 +-
 build/rpmbuild_internal.h |   7 ++
 macros.in                 |   3 +
 4 files changed, 284 insertions(+), 4 deletions(-)

diff --git a/build/files.c b/build/files.c
index f58569e..d06a0f3 100644
--- a/build/files.c
+++ b/build/files.c
@@ -2659,24 +2659,285 @@ exit:
     return rc;
 }
 
+static rpmTag copyTagsForDebug[] = {
+    /* see copyTagsDuringParse */
+    RPMTAG_EPOCH,
+    RPMTAG_VERSION,
+    RPMTAG_RELEASE,
+    RPMTAG_LICENSE,
+    RPMTAG_PACKAGER,
+    RPMTAG_DISTRIBUTION,
+    RPMTAG_DISTURL,
+    RPMTAG_VENDOR,
+    RPMTAG_ICON,
+    RPMTAG_URL,
+    RPMTAG_VCS,
+    RPMTAG_CHANGELOGTIME,
+    RPMTAG_CHANGELOGNAME,
+    RPMTAG_CHANGELOGTEXT,
+    RPMTAG_PREFIXES,
+    RPMTAG_DISTTAG,
+    RPMTAG_BUGURL,
+    0
+};
+
+static rpmTag copyTagsForDebugMain[] = {
+    RPMTAG_ARCH,
+    RPMTAG_SUMMARY,
+    RPMTAG_DESCRIPTION,
+    RPMTAG_GROUP,
+    /* see addTargets */
+    RPMTAG_OS,
+    RPMTAG_PLATFORM,
+    RPMTAG_OPTFLAGS,
+};
+
+/* this is a hack: patch the summary and the description to include
+ * the correct package name */
+static void patch_debug_package_string(Package dbg, rpmTag tag, Package pkg, Package mainpkg)
+{
+    const char *oldname, *newname, *old;
+    char *oldsubst = NULL, *newsubst = NULL, *p;
+    oldname = headerGetString(mainpkg->header, RPMTAG_NAME);
+    newname = headerGetString(pkg->header, RPMTAG_NAME);
+    rasprintf(&oldsubst, "package %s", oldname);
+    rasprintf(&newsubst, "package %s", newname);
+    old = headerGetString(dbg->header, tag);
+    p = old ? strstr(old, oldsubst) : NULL;
+    if (p) {
+	char *new = NULL;
+	rasprintf(&new, "%.*s%s%s", (int)(p - old), old, newsubst, p + strlen(oldsubst));
+	headerDel(dbg->header, tag);
+	headerPutString(dbg->header, tag, new);
+	_free(new);
+    }
+    _free(oldsubst);
+    _free(newsubst);
+}
+
+/* create a new debuginfo subpackage for package pkg from the
+ * main debuginfo package */
+static Package cloneDebuginfoPackage(rpmSpec spec, Package pkg, Package maindbg)
+{
+    const char *name = headerGetString(pkg->header, RPMTAG_NAME);
+    char *dbgname = NULL;
+    Package dbg;
+
+    rasprintf(&dbgname, "%s-%s", name, "debuginfo");
+    dbg = newPackage(dbgname, spec->pool, &spec->packages);
+    headerPutString(dbg->header, RPMTAG_NAME, dbgname);
+    headerCopyTags(pkg->header, dbg->header, copyTagsForDebug);
+    headerCopyTags(maindbg->header, dbg->header, copyTagsForDebugMain);
+    dbg->autoReq = maindbg->autoReq;
+    dbg->autoProv = maindbg->autoProv;
+
+    /* patch summary and description strings */
+    patch_debug_package_string(dbg, RPMTAG_SUMMARY, pkg, spec->packages);
+    patch_debug_package_string(dbg, RPMTAG_DESCRIPTION, pkg, spec->packages);
+
+    /* Add self-provides (normally done by addTargets) */
+    addPackageProvides(dbg);
+    dbg->ds = rpmdsThis(dbg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
+
+    _free(dbgname);
+    return dbg;
+}
+
+/* collect the debug files for package pkg and put them into
+ * a (possibly new) debuginfo subpackage */
+static void filterDebuginfoPackage(rpmSpec spec, Package pkg,
+		Package maindbg, char *buildroot, char *uniquearch)
+{
+    rpmfi fi;
+    ARGV_t files = NULL;
+    Package dbg = NULL;
+    char *path = NULL;
+    size_t buildrootlen = strlen(buildroot);
+
+    /* ignore noarch subpackages */
+    if (rstreq(headerGetString(pkg->header, RPMTAG_ARCH), "noarch"))
+	return;
+
+    if (!uniquearch)
+	uniquearch = "";
+
+    fi = rpmfilesIter(pkg->cpioList, RPMFI_ITER_FWD);
+    /* Check if the current package has files with debug info
+       and add them to the file list */
+    fi = rpmfiInit(fi, 0);
+    while (rpmfiNext(fi) >= 0) {
+	const char *name = rpmfiFN(fi);
+	int namel = strlen(name);
+
+	/* strip trailing .debug like in find-debuginfo.sh */
+	namel = strlen(name);
+	if (namel > 6 && !strcmp(name + namel - 6, ".debug"))
+	    namel -= 6;
+	
+	/* generate path */
+	rasprintf(&path, "%s/usr/lib/debug%.*s%s.debug", buildroot, namel, name, uniquearch);
+
+	/* If that file exists we have debug information for it */
+	if (access(path, F_OK) == 0) {
+	    /* Append the file list preamble */
+	    if (!files) {
+		argvAdd(&files, "%defattr(-,root,root)");
+		argvAdd(&files, "%dir /usr/lib/debug");
+	    }
+	    /* Add the files main debug-info file */
+	    argvAdd(&files, path + buildrootlen);
+	}
+	path = _free(path);
+    }
+
+    if (files) {
+	/* we have collected some files. Now put them in a debuginfo
+         * package. If this is not the main package, clone the main
+         * debuginfo package */
+	if (pkg == spec->packages)
+	    maindbg->fileList = files;
+	else {
+	    Package dbg = cloneDebuginfoPackage(spec, pkg, maindbg);
+	    dbg->fileList = files;
+	}
+    }
+}
+
+/* add the debug dwz files to package pkg.
+ * return 1 if something was added, 0 otherwise. */
+static int addDebugDwz(Package pkg, char *buildroot)
+{
+    int ret = 0;
+    char *path = NULL;
+    struct stat sbuf;
+
+    rasprintf(&path, "%s/usr/lib/debug/.dwz", buildroot);
+    if (lstat(path, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)) {
+	if (!pkg->fileList) {
+	    argvAdd(&pkg->fileList, "%defattr(-,root,root)");
+	    argvAdd(&pkg->fileList, "%dir /usr/lib/debug");
+	}
+	argvAdd(&pkg->fileList, "/usr/lib/debug/.dwz");
+	ret = 1;
+    }
+    path = _free(path);
+    return ret;
+}
+
+/* add the debug source files to package pkg.
+ * return 1 if something was added, 0 otherwise. */
+static int addDebugSrc(Package pkg, char *buildroot)
+{
+    int ret = 0;
+    char *path = NULL;
+    DIR *d;
+    struct dirent *de;
+
+    /* not needed if we have an extra debugsource subpackage */
+    if (rpmExpandNumeric("%{?_debugsource_packages}"))
+	return 0;
+
+    rasprintf(&path, "%s/usr/src/debug", buildroot);
+    d = opendir(path);
+    path = _free(path);
+    if (d) {
+	while ((de = readdir(d)) != NULL) {
+	    if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+		continue;
+	    rasprintf(&path, "/usr/src/debug/%s", de->d_name);
+	    if (!pkg->fileList)
+		argvAdd(&pkg->fileList, "%defattr(-,root,root)");
+	    argvAdd(&pkg->fileList, path);
+	    path = _free(path);
+	    ret = 1;
+	}
+	closedir(d);
+    }
+    return ret;
+}
+
+/* find the main debuginfo package. We do this simply by
+ * searching for a package with the right name. */
+static Package findDebuginfoPackage(rpmSpec spec)
+{
+    Package pkg = NULL;
+    if (lookupPackage(spec, "debuginfo", PART_SUBNAME, &pkg))
+	return NULL;
+    return pkg && pkg->fileList ? pkg : NULL;
+}
+
+/* add a requires for package "to" into package "from". */
+static void addDebugRequires(Package from, Package to)
+{
+    const char *name;
+    char *evr, *isaprov;
+    name = headerGetString(to->header, RPMTAG_NAME);
+    evr = headerGetAsString(to->header, RPMTAG_EVR);
+    isaprov = rpmExpand(name, "%{?_isa}", NULL);
+    addReqProv(from, RPMTAG_REQUIRENAME, isaprov, evr, RPMSENSE_EQUAL, 0);
+    free(isaprov);
+    free(evr);
+}
+
 rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
 			int didInstall, int test)
 {
     Package pkg;
     rpmRC rc = RPMRC_OK;
+    char *buildroot;
+    char *uniquearch = NULL;
+    Package maindbg = NULL;		/* the (existing) main debuginfo package */
+    Package deplink = NULL;		/* create requires to this package */
     
 #if HAVE_LIBDW
     elf_version (EV_CURRENT);
 #endif
     check_fileList = newStringBuf();
     genSourceRpmName(spec);
+    buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
     
+    if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) {
+	maindbg = findDebuginfoPackage(spec);
+	if (maindbg) {
+	    /* move debuginfo package to back */
+	    if (maindbg->next) {
+		Package *pp;
+		/* dequeue */
+		for (pp = &spec->packages; *pp != maindbg; pp = &(*pp)->next)
+		    ;
+		*pp = maindbg->next;
+		maindbg->next = 0;
+		/* enqueue at tail */
+		for (; *pp; pp = &(*pp)->next)
+		    ;
+		*pp = maindbg;
+	    }
+	    /* delete unsplit file list, we will re-add files back later */
+	    maindbg->fileFile = argvFree(maindbg->fileFile);
+	    maindbg->fileList = argvFree(maindbg->fileList);
+	    if (rpmExpandNumeric("%{?_unique_debug_names}"))
+		uniquearch = rpmExpand("-%{VERSION}-%{RELEASE}.%{_arch}", NULL);
+	}
+    }
+
     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
 	char *nvr;
 	const char *a;
 	int header_color;
 	int arch_color;
 
+	if (pkg == maindbg) {
+	    /* if there is just one debuginfo package, we put our extra stuff
+	     * in it. Otherwise we put it in the main debug package */
+	    Package extradbg = !maindbg->fileList && maindbg->next && !maindbg->next->next ?
+		 maindbg->next : maindbg;
+	    if (addDebugDwz(extradbg, buildroot))
+		deplink = extradbg;
+	    if (addDebugSrc(extradbg, buildroot))
+		deplink = extradbg;
+	    maindbg = NULL;	/* all normal packages processed */
+	}
+
 	if (pkg->fileList == NULL)
 	    continue;
 
@@ -2685,9 +2946,16 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
 	nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
 	rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n"), nvr);
 	free(nvr);
-		   
-	if ((rc = processPackageFiles(spec, pkgFlags, pkg, didInstall, test)) != RPMRC_OK ||
-	    (rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
+
+	if ((rc = processPackageFiles(spec, pkgFlags, pkg, didInstall, test)) != RPMRC_OK)
+	    goto exit;
+
+	if (maindbg)
+	    filterDebuginfoPackage(spec, pkg, maindbg, buildroot, uniquearch);
+	else if (deplink && pkg != deplink)
+	    addDebugRequires(pkg, deplink);
+
+        if ((rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
 	    goto exit;
 
 	a = headerGetString(pkg->header, RPMTAG_ARCH);
@@ -2722,6 +2990,8 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
     }
 exit:
     check_fileList = freeStringBuf(check_fileList);
+    _free(buildroot);
+    _free(uniquearch);
     
     return rc;
 }
diff --git a/build/parseSpec.c b/build/parseSpec.c
index 2928e85..d0c42a4 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -572,7 +572,7 @@ static void initSourceHeader(rpmSpec spec)
 }
 
 /* Add extra provides to package.  */
-static void addPackageProvides(Package pkg)
+void addPackageProvides(Package pkg)
 {
     const char *arch, *name;
     char *evr, *isaprov;
diff --git a/build/rpmbuild_internal.h b/build/rpmbuild_internal.h
index 948dc31..4f26324 100644
--- a/build/rpmbuild_internal.h
+++ b/build/rpmbuild_internal.h
@@ -452,6 +452,13 @@ rpmRC addReqProvPkg(void *cbdata, rpmTagVal tagN,
 		    int index);
 
 /** \ingroup rpmbuild
+ * Add self-provides to package.
+ * @param pkg		package
+ */
+RPM_GNUC_INTERNAL
+void addPackageProvides(Package pkg);
+
+/** \ingroup rpmbuild
  * Add rpmlib feature dependency.
  * @param pkg		package
  * @param feature	rpm feature name (i.e. "rpmlib(Foo)" for feature Foo)
diff --git a/macros.in b/macros.in
index b2cfceb..dcd4865 100644
--- a/macros.in
+++ b/macros.in
@@ -532,6 +532,9 @@ package or when debugging this package.\
 # Whether rpm should put debug source files into an own subpackage
 #%_debugsource_packages	1
 
+# Whether rpm should create extra debuginfo packages for subpackage
+#%_debuginfo_subpackages 1
+
 #
 # Use internal dependency generator rather than external helpers?
 %_use_internal_dependency_generator	1
-- 
2.1.4

_______________________________________________
Rpm-maint mailing list
Rpm-maint@lists.rpm.org
http://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to