#define MODE_INFO 7
#define MODE_REPOLIST 8
#define MODE_SEARCH 9
+#define MODE_ERASECLEAN 10
void
usage(int r)
mainmode = MODE_ERASE;
mode = SOLVER_ERASE;
}
+ else if (!strcmp(argv[0], "eraseclean") || !strcmp(argv[0], "rmclean"))
+ {
+ mainmode = MODE_ERASECLEAN;
+ mode = SOLVER_ERASE;
+ }
else if (!strcmp(argv[0], "list"))
{
mainmode = MODE_LIST;
}
}
job.elements[i] |= mode;
+ if (mainmode == MODE_ERASECLEAN)
+ job.elements[i] |= SOLVER_CLEANDEPS;
}
if (mainmode == MODE_DISTUPGRADE && allpkgs && repofilter)
solv->allowarchchange = 1;
solv->allowvendorchange = 1;
}
- if (mainmode == MODE_ERASE)
+ if (mainmode == MODE_ERASE || mainmode == MODE_ERASECLEAN)
solv->allowuninstall = 1; /* don't nag */
solver_solve(solv, &job);
if (!yesno("OK to continue (y/n)? "))
{
printf("Abort.\n");
+ solver_free(solv);
+ queue_free(&job);
+ pool_free(pool);
+ free_repoinfos(repoinfos, nrepoinfos);
+ sat_free(commandlinepkgs);
+#ifdef FEDORA
+ yum_substitute(pool, 0);
+#endif
exit(1);
}
#define RULES_BLOCK 63
static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
+static void solver_createcleandepsmap(Solver *solv);
/*-------------------------------------------------------------------
* Check if dependency is possible
break;
if (i < q->count)
continue;
- queue_push(q, DISABLE_INFARCH);
- queue_push(q, s->name);
+ queue_push2(q, DISABLE_INFARCH, s->name);
}
}
}
break;
s = pool->solvables + what;
if (solv->infarchrules != solv->infarchrules_end)
- {
- queue_push(q, DISABLE_INFARCH);
- queue_push(q, s->name);
- }
+ queue_push2(q, DISABLE_INFARCH, s->name);
if (solv->duprules != solv->duprules_end)
- {
- queue_push(q, DISABLE_DUP);
- queue_push(q, s->name);
- }
+ queue_push2(q, DISABLE_DUP, s->name);
if (!installed)
return;
if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
{
/* XXX: remove if we always do distupgrade with DUP rules */
if (solv->distupgrade && s->repo == installed)
- {
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, what);
- return;
- }
+ queue_push2(q, DISABLE_UPDATE, what);
return;
}
if (s->repo == installed)
{
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, what);
+ queue_push2(q, DISABLE_UPDATE, what);
return;
}
if (s->obsoletes)
continue;
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
+ queue_push2(q, DISABLE_UPDATE, p);
}
}
FOR_PROVIDES(p, pp, s->name)
continue;
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
+ queue_push2(q, DISABLE_UPDATE, p);
}
return;
case SOLVER_ERASE:
break;
FOR_JOB_SELECT(p, pp, select, what)
if (pool->solvables[p].repo == installed)
- {
- queue_push(q, DISABLE_UPDATE);
- queue_push(q, p);
- }
+ queue_push2(q, DISABLE_UPDATE, p);
return;
default:
return;
lastjob = j;
jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
}
+ if (solv->cleandepsmap.size)
+ {
+ solver_createcleandepsmap(solv);
+ for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+ queue_push2(&allq, DISABLE_UPDATE, i);
+ }
MAPZERO(&solv->noupdate);
for (i = 0; i < allq.count; i += 2)
{
lastjob = j;
jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
}
+ if (solv->cleandepsmap.size)
+ {
+ solver_createcleandepsmap(solv);
+ for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+ queue_push2(&allq, DISABLE_UPDATE, i);
+ }
for (j = 0; j < q.count; j += 2)
{
Id type = q.elements[j], arg = q.elements[j + 1];
}
}
+void solver_createcleandepsmap(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Queue *job = &solv->job;
+ Map userinstalled;
+ Map im;
+ Map installedm;
+ Rule *r;
+ Id rid, how, what, select;
+ Id p, pp, ip, *jp;
+ Id req, *reqp, sup, *supp;
+ Solvable *s;
+ Queue iq;
+ int i;
+
+ map_init(&userinstalled, installed->end - installed->start);
+ map_init(&im, pool->nsolvables);
+ map_init(&installedm, pool->nsolvables);
+ map_empty(&solv->cleandepsmap);
+ queue_init(&iq);
+
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_USERINSTALLED:
+ what = job->elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ break;
+ }
+ }
+ /* add all positive elements (e.g. locks) to "userinstalled" */
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->d < 0)
+ continue;
+ FOR_RULELITERALS(p, jp, r)
+ if (p > 0 && pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->p >= 0 || r->d != 0)
+ continue; /* disabled or not erase */
+ p = -r->p;
+ if (pool->solvables[p].repo != installed)
+ continue;
+ MAPCLR(&userinstalled, p - installed->start);
+ i = solv->ruletojob.elements[rid - solv->jobrules];
+ how = job->elements[i];
+ if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
+ queue_push(&iq, p);
+ }
+ for (p = installed->start; p < installed->end; p++)
+ {
+ if (pool->solvables[p].repo != installed)
+ continue;
+ MAPSET(&installedm, p);
+ MAPSET(&im, p);
+ }
+
+ while (iq.count)
+ {
+ ip = queue_shift(&iq);
+ if (!MAPTST(&im, ip))
+ continue;
+ if (!MAPTST(&installedm, ip))
+ continue;
+ if (MAPTST(&userinstalled, ip))
+ continue;
+ MAPCLR(&im, ip);
+ s = pool->solvables + ip;
+#ifdef CLEANDEPSDEBUG
+ printf("hello %s\n", solvable2str(pool, s));
+#endif
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ while ((req = *reqp++) != 0)
+ {
+ if (req == SOLVABLE_PREREQMARKER)
+ continue;
+#if 0
+ /* count number of installed packages that match */
+ count = 0;
+ FOR_PROVIDES(p, pp, req)
+ if (MAPTST(&installedm, p))
+ count++;
+ if (count > 1)
+ continue;
+#endif
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (MAPTST(&im, p))
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (s->recommends)
+ {
+ reqp = s->repo->idarraydata + s->recommends;
+ while ((req = *reqp++) != 0)
+ {
+#if 0
+ count = 0;
+ FOR_PROVIDES(p, pp, req)
+ if (MAPTST(&installedm, p))
+ count++;
+ if (count > 1)
+ continue;
+#endif
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (MAPTST(&im, p))
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (!iq.count)
+ {
+ /* supplements pass */
+ for (ip = solv->installed->start; ip < solv->installed->end; ip++)
+ {
+ if (!MAPTST(&installedm, ip))
+ continue;
+ s = pool->solvables + ip;
+ if (!s->supplements)
+ continue;
+ if (!MAPTST(&im, ip))
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
+ break;
+ /* no longer supplemented, also erase */
+ if (sup)
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+ queue_push(&iq, ip);
+ }
+ }
+ }
+ }
+
+ /* turn userinstalled into remove set for pruning */
+ map_empty(&userinstalled);
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->p >= 0 || r->d != 0)
+ continue; /* disabled or not erase */
+ p = -r->p;
+ MAPCLR(&im, p);
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ for (p = installed->start; p < installed->end; p++)
+ if (MAPTST(&im, p))
+ queue_push(&iq, p);
+ for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+ {
+ r = solv->rules + rid;
+ if (r->d < 0)
+ continue;
+ FOR_RULELITERALS(p, jp, r)
+ if (p > 0)
+ queue_push(&iq, p);
+ }
+ while (iq.count)
+ {
+ ip = queue_shift(&iq);
+ s = pool->solvables + ip;
+#ifdef CLEANDEPSDEBUG
+ printf("bye %s\n", solvable2str(pool, s));
+#endif
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ while ((req = *reqp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+ {
+ if (p == ip)
+ continue;
+#ifdef CLEANDEPSDEBUG
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ MAPSET(&im, p);
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (s->recommends)
+ {
+ reqp = s->repo->idarraydata + s->recommends;
+ while ((req = *reqp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, req)
+ {
+ if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+ {
+ if (p == ip)
+ continue;
+ if (MAPTST(&userinstalled, p - installed->start))
+ continue;
+#ifdef CLEANDEPSDEBUG
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+ MAPSET(&im, p);
+ queue_push(&iq, p);
+ }
+ }
+ }
+ }
+ if (!iq.count)
+ {
+ /* supplements pass */
+ for (ip = installed->start; ip < installed->end; ip++)
+ {
+ if (!MAPTST(&installedm, ip))
+ continue;
+ if (MAPTST(&userinstalled, ip - installed->start))
+ continue;
+ s = pool->solvables + ip;
+ if (!s->supplements)
+ continue;
+ if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (dep_possible(solv, sup, &im))
+ break;
+ if (sup)
+ {
+#ifdef CLEANDEPSDEBUG
+ printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+ MAPSET(&im, ip);
+ queue_push(&iq, ip);
+ }
+ }
+ }
+ }
+
+ queue_free(&iq);
+ for (p = installed->start; p < installed->end; p++)
+ {
+ if (pool->solvables[p].repo != installed)
+ continue;
+ if (!MAPTST(&im, p))
+ MAPSET(&solv->cleandepsmap, p - installed->start);
+ }
+ map_free(&im);
+ map_free(&installedm);
+ map_free(&userinstalled);
+}
+
+
/* EOF */
map_free(&solv->dupmap);
map_free(&solv->dupinvolvedmap);
map_free(&solv->droporphanedmap);
+ map_free(&solv->cleandepsmap);
sat_free(solv->decisionmap);
sat_free(solv->rules);
if (solv->decisionmap[i] == 0)
{
olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
- level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+ if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
+ {
+ POOL_DEBUG(SAT_DEBUG_POLICY, "cleandeps erasing %s\n", solvid2str(pool, i));
+ level = setpropagatelearn(solv, level, -i, disablerules, 0);
+ }
+ else
+ {
+ POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
+ level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+ }
if (level == 0)
{
queue_free(&dq);
}
/*
+ * add a rule created by a job, record job number and weak flag
+ */
+static inline void
+solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
+{
+ solver_addrule(solv, p, d);
+ queue_push(&solv->ruletojob, job);
+ if (weak)
+ queue_push(&solv->weakruleq, solv->nrules - 1);
+}
+
+/*
*
* solve job queue
*
p = queue_shift(&q); /* get first candidate */
d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q); /* internalize */
}
- solver_addrule(solv, p, d); /* add install rule */
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, p, d, i, weak);
break;
case SOLVER_ERASE:
- POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(solv, select, what));
+ if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && solv->installed)
+ map_grow(&solv->cleandepsmap, solv->installed->end - solv->installed->start);
if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
{
/* special case for "erase a specific solvable": we also
* erase all other solvables with that name, so that they
* don't get picked up as replacement */
+ /* XXX: look also at packages that obsolete this package? */
name = pool->solvables[what].name;
FOR_PROVIDES(p, pp, name)
{
/* keep installcandidates of other jobs */
if (MAPTST(&installcandidatemap, p))
continue;
- solver_addrule(solv, -p, 0); /* remove by Id */
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */
}
}
FOR_JOB_SELECT(p, pp, select, what)
- {
- solver_addrule(solv, -p, 0);
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
- }
+ solver_addjobrule(solv, -p, 0, i, weak);
break;
case SOLVER_UPDATE:
FOR_JOB_SELECT(p, pp, select, what)
{
s = pool->solvables + p;
- if (installed && s->repo == installed)
- solver_addrule(solv, p, 0);
- else
- solver_addrule(solv, -p, 0);
- queue_push(&solv->ruletojob, i);
- if (weak)
- queue_push(&solv->weakruleq, solv->nrules - 1);
+ solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, i, weak);
}
break;
case SOLVER_DISTUPGRADE:
MAPSET(&solv->droporphanedmap, p - installed->start);
}
break;
+ case SOLVER_USERINSTALLED:
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: user installed %s\n", solver_select2str(solv, select, what));
+ break;
default:
POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
break;
map_free(&installedmap);
}
-
-#if 0
-#define FIND_INVOLVED_DEBUG 0
-void
-solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
-{
- Pool *pool = solv->pool;
- Map im;
- Map installedm;
- Solvable *s;
- Queue iq;
- Queue installedq_internal;
- Id tp, ip, p, pp, req, *reqp, sup, *supp;
- int i, count;
-
- tp = ts - pool->solvables;
- queue_init(&iq);
- queue_init(&installedq_internal);
- map_init(&im, pool->nsolvables);
- map_init(&installedm, pool->nsolvables);
-
- if (!installedq)
- {
- installedq = &installedq_internal;
- if (solv->installed)
- {
- for (ip = solv->installed->start; ip < solv->installed->end; ip++)
- {
- s = pool->solvables + ip;
- if (s->repo != solv->installed)
- continue;
- queue_push(installedq, ip);
- }
- }
- }
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- MAPSET(&installedm, ip);
- MAPSET(&im, ip);
- }
-
- queue_push(&iq, ts - pool->solvables);
- while (iq.count)
- {
- ip = queue_shift(&iq);
- if (!MAPTST(&im, ip))
- continue;
- if (!MAPTST(&installedm, ip))
- continue;
- MAPCLR(&im, ip);
- s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
- printf("hello %s\n", solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
- if (req == SOLVABLE_PREREQMARKER)
- continue;
- /* count number of installed packages that match */
- count = 0;
- FOR_PROVIDES(p, pp, req)
- if (MAPTST(&installedm, p))
- count++;
- if (count > 1)
- continue;
- FOR_PROVIDES(p, pp, req)
- {
- if (MAPTST(&im, p))
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)
- {
- count = 0;
- FOR_PROVIDES(p, pp, req)
- if (MAPTST(&installedm, p))
- count++;
- if (count > 1)
- continue;
- FOR_PROVIDES(p, pp, req)
- {
- if (MAPTST(&im, p))
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- queue_push(&iq, p);
- }
- }
- }
- }
- if (!iq.count)
- {
- /* supplements pass */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (!MAPTST(&im, ip))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
- break;
- /* no longer supplemented, also erase */
- if (sup)
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
- queue_push(&iq, ip);
- }
- }
- }
- }
-
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (MAPTST(&im, ip))
- queue_push(&iq, ip);
- }
-
- while (iq.count)
- {
- ip = queue_shift(&iq);
- if (!MAPTST(&installedm, ip))
- continue;
- s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
- printf("bye %s\n", solvable2str(pool, s));
-#endif
- if (s->requires)
- {
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
- {
- FOR_PROVIDES(p, pp, req)
- {
- if (!MAPTST(&im, p))
- {
- if (p == tp)
- continue;
-#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- MAPSET(&im, p);
- queue_push(&iq, p);
- }
- }
- }
- }
- if (s->recommends)
- {
- reqp = s->repo->idarraydata + s->recommends;
- while ((req = *reqp++) != 0)
- {
- FOR_PROVIDES(p, pp, req)
- {
- if (!MAPTST(&im, p))
- {
- if (p == tp)
- continue;
-#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
- MAPSET(&im, p);
- queue_push(&iq, p);
- }
- }
- }
- }
- if (!iq.count)
- {
- /* supplements pass */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (ip == tp)
- continue;
- s = pool->solvables + ip;
- if (!s->supplements)
- continue;
- if (MAPTST(&im, ip))
- continue;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
- break;
- if (sup)
- {
-#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
- MAPSET(&im, ip);
- queue_push(&iq, ip);
- }
- }
- }
- }
-
- queue_free(&iq);
-
- /* convert map into result */
- for (i = 0; i < installedq->count; i++)
- {
- ip = installedq->elements[i];
- if (MAPTST(&im, ip))
- continue;
- if (ip == ts - pool->solvables)
- continue;
- queue_push(q, ip);
- }
- map_free(&im);
- map_free(&installedm);
- queue_free(&installedq_internal);
-}
-#endif
-
Map dupmap; /* packages from dup repos */
Map dupinvolvedmap; /* packages involved in dup process */
Map droporphanedmap; /* packages to drop in dup mode */
+ Map cleandepsmap; /* try to drop those packages as of cleandeps erases */
Queue *ruleinfoq; /* tmp space for solver_ruleinfo() */
} Solver;
#define SOLVER_DISTUPGRADE 0x0700
#define SOLVER_VERIFY 0x0800
#define SOLVER_DROP_ORPHANED 0x0900
+#define SOLVER_USERINSTALLED 0x0a00
#define SOLVER_JOBMASK 0xff00
#define SOLVER_WEAK 0x010000
#define SOLVER_ESSENTIAL 0x020000
+#define SOLVER_CLEANDEPS 0x040000
/* old API compatibility, do not use in new code */
#if 1