rpm/0037-Support-debuginfo-subp...

477 lines
15 KiB
Diff

From bc5c404e7415108f15a8cd5e8514a74b43a7755a Mon Sep 17 00:00:00 2001
From: Michael Schroeder <mls@suse.de>
Date: Fri, 24 Mar 2017 15:35:23 +0100
Subject: [PATCH] Support debuginfo subpackages
We do this by filtering the debuginfo files generated by find-debuginfo.sh
with the files from the (sub)packages.
This commit is heavily based on a patch by Richard Biener.
(cherry picked from commit 980749fdce055254ca92ee7e2595b16750b699a2)
Conflicts:
build/files.c
---
build/files.c | 285 ++++++++++++++++++++++++++++++++++++++++++++--
build/parsePreamble.c | 10 +-
build/parseSpec.c | 2 +-
build/rpmbuild_internal.h | 17 +++
macros.in | 3 +
5 files changed, 304 insertions(+), 13 deletions(-)
diff --git a/build/files.c b/build/files.c
index 2f02587f0..779a2a102 100644
--- a/build/files.c
+++ b/build/files.c
@@ -40,6 +40,16 @@
#define SKIPWHITE(_x) {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
#define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
+/* the following defines must be in sync with the equally hardcoded paths from
+ * scripts/find-debuginfo.sh
+ */
+#define BUILD_ID_DIR "/usr/lib/.build-id"
+#define DEBUG_SRC_DIR "/usr/src/debug"
+#define DEBUG_LIB_DIR "/usr/lib/debug"
+#define DEBUG_LIB_PREFIX "/usr/lib/debug/"
+#define DEBUG_ID_DIR "/usr/lib/debug/.build-id"
+#define DEBUG_DWZ_DIR "/usr/lib/debug/.dwz"
+
/**
*/
enum specfFlags_e {
@@ -1702,9 +1712,8 @@ static int generateBuildIDs(FileList fl)
if (lstat(flp->diskPath, &sbuf) == 0 && S_ISREG (sbuf.st_mode)) {
/* We determine whether this is a main or
debug ELF based on path. */
- #define DEBUGPATH "/usr/lib/debug/"
int isDbg = strncmp (flp->cpioPath,
- DEBUGPATH, strlen (DEBUGPATH)) == 0;
+ DEBUG_LIB_PREFIX, strlen (DEBUG_LIB_PREFIX)) == 0;
/* For the main package files mimic what find-debuginfo.sh does.
Only check build-ids for executable files. Debug files are
@@ -1797,8 +1806,6 @@ static int generateBuildIDs(FileList fl)
if (rc == 0) {
char *attrstr;
/* Add .build-id directories to hold the subdirs/symlinks. */
- #define BUILD_ID_DIR "/usr/lib/.build-id"
- #define DEBUG_ID_DIR "/usr/lib/debug/.build-id"
mainiddir = rpmGetPath(fl->buildRoot, BUILD_ID_DIR, NULL);
debugiddir = rpmGetPath(fl->buildRoot, DEBUG_ID_DIR, NULL);
@@ -1864,8 +1871,8 @@ static int generateBuildIDs(FileList fl)
/* Don't add anything more when an error occured. But do
cleanup. */
if (rc == 0) {
- int isDbg = strncmp (paths[i], DEBUGPATH,
- strlen (DEBUGPATH)) == 0;
+ int isDbg = strncmp (paths[i], DEBUG_LIB_PREFIX,
+ strlen (DEBUG_LIB_PREFIX)) == 0;
char *buildidsubdir;
char subdir[4];
@@ -1967,7 +1974,7 @@ static int generateBuildIDs(FileList fl)
which don't end in ".debug". */
int pathlen = strlen(paths[i]);
int debuglen = strlen(".debug");
- int prefixlen = strlen("/usr/lib/debug");
+ int prefixlen = strlen(DEBUG_LIB_DIR);
int vralen = vra == NULL ? 0 : strlen(vra);
if (pathlen > prefixlen + debuglen + vralen
&& strcmp ((paths[i] + pathlen - debuglen),
@@ -2621,24 +2628,273 @@ exit:
return rc;
}
+static rpmTag copyTagsFromMainDebug[] = {
+ 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 patchDebugPackageString(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);
+ copyInheritedTags(dbg->header, pkg->header);
+ headerDel(dbg->header, RPMTAG_GROUP);
+ headerCopyTags(maindbg->header, dbg->header, copyTagsFromMainDebug);
+ dbg->autoReq = maindbg->autoReq;
+ dbg->autoProv = maindbg->autoProv;
+
+ /* patch summary and description strings */
+ patchDebugPackageString(dbg, RPMTAG_SUMMARY, pkg, spec->packages);
+ patchDebugPackageString(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;
+}
+
+/* add a directory to the file list */
+static void argvAddDir(ARGV_t *filesp, const char *dir)
+{
+ char *line = NULL;
+ rasprintf(&line, "%%dir %s", dir);
+ argvAdd(filesp, line);
+ _free(line);
+}
+
+/* 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%s%.*s%s.debug", buildroot, DEBUG_LIB_DIR, 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)");
+ argvAddDir(&files, DEBUG_LIB_DIR);
+ }
+ /* 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%s", buildroot, DEBUG_DWZ_DIR);
+ if (lstat(path, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)) {
+ if (!pkg->fileList) {
+ argvAdd(&pkg->fileList, "%defattr(-,root,root)");
+ argvAddDir(&pkg->fileList, DEBUG_LIB_DIR);
+ }
+ argvAdd(&pkg->fileList, DEBUG_DWZ_DIR);
+ 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%s", buildroot, DEBUG_SRC_DIR);
+ 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, "%s/%s", DEBUG_SRC_DIR, 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 addPackageRequires(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 installSpecialDoc, 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;
@@ -2647,9 +2903,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, installSpecialDoc, test)) != RPMRC_OK ||
- (rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
+
+ if ((rc = processPackageFiles(spec, pkgFlags, pkg, installSpecialDoc, test)) != RPMRC_OK)
+ goto exit;
+
+ if (maindbg)
+ filterDebuginfoPackage(spec, pkg, maindbg, buildroot, uniquearch);
+ else if (deplink && pkg != deplink)
+ addPackageRequires(pkg, deplink);
+
+ if ((rc = rpmfcGenerateDepends(spec, pkg)) != RPMRC_OK)
goto exit;
a = headerGetString(pkg->header, RPMTAG_ARCH);
@@ -2684,6 +2947,8 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
}
exit:
check_fileList = freeStringBuf(check_fileList);
+ _free(buildroot);
+ _free(uniquearch);
return rc;
}
diff --git a/build/parsePreamble.c b/build/parsePreamble.c
index 6be440369..3bb833cff 100644
--- a/build/parsePreamble.c
+++ b/build/parsePreamble.c
@@ -544,6 +544,13 @@ static void fillOutMainPackage(Header h)
/**
*/
+void copyInheritedTags(Header h, Header fromh)
+{
+ headerCopyTags(fromh, h, (rpmTagVal *)copyTagsDuringParse);
+}
+
+/**
+ */
static rpmRC readIcon(Header h, const char * file)
{
char *fn = NULL;
@@ -1171,8 +1178,7 @@ int parsePreamble(rpmSpec spec, int initialPackage)
}
if (pkg != spec->packages) {
- headerCopyTags(spec->packages->header, pkg->header,
- (rpmTagVal *)copyTagsDuringParse);
+ copyInheritedTags(pkg->header, spec->packages->header);
}
if (checkForRequired(pkg->header, NVR)) {
diff --git a/build/parseSpec.c b/build/parseSpec.c
index 9fff0e2c8..582060770 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -564,7 +564,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 7dd577f26..7ec05b9c9 100644
--- a/build/rpmbuild_internal.h
+++ b/build/rpmbuild_internal.h
@@ -442,6 +442,13 @@ int addReqProv(Package pkg, rpmTagVal tagN,
/** \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)
@@ -453,6 +460,16 @@ int rpmlibNeedsFeature(Package pkg, const char * feature, const char * featureEV
RPM_GNUC_INTERNAL
rpmRC checkForEncoding(Header h, int addtag);
+
+
+/** \ingroup rpmbuild
+ * Copy tags inherited by subpackages from the source header to the target header
+ * @param h target header
+ * @param fromh source header
+ */
+RPM_GNUC_INTERNAL
+void copyInheritedTags(Header h, Header fromh);
+
#ifdef __cplusplus
}
#endif
diff --git a/macros.in b/macros.in
index d104ad5a7..0c055a7fd 100644
--- a/macros.in
+++ b/macros.in
@@ -539,6 +539,9 @@ package or when debugging this package.\
# Whether rpm should put debug source files into its own subpackage
#%_debugsource_packages 1
+# Whether rpm should create extra debuginfo packages for each subpackage
+#%_debuginfo_subpackages 1
+
#
# Use internal dependency generator rather than external helpers?
%_use_internal_dependency_generator 1