commit 538cecf0f1fe127dc416afce7a7ee6f94fdb1ad7 Author: Michael Schroeder Date: Tue Mar 28 14:21:40 2017 +0200 Support debugsource subpackages This can be enabled by setting the _debugsource_packages macro. diff --git a/macros.in b/macros.in index 0ddde29..007b8d4 100644 --- a/macros.in +++ b/macros.in @@ -183,13 +183,12 @@ %{?_unique_debug_srcs:--unique-debug-src-base "%{name}-%{VERSION}-%{RELEASE}.%{_arch}"} \\\ %{?_find_debuginfo_dwz_opts} \\\ %{?_find_debuginfo_opts} \\\ + %{?_debugsource_packages:-S debugsourcefiles.list} \\\ "%{_builddir}/%{?buildsubdir}"\ %{nil} # Template for debug information sub-package. -%debug_package \ -%ifnarch noarch\ -%global __debug_package 1\ +%_debuginfo_template \ %package debuginfo\ Summary: Debug information for package %{name}\ Group: Development/Debug\ @@ -201,6 +200,26 @@ Debug information is useful when developing applications that use this\ package or when debugging this package.\ %files debuginfo -f debugfiles.list\ %defattr(-,root,root)\ +%{nil} + +%_debugsource_template \ +%package debugsource\ +Summary: Debug sources for package %{name}\ +Group: Development/Debug\ +AutoReqProv: 0\ +%description debugsource\ +This package provides debug sources for package %{name}.\ +Debug sources are useful when developing applications that use this\ +package or when debugging this package.\ +%files debugsource -f debugsourcefiles.list\ +%defattr(-,root,root)\ +%{nil} + +%debug_package \ +%ifnarch noarch\ +%global __debug_package 1\ +%_debuginfo_template\ +%{?_debugsource_packages:%_debugsource_template}\ %endif\ %{nil} @@ -527,6 +546,9 @@ package or when debugging this package.\ # directory under /usr/debug/src as --. %_unique_debug_srcs 1 +# Whether rpm should put debug source files into its own subpackage +#%_debugsource_packages 1 + # # Use internal dependency generator rather than external helpers? %_use_internal_dependency_generator 1 diff --git a/scripts/find-debuginfo.sh b/scripts/find-debuginfo.sh index 1ebc159..aaf4c75 100755 --- a/scripts/find-debuginfo.sh +++ b/scripts/find-debuginfo.sh @@ -4,6 +4,7 @@ # # Usage: find-debuginfo.sh [--strict-build-id] [-g] [-r] [-m] [-i] [-n] # [-o debugfiles.list] +# [-S debugsourcefiles.list] # [--run-dwz] [--dwz-low-mem-die-limit N] # [--dwz-max-die-limit N] # [--build-id-seed VERSION-RELEASE] @@ -79,6 +80,7 @@ n_jobs=1 BUILDDIR=. out=debugfiles.list +srcout= nout=0 while [ $# -gt 0 ]; do case "$1" in @@ -147,6 +149,10 @@ while [ $# -gt 0 ]; do -j*) n_jobs=${1#-j} ;; + -S) + srcout=$2 + shift + ;; *) BUILDDIR=$1 shift @@ -512,10 +518,19 @@ if [ -d "${RPM_BUILD_ROOT}/usr/lib" -o -d "${RPM_BUILD_ROOT}/usr/src" ]; then (cd "${RPM_BUILD_ROOT}/usr" test ! -d lib/debug || find lib/debug ! -type d - test ! -d src/debug || find src/debug -mindepth 1 -maxdepth 1 + test ! -d src/debug -o -n "$srcout" || find src/debug -mindepth 1 -maxdepth 1 ) | sed 's,^,/usr/,' >> "$LISTFILE" fi +if [ -n "$srcout" ]; then + > "$srcout" + if [ -d "${RPM_BUILD_ROOT}/usr/src/debug" ]; then + (cd "${RPM_BUILD_ROOT}/usr" + find src/debug -mindepth 1 -maxdepth 1 + ) | sed 's,^,/usr/,' >> "$srcout" + fi +fi + # Append to $1 only the lines from stdin not already in the file. append_uniq() { commit 980749fdce055254ca92ee7e2595b16750b699a2 Author: Michael Schroeder Date: Fri Mar 24 15:35:23 2017 +0100 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. diff --git a/build/files.c b/build/files.c index f58569e..e3fc8d6 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 { @@ -1738,9 +1748,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 @@ -1833,8 +1842,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); @@ -1898,8 +1905,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]; @@ -2001,7 +2008,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), @@ -2659,24 +2666,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; @@ -2685,9 +2941,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); @@ -2722,6 +2985,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 6d25f4c..5715d25 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; @@ -1197,8 +1204,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 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..46d9676 100644 --- a/build/rpmbuild_internal.h +++ b/build/rpmbuild_internal.h @@ -442,6 +442,13 @@ /** \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) @@ -463,6 +470,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 007b8d4..cb65f4f 100644 --- a/macros.in +++ b/macros.in @@ -549,6 +549,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 commit a517554e36666f58724620347a4b8224471d2225 Author: Michael Schroeder Date: Wed Mar 29 14:55:10 2017 +0200 Also add directories to split debuginfo packages This gets rid of the last difference between debuginfo subpackages and normal debuginfo packages. diff --git a/build/files.c b/build/files.c index e3fc8d6..5022069 100644 --- a/build/files.c +++ b/build/files.c @@ -2745,8 +2745,9 @@ static void filterDebuginfoPackage(rpmSpec spec, Package pkg, { rpmfi fi; ARGV_t files = NULL; - Package dbg = NULL; - char *path = NULL; + ARGV_t dirs = NULL; + int lastdiridx = -1, dirsadded; + char *path = NULL, *p, *pmin; size_t buildrootlen = strlen(buildroot); /* ignore noarch subpackages */ @@ -2779,12 +2780,37 @@ static void filterDebuginfoPackage(rpmSpec spec, Package pkg, argvAdd(&files, "%defattr(-,root,root)"); argvAddDir(&files, DEBUG_LIB_DIR); } + /* Add the files main debug-info file */ argvAdd(&files, path + buildrootlen); + + /* Add the dir(s) */ + dirsadded = 0; + pmin = path + buildrootlen + strlen(DEBUG_LIB_DIR); + while ((p = strrchr(path + buildrootlen, '/')) != NULL && p > pmin) { + *p = 0; + if (lastdiridx >= 0 && !strcmp(dirs[lastdiridx], path + buildrootlen)) + break; /* already added this one */ + argvAdd(&dirs, path + buildrootlen); + dirsadded++; + } + if (dirsadded) + lastdiridx = argvCount(dirs) - dirsadded; /* remember longest dir */ } path = _free(path); } + /* add collected directories to file list */ + if (dirs) { + int i; + argvSort(dirs, NULL); + for (i = 0; dirs[i]; i++) { + if (!i || strcmp(dirs[i], dirs[i - 1]) != 0) + argvAddDir(&files, dirs[i]); + } + dirs = argvFree(dirs); + } + if (files) { /* we have collected some files. Now put them in a debuginfo * package. If this is not the main package, clone the main