Skip to content

Commit

Permalink
Add support for dynamic BuildRequires
Browse files Browse the repository at this point in the history
Supports new %generate_buildrequires section in the spec file which is executed
after %prep. Stdout is captured and turned into BuildRequires. These are then
checked. If they cannot be fulfilled a source package is created with all
BuildRequires and the build is terminated after that.

rpmbuild has now the following new build modes -br, -tr, -rr and exits with 11
if build requirements are not met.

That means for users:
* No %generate_buildrequires
  * rpmbuild -br is equivalent to rpmbuild -bs
  * rpmbuild -br --nodeps is equivalent to rpmbuild -bs
* %generate_buildrequires
  * rpmbuild -br will check dynamic BuildRequires
    * Satisfied → src.rpm
    * Unsatisfied → buildreqs.nosrc.rpm
  * rpmbuild -br --nodeps will always generate buildreqs.nosrc.rpm

Source packages contain
Requires: rpmlib(DynamicBuildRequires) <= 4.15.0-1
if the spec contains a %generate_buildrequires section and
Provide: rpmlib(DynamicBuildRequires) = 4.15.0-1
if the results been added to the source package.

Co-authored-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
  • Loading branch information
2 people authored and pmatilai committed May 28, 2019
1 parent d0754b4 commit 58dcfdd
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 10 deletions.
86 changes: 84 additions & 2 deletions build/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
mPost = "%{__spec_prep_post}";
mCmd = "%{__spec_prep_cmd}";
break;
case RPMBUILD_BUILDREQUIRES:
mTemplate = "%{__spec_buildrequires_template}";
mPost = "%{__spec_buildrequires_post}";
mCmd = "%{__spec_buildrequires_cmd}";
break;
case RPMBUILD_BUILD:
mTemplate = "%{__spec_build_template}";
mPost = "%{__spec_build_post}";
Expand Down Expand Up @@ -174,6 +179,52 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name,
return rc;
}

static int doBuildRequires(rpmSpec spec, int test)
{
StringBuf sb_stdout = NULL;
int outc;
ARGV_t output = NULL;

int rc = 1; /* assume failure */

if (!spec->buildrequires) {
rc = RPMRC_OK;
goto exit;
}

if ((rc = doScript(spec, RPMBUILD_BUILDREQUIRES, "%generate_buildrequires",
getStringBuf(spec->buildrequires), test, &sb_stdout)))
goto exit;

/* add results to requires of the srpm */
argvSplit(&output, getStringBuf(sb_stdout), "\n\r");
outc = argvCount(output);

if (!outc) {
goto exit;
}

for (int i = 0; i < outc; i++) {
parseRCPOT(spec, spec->sourcePackage, output[i], RPMTAG_REQUIRENAME,
0, 0, addReqProvPkg, NULL);
}

rpmdsPutToHeader(
*packageDependencies(spec->sourcePackage, RPMTAG_REQUIRENAME),
spec->sourcePackage->header);

parseRCPOT(spec, spec->sourcePackage,
"rpmlib(DynamicBuildRequires) = 4.15.0-1",
RPMTAG_PROVIDENAME, 0, RPMSENSE_FIND_PROVIDES | RPMSENSE_RPMLIB,
addReqProvPkg, NULL);
rc = RPMRC_MISSINGBUILDREQUIRES;

exit:
freeStringBuf(sb_stdout);
free(output);
return rc;
}

static rpmRC doCheckBuildRequires(rpmts ts, rpmSpec spec, int test)
{
rpmRC rc = RPMRC_OK;
Expand All @@ -182,9 +233,9 @@ static rpmRC doCheckBuildRequires(rpmts ts, rpmSpec spec, int test)
if (ps) {
rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
rpmpsPrint(NULL, ps);
}
if (ps != NULL)
rc = RPMRC_MISSINGBUILDREQUIRES;
}

rpmpsFree(ps);
return rc;
}
Expand Down Expand Up @@ -230,6 +281,14 @@ static rpmRC buildSpec(rpmts ts, BTA_t buildArgs, rpmSpec spec, int what)
}
} else {
int didBuild = (what & (RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL));
int sourceOnly = ((what & RPMBUILD_PACKAGESOURCE) &&
!(what & (RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)));

if (!spec->buildrequires && sourceOnly) {
/* don't run prep if not needed for source build */
/* with(out) dynamic build requires*/
what &= ~(RPMBUILD_PREP);
}

if ((what & RPMBUILD_CHECKBUILDREQUIRES) &&
(rc = doCheckBuildRequires(ts, spec, test)))
Expand All @@ -240,6 +299,29 @@ static rpmRC buildSpec(rpmts ts, BTA_t buildArgs, rpmSpec spec, int what)
getStringBuf(spec->prep), test, NULL)))
goto exit;

if (what & RPMBUILD_BUILDREQUIRES)
rc = doBuildRequires(spec, test);
if ((what & RPMBUILD_CHECKBUILDREQUIRES) &&
(rc == RPMRC_MISSINGBUILDREQUIRES))
rc = doCheckBuildRequires(ts, spec, test);
if (rc == RPMRC_MISSINGBUILDREQUIRES) {
if (what & RPMBUILD_DUMPBUILDREQUIRES) {
/* Create buildreqs package */
char *nvr = headerGetAsString(spec->packages->header, RPMTAG_NVR);
rasprintf(&spec->sourceRpmName, "%s.buildreqs.nosrc.rpm", nvr);
free(nvr);
/* free sources to not include them in the buildreqs package */
spec->sources = freeSources(spec->sources);
spec->numSources = 0;
missing_buildreqs = 1;
what = RPMBUILD_PACKAGESOURCE;
} else {
rc = RPMRC_OK;
}
} else if (rc) {
goto exit;
}

if ((what & RPMBUILD_BUILD) &&
(rc = doScript(spec, RPMBUILD_BUILD, "%build",
getStringBuf(spec->build), test, NULL)))
Expand Down
4 changes: 4 additions & 0 deletions build/pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,10 @@ rpmRC packageSources(rpmSpec spec, char **cookie)
headerPutUint32(sourcePkg->header, RPMTAG_BUILDTIME, &(spec->buildTime), 1);
headerPutUint32(sourcePkg->header, RPMTAG_SOURCEPACKAGE, &one, 1);

if (spec->buildrequires) {
(void) rpmlibNeedsFeature(sourcePkg, "DynamicBuildRequires", "4.15.0-1");
}

/* XXX this should be %_srpmdir */
{ sourcePkg->filename = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", sourcePkg->filename, NULL);
Expand Down
5 changes: 5 additions & 0 deletions build/parseSpec.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const struct PartRec {
} partList[] = {
{ PART_PREAMBLE, LEN_AND_STR("%package")},
{ PART_PREP, LEN_AND_STR("%prep")},
{ PART_BUILDREQUIRES, LEN_AND_STR("%generate_buildrequires")},
{ PART_BUILD, LEN_AND_STR("%build")},
{ PART_INSTALL, LEN_AND_STR("%install")},
{ PART_CHECK, LEN_AND_STR("%check")},
Expand Down Expand Up @@ -906,6 +907,10 @@ static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
case PART_PREP:
parsePart = parsePrep(spec);
break;
case PART_BUILDREQUIRES:
parsePart = parseSimpleScript(spec, "%generate_buildrequires",
&(spec->buildrequires));
break;
case PART_BUILD:
parsePart = parseSimpleScript(spec, "%build", &(spec->build));
break;
Expand Down
10 changes: 8 additions & 2 deletions build/reqprov.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ int addReqProv(Package pkg, rpmTagVal tagN,

dsp = packageDependencies(pkg, tagN);

/* rpmlib() dependency sanity: only requires permitted, ensure sense bit */
/* rpmlib() dependency sanity:
* - Provides are permitted only for source packages
* - Otherwise only requires
* - Ensure sense bit
*/
if (rstreqn(N, "rpmlib(", sizeof("rpmlib(")-1)) {
if (tagN != RPMTAG_REQUIRENAME) return 1;
if (tagN != RPMTAG_REQUIRENAME &&
(tagN == RPMTAG_PROVIDENAME && !(Flags & RPMSENSE_RPMLIB)))
return 1;
Flags |= RPMSENSE_RPMLIB;
}

Expand Down
6 changes: 5 additions & 1 deletion build/rpmbuild.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ enum rpmBuildFlags_e {
RPMBUILD_FILE_LIST = (1 << 17), /*!< rpmSpecPkgGetSection: %files */
RPMBUILD_POLICY = (1 << 18), /*!< rpmSpecPkgGetSection: %policy */
RPMBUILD_CHECKBUILDREQUIRES = (1 << 19), /*!< Check %%buildrequires. */
RPMBUILD_BUILDREQUIRES = (1 << 20), /*!< Execute %%buildrequires. */
RPMBUILD_DUMPBUILDREQUIRES = (1 << 21), /*!< Write buildrequires.nosrc.rpm. */

RPMBUILD_NOBUILD = (1 << 31) /*!< Don't execute or package. */
};
Expand Down Expand Up @@ -109,7 +111,9 @@ rpmds rpmSpecDS(rpmSpec spec, rpmTagVal tag);
* @param ts rpm transaction set
* @param spec spec file control structure
* @param buildArgs build arguments
* @return RPMRC_OK on success, RPMRC_MISSINGBUILDREQUIRES or 1
* @return 0 on success, 1 on build error,
* RPMRC_MISSINGBUILDREQUIRES on missing build
* requirements
*/
int rpmSpecBuild(rpmts ts, rpmSpec spec, BTA_t buildArgs);

Expand Down
4 changes: 3 additions & 1 deletion build/rpmbuild_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ struct rpmSpec_s {
rpmstrPool pool;

StringBuf prep; /*!< %prep scriptlet. */
StringBuf buildrequires; /*!< %buildrequires scriptlet. */
StringBuf build; /*!< %build scriptlet. */
StringBuf install; /*!< %install scriptlet. */
StringBuf check; /*!< %check scriptlet. */
Expand Down Expand Up @@ -237,7 +238,8 @@ typedef enum rpmParseState_e {
PART_EMPTY = 39+PART_BASE, /*!< */
PART_PATCHLIST = 40+PART_BASE, /*!< */
PART_SOURCELIST = 41+PART_BASE, /*!< */
PART_LAST = 42+PART_BASE /*!< */
PART_BUILDREQUIRES = 42+PART_BASE, /*!< */
PART_LAST = 43+PART_BASE /*!< */
} rpmParseState;


Expand Down
9 changes: 6 additions & 3 deletions doc/rpmbuild.8
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ rpmbuild \- Build RPM Package(s)
.PP


\fBrpmbuild\fR {\fB-ba|-bb|-bp|-bc|-bi|-bl|-bs\fR} [\fBrpmbuild-options\fR] \fB\fISPECFILE\fB\fR\fI ...\fR
\fBrpmbuild\fR {\fB-ba|-bb|-bp|-bc|-bi|-bl|-bs|-br\fR} [\fBrpmbuild-options\fR] \fB\fISPECFILE\fB\fR\fI ...\fR


\fBrpmbuild\fR {\fB-ra|-rb|-rp|-rc|-ri|-rl|-rs\fR} [\fBrpmbuild-options\fR] \fB\fISOURCEPACKAGE\fB\fR\fI ...\fR
\fBrpmbuild\fR {\fB-ra|-rb|-rp|-rc|-ri|-rl|-rs|-rr\fR} [\fBrpmbuild-options\fR] \fB\fISOURCEPACKAGE\fB\fR\fI ...\fR


\fBrpmbuild\fR {\fB-ta|-tb|-tp|-tc|-ti|-tl|-ts\fR} [\fBrpmbuild-options\fR] \fB\fITARBALL\fB\fR\fI ...\fR
\fBrpmbuild\fR {\fB-ta|-tb|-tp|-tc|-ti|-tl|-ts|-tr\fR} [\fBrpmbuild-options\fR] \fB\fITARBALL\fB\fR\fI ...\fR



Expand Down Expand Up @@ -162,6 +162,9 @@ exists.
.TP
\fB-bs\fR
Build just the source package.
.TP
\fB-br\fR
Build just the source package - but calculate and include the dynamic build requires.
.PP
The following options may also be used:
.TP
Expand Down
3 changes: 3 additions & 0 deletions lib/rpmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,9 @@ static const struct rpmlibProvides_s rpmlibProvides[] = {
{ "rpmlib(RichDependencies)", "4.12.0-1",
( RPMSENSE_EQUAL),
N_("support for rich dependencies.") },
{ "rpmlib(DynamicBuildRequires)", "4.15.0-1",
(RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
N_("support for dynamic buildrequires.") },
#ifdef HAVE_ZSTD
{ "rpmlib(PayloadIsZstd)", "5.4.18-1",
(RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
Expand Down
15 changes: 15 additions & 0 deletions macros.in
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,21 @@ package or when debugging this package.\
#%{__spec_prep_post}\
#%{nil}

%__spec_buildrequires_shell %{___build_shell}
%__spec_buildrequires_args %{___build_args}
%__spec_buildrequires_cmd %{___build_cmd}
%__spec_buildrequires_pre %{___build_pre}
%__spec_buildrequires_body %{___build_body}
%__spec_buildrequires_post %{___build_post}
%__spec_buildrequires_template #!%{__spec_buildrequires_shell}\
%{__spec_buildrequires_pre}\
%{nil}

#%{__spec_buildrequires_body}\
#%{__spec_buildrequires_post}\
#%{nil}


%__spec_build_shell %{___build_shell}
%__spec_build_args %{___build_args}
%__spec_build_cmd %{___build_cmd}
Expand Down
24 changes: 23 additions & 1 deletion rpmbuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ static struct rpmBuildArguments_s rpmBTArgs;
#define POPT_BL 0x626c
#define POPT_BP 0x6270
#define POPT_BS 0x6273
#define POPT_BR 0x6272
#define POPT_RA 0x4261
#define POPT_RB 0x4262
#define POPT_RC 0x4263
#define POPT_RI 0x4269
#define POPT_RL 0x426c
#define POPT_RP 0x4270
#define POPT_RS 0x4273
#define POPT_RR 0x4272
#define POPT_TA 0x7461
#define POPT_TB 0x7462
#define POPT_TC 0x7463
#define POPT_TI 0x7469
#define POPT_TL 0x746c
#define POPT_TP 0x7470
#define POPT_TS 0x7473
#define POPT_TR 0x7472

extern int _fsm_debug;

Expand Down Expand Up @@ -81,20 +84,23 @@ static void buildArgCallback( poptContext con,
case POPT_BL:
case POPT_BP:
case POPT_BS:
case POPT_BR:
case POPT_RA:
/* case POPT_RB: same value as POPT_REBUILD */
case POPT_RC:
case POPT_RI:
case POPT_RL:
case POPT_RP:
case POPT_RS:
case POPT_RR:
case POPT_TA:
case POPT_TB:
case POPT_TC:
case POPT_TI:
case POPT_TL:
case POPT_TP:
case POPT_TS:
case POPT_TR:
if (opt->val == POPT_BS || opt->val == POPT_TS)
noDeps = 1;
if (buildMode == '\0' && buildChar == '\0') {
Expand Down Expand Up @@ -156,6 +162,9 @@ static struct poptOption rpmBuildPoptTable[] = {
{ "bs", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BS,
N_("build source package only from <specfile>"),
N_("<specfile>") },
{ "br", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BR,
N_("build source package only from <specfile> - calculate dynamic build requires"),
N_("<specfile>") },

{ "rp", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RP,
N_("build through %prep (unpack sources and apply patches) from <source package>"),
Expand All @@ -178,6 +187,9 @@ static struct poptOption rpmBuildPoptTable[] = {
{ "rs", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RS,
N_("build source package only from <source package>"),
N_("<source package>") },
{ "rr", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RR,
N_("build source package only from <source package> - calculate dynamic build requires"),
N_("<source package>") },

{ "tp", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TP,
N_("build through %prep (unpack sources and apply patches) from <tarball>"),
Expand All @@ -200,7 +212,9 @@ static struct poptOption rpmBuildPoptTable[] = {
{ "ts", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TS,
N_("build source package only from <tarball>"),
N_("<tarball>") },

{ "tr", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TR,
N_("build source package only from <tarball> - calculate dynamic build requires"),
N_("<tarball>") },
{ "rebuild", '\0', 0, 0, POPT_REBUILD,
N_("build binary package from <source package>"),
N_("<source package>") },
Expand Down Expand Up @@ -623,7 +637,9 @@ int main(int argc, char *argv[])
break;
case 'c':
ba->buildAmount |= RPMBUILD_BUILD;
ba->buildAmount |= RPMBUILD_BUILDREQUIRES;
if (!noDeps) {
ba->buildAmount |= RPMBUILD_DUMPBUILDREQUIRES;
ba->buildAmount |= RPMBUILD_CHECKBUILDREQUIRES;
}
if ((buildChar == 'c') && shortCircuit)
Expand All @@ -634,6 +650,12 @@ int main(int argc, char *argv[])
case 'l':
ba->buildAmount |= RPMBUILD_FILECHECK;
break;
case 'r':
ba->buildAmount |= RPMBUILD_PREP;
ba->buildAmount |= RPMBUILD_BUILDREQUIRES;
ba->buildAmount |= RPMBUILD_DUMPBUILDREQUIRES;
if (!noDeps)
ba->buildAmount |= RPMBUILD_CHECKBUILDREQUIRES;
case 's':
ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
break;
Expand Down
Binary file added tests/data/SOURCES/buildrequires-1.0.tar.gz
Binary file not shown.

0 comments on commit 58dcfdd

Please sign in to comment.