LIBSOLV-POOL(3)
π LIBSOLV-POOL(3) π
(from the LIBSOLV manual, bestie β yes, we're in the LIBSOLV chapter and it's giving iconic documentation energy π«Ά)
πΈ NAME πΈ
libsolv-pool β Libsolv's pool object β¨
π PUBLIC ATTRIBUTES π
Okay so these are the public fields, the little group-chat members of the pool. Some you can read freely, some you should only change through the proper function. Periodt. π
void *appdataβ a no-purpose pointer that's free for you, the library user, to use. When the pool is freed, it just discards the pointer. No cap.Stringpool ssβ the pool of unified strings. π§΅Reldep *relsβ the pool of unified relation dependencies.int nrelsβ number of allocated relation dependencies.Repo **reposβ the array of repository pointers, indexed by repository Id.int nreposβ number of allocated repository array elements, i.e. the size of thereposarray.int ureposβ number of used (i.e. non-zero) repository array elements.Repo *installedβ pointer to the repo holding the installed packages. You can read this attribute all you want, but if you want to change it, usepool_set_installed(). πSolvable *solvablesβ the array ofSolvableobjects.int nsolvablesβ number ofSolvableobjects, i.e. the size of thesolvablesarray. Heads up: the array may contain freed solvables, and in that case the repo pointer of the solvable will be zero. πint disttypeβ the distribution type of your system, e.g.DISTTYPE_DEB. You're free to read this attribute, but you should usepool_setdisttype()if you want to change it.Id *whatprovidesdataβ multi-purposeIdstorage holding zero terminated arrays ofIds.pool_whatprovides()returns an offset into this data. π₯Map *consideredβ optional bitmap that can make the library ignore solvables. If a bitmap is set, only solvables that have a set bit in the bitmap at theirIdare considered usable.int debugmaskβ a mask that defines which debug events should be reported.pool_setdebuglevel()sets this mask. π οΈDatapos posβ an object storing some position in the repository data. Functions likedataiterator_set_pos()set this object, and accessing data with a pseudo solvableIdofSOLVID_POSuses it.Queue pooljobsβ a queue where fixed solver jobs can be stored. These jobs are automatically added whensolver_solve()is called; they're useful to store configuration data like which packages should be multiversion installed. π«Ά
β¨ CREATION AND DESTRUCTION β¨
Pool *pool_create();β create a new instance of a pool. Slay. πvoid pool_free(Pool *pool);β free a pool and all of the data it contains, e.g. the solvables, repositories, strings. It's giving cleanup, and also it's giving finality. π
π οΈ DEBUGGING AND ERROR REPORTING π οΈ
π§Έ Constants π§Έ
SOLV_FATALβ report the error and callexit(1)afterwards. You cannot mask this level. Reports to stderr instead of stdout. πSOLV_ERRORβ used to report errors. Reports to stderr instead of stdout.SOLV_WARNβ used to report warnings.SOLV_DEBUG_STATSβ used to report statistical data.SOLV_DEBUG_RULE_CREATIONβ used to report information about the solver's creation of rules.SOLV_DEBUG_PROPAGATEβ used to report information about the solver's unit rule propagation process.SOLV_DEBUG_ANALYZEβ used to report information about the solver's learnt rule generation mechanism.SOLV_DEBUG_UNSOLVABLEβ used to report information about the solver dealing with conflicting rules.SOLV_DEBUG_SOLUTIONSβ used to report information about the solver creating solutions to solve problems.SOLV_DEBUG_POLICYβ used to report information about the solver searching for an optimal solution.SOLV_DEBUG_RESULTβ used by the debug functions to output results.SOLV_DEBUG_JOBβ used to report information about the job rule generation process.SOLV_DEBUG_SOLVERβ used to report information about what the solver is currently doing.SOLV_DEBUG_TRANSACTIONβ used to report information about the transaction generation and ordering process.SOLV_DEBUG_TO_STDERRβ write debug messages to stderr instead of stdout.
πͺ Functions πͺ
void pool_debug(Pool *pool, int type, const char *format, ...);β report a message of the type type. You can filter debug messages by setting a debug mask.void pool_setdebuglevel(Pool *pool, int level);β set a predefined debug mask. A higher level generally means more bits in the mask are set, thus more messages are printed. ποΈvoid pool_setdebugmask(Pool *pool, int mask);β set the debug mask to filter debug messages.int pool_error(Pool *pool, int ret, const char *format, ...);β set the pool's error string. The ret value is simply used as a return value of the function so that you can write code likereturn pool_error(...);. If the debug mask contains theSOLV_ERRORbit,pool_debug()is also called with the message and typeSOLV_ERROR. π¨extern char *pool_errstr(Pool *pool);β return the current error string stored in the pool. Like with the libc'serrnovalue, the string is only meaningful after a function returned an error.void pool_setdebugcallback(Pool *pool, void (*debugcallback)(Pool *, void *data, int type, const char *str), void *debugcallbackdata);β set a custom debug callback function. Instead of writing to stdout or stderr, the callback function will be called. πͺ
β¨ POOL CONFIGURATION β¨
Okay bestie, this is where you configure the whole pool vibe. It's giving setup era, and we're doing it right. π
π Constants π
These are the constants you can use, no cap:
DISTTYPE_RPMβ For systems whererpmis the low-level package manager. rpm girlies, this one's for you. πDISTTYPE_DEBβ For systems wheredpkgis the low-level package manager. Debian besties rise. π¦DISTTYPE_ARCHβ For systems that use the arch linux package manager. Arch btw. βDISTTYPE_HAIKUβ For systems that use haiku packages. Haiku, you're iconic. πΈPOOL_FLAG_PROMOTEEPOCHβ Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch. This was used at some time in old rpm versions, and modern systems should never need it. Lowkey ancient history. πPOOL_FLAG_FORBIDSELFCONFLICTSβ Disallow the installation of packages that conflict with themselves. Debian always allows self-conflicting packages, rpm used to forbid them but switched to also allowing them recently. So it's a whole saga. πPOOL_FLAG_OBSOLETEUSESPROVIDESβ Make obsolete type dependency match against provides instead of just the name and version of packages. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version. History lesson fr fr. πPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDESβ An implicit obsoletes is the internal mechanism to remove the old package on an update. The default is to remove all packages with the same name; rpm-5 switched to also removing packages providing the same name. The way rpm-5 did its own thing. πPOOL_FLAG_OBSOLETEUSESCOLORSβ Rpm's multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color). Ifobsoleteusescolorsis set, packages with different colors will not obsolete each other. It's giving 32-bit vs 64-bit drama. π¨POOL_FLAG_IMPLICITOBSOLETEUSESCOLORSβ Same asPOOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel. For current Fedora systems,POOL_FLAG_OBSOLETEUSESCOLORSshould be false andPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORSshould be true (this is the default ifFEDORAis defined when libsolv is compiled). Fedora girlies check this. βPOOL_FLAG_NOINSTALLEDOBSOLETESβ New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package. So don't try it unless you're ready to erase. π«POOL_FLAG_HAVEDISTEPOCHβ Mandriva added a new field calleddistepochthat gets checked in version comparison if the epoch/version/release of two packages are the same. Mandriva really said "one more field." β¨POOL_FLAG_NOOBSOLETESMULTIVERSIONβ If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed. So you can have multiples, but obsoleted ones still get yeeted. π§ΉPOOL_FLAG_ADDFILEPROVIDESFILTEREDβ Make theaddfileprovidesmethod only add files from the standard locations (i.e. thebinandetcdirectories). This is useful if you have only few packages that use non-standard file dependencies, but you still want the fast speed thataddfileprovides()generates. Filtered but fast, we love. β‘POOL_FLAG_NOWHATPROVIDESSHRINKβ Do not unify identical provider lists when the whatprovides index is created. This makes creating the index faster, at the price of using more memory. Speed vs memory, classic tradeoff. π§
π οΈ Functions π οΈ
int pool_setdisttype(Pool *pool, int disttype);β Set the package type of your system. The disttype is used for example to define package comparison semantics. Libsolv's default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems. This function returns the old disttype on success, and-1if the new disttype is not supported.
β οΈ Note that anypool_setarchandpool_setarchpolicycalls need to come after thepool_setdisttypecall, as they make use of thenoarch/any/allarchitecture id.
int pool_set_flag(Pool *pool, int flag, int value);β Set a flag to a new value. Returns the old value of the flag. πint pool_get_flag(Pool *pool, int flag);β Get the value of a pool flag. See the constants section about the meaning of the flags. πvoid pool_set_rootdir(Pool *pool, const char *rootdir);β Set a specific root directory. Some library functions support a flag that tells the function to prepend therootdirto file and directory names. πconst char *pool_get_rootdir(Pool *pool);β Return the current value of the root directory. πchar *pool_prepend_rootdir(Pool *pool, const char *dir);β Prepend the root directory to thedirargument string. The returned string has been newly allocated and needs to be freed after use. Don't forget to free, bestie. π«Άchar *pool_prepend_rootdir_tmp(Pool *pool, const char *dir);β Same aspool_prepend_rootdir, but uses the pool's temporary space for allocation. Temp space, no cleanup required. β¨void pool_set_installed(Pool *pool, Repo *repo);β Set which repository should be treated as the "installed" repository, i.e. the one that holds information about the installed packages. This is the one that knows what's already on your system. πvoid pool_set_languages(Pool *pool, const char **languages, int nlanguages);β Set the language of your system. The library provides lookup functions that return localized strings, for example for package descriptions. You can set an array of languages to provide a fallback mechanism if one language is not available. Multilingual queen behavior. πvoid pool_setarch(Pool *pool, const char *arch);β Set the architecture of your system. The architecture is used to determine which packages are installable and which packages cannot be installed. Thearchargument is normally the "machine" value of the "uname" system call. π₯οΈvoid pool_setarchpolicy(Pool *, const char *);β Set the architecture policy for your system. This is the general version ofpool_setarch(in factpool_setarchcallspool_setarchpolicyinternally). See the section about architecture policies for more information. ποΈvoid pool_addvendorclass(Pool *pool, const char **vendorclass);β Add a new vendor equivalence class to the system. A vendor equivalence class defines if an installed package of one vendor can be replaced by a package coming from a different vendor. Thevendorclassargument must be aNULLterminated array of strings. See the section about vendor policies for more information. Vendor drama, but make it official. π€void pool_setvendorclasses(Pool *pool, const char **vendorclasses);β Set all allowed vendor equivalences. Thevendorclassesargument must be anNULLterminated array consisting of all allowed classes concatenated. Each class itself must beNULLterminated, thus the last class ends with twoNULLelements, one to finish the class and one to finish the list of classes. So manyNULLs, but that's the assignment. πvoid pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *));β Define a custom vendor check mechanism. You can use this if libsolv's internal vendor equivalence class mechanism does not match your needs. Custom means custom, periodt. πvoid pool_setloadcallback(Pool *pool, int (*cb)(Pool *, Repodata *, void *), void *loadcbdata);β Define a callback function that gets called when repository metadata needs to be loaded on demand. See the section about on demand loading in thelibsolv-repodatamanual. On-demand loading is highkey useful. β‘void pool_setnamespacecallback(Pool *pool, Id (*cb)(Pool *, void *, Id, Id), void *nscbdata);β Define a callback function to implement custom namespace support. See the section about namespace dependencies. π«Ά
π ID POOL MANAGEMENT π
Okay bestie, this is where the pool keeps all its little identity cards. Every string, every relation β they all get an Id. Let's meet them π
β¨ Constants β¨
ID_EMPTYβ the Id of the empty string, and it is always Id 1. Like, forever. No cap.REL_LTβ represents a<relation.REL_EQβ represents a=relation.REL_GTβ represents a>relation. And the cute part? You can or-together combos ofREL_GT,REL_EQ, andREL_LTto build literally any relation you want. mix and match, it's giving build-a-bear π§ΈREL_ANDβ a boolean AND operation. Thenameandevrparts of the relation can be two sub-dependencies, and packages must match both parts. both of them. obsessed.REL_ORβ a boolean OR operation. Thenameandevrparts of the relation can be two sub-dependencies, and packages can match any part. pick whichever, it's fine β¨REL_WITHβ likeREL_AND, but packages must match both dependencies simultaneously. There's a whole section about boolean dependencies if you want the deep lore.REL_NAMESPACEβ a special namespace relation. See the namespace dependencies section for the tea.REL_ARCHβ an architecture filter dependency. Thenamepart is a sub-dependency, and theevrpart is the Id of an architecture that the matching packages must have. heads up: this is an exact match ignoring architecture policies.REL_FILECONFLICTβ an internal file conflict dependency, used to represent file conflicts. Check out thepool_add_fileconflicts_deps()function if you're curious.REL_CONDβ a conditional dependency. Thenamesub-dependency is only considered if theevrsub-dependency is fulfilled. Boolean dependencies section has more.REL_UNLESSβ a conditional dependency, but flipped: thenamesub-dependency is only considered if theevrsub-dependency is not fulfilled.REL_COMPATβ a compat dependency used in Haiku to represent version ranges. Thenamepart is the actual version, and theevrpart is the backwards compatibility version.REL_KINDβ a pseudo dependency that limits the solvables to a specific kind. The kind is expected to be a prefix of the solvable name, so likepatch:foowould be of kindpatch. fyiREL_KINDis only supported in the selection functions.REL_MULTIARCHβ a debian multiarch annotation. The most common value for theevrpart isany.REL_ELSEβ the else part of aREL_CONDorREL_UNLESSdependency. boolean dependencies section, go look πREL_ERRORβ an illegal dependency. sounds bad and it is, but it's genuinely useful for encoding dependency parse errors.
π«Ά Functions π«Ά
Id pool_str2id(Pool *pool, const char *str, int create);
Add a string to the pool of unified strings and get the Id of that string back. If create is zero, new strings won't be added to the pool β instead you get Id 0. sorry bestie, no new friends.
Id pool_strn2id(Pool *pool, const char *str, unsigned int len, int create);
Same as pool_str2id, but only len characters of the string are used. perfect for adding substrings to the pool, slay βοΈ
Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create);
Create a relational dependency from two other dependencies, name and evr, plus a flag. Peep the REL_ constants for the supported flags. And just like with pool_str2id, create decides whether new dependencies get added or you get Id zero back instead.
Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
Attach a language suffix to a string Id. Use this to make language keyname Ids out of keynames β it's functionally equivalent to converting the id argument to a string, adding a : character and the lang argument to that string, then converting the whole result back into an Id. same energy, fewer steps π«
const char *pool_id2str(const Pool *pool, Id id);
Convert an Id back into a string. If the Id is a relational Id, the name part gets converted instead.
const char *pool_id2rel(const Pool *pool, Id id);
Return the relation string of a relational Id. Returns an empty string if the Id you passed isn't a relation. no relation, no string π
const char *pool_id2evr(const Pool *pool, Id id);
Return the evr part of a relational Id as a string. Again, empty string if the passed Id isn't a relation.
const char *pool_dep2str(Pool *pool, Id id);
Convert an Id back into a string. If the passed Id belongs to a relation, you get a string representing the relation. β οΈ and note: in that case the string is allocated on the pool's temporary space.
void pool_freeidhashes(Pool *pool);
Free the hashes used to unify strings and relations. Use this to save memory when you know for a fact you'll never create new strings and relations again. goodbye hashes, it was real π₯²
void pool_get_idcounts(Pool *pool, unsigned int *nstringsp, unsigned int *nrelsp);
Return the number of string Ids and relation Ids currently chillin' in the pool.
void pool_presize_idhashes(Pool *pool, unsigned int nstrings, unsigned int nrels);
Presize the hashes so that nstrings/nrels new strings/relations can be added without the hashes needing to grow. planning ahead is highkey iconic.
π¦ SOLVABLE FUNCTIONS π¦
Solvable *pool_id2solvable(const Pool *pool, Id p);
Convert a solvable Id into a pointer to the solvable data. β οΈ heads up though: that pointer may become invalid if new solvables are created or old ones get deleted, because the array storing all solvables might get reallocated. don't hold onto it like it's your emotional support pointer, bestie.
Id pool_solvable2id(const Pool *pool, Solvable *s);
Convert a pointer to the solvable data back into a solvable Id. the round trip β¨
const char *pool_solvid2str(Pool *pool, Id p);
Return a string representing the solvable with the Id p. The string will be some canonical representation of the solvable β usually a combo of the name, the version, and the architecture. it's giving package business card π
const char *pool_solvable2str(Pool *pool, Solvable *s);
Same as pool_solvid2str, except instead of the Id you pass a pointer to the solvable. same string, different entry point π«Ά
π DEPENDENCY MATCHING π
β¨ Constants β¨
EVRCMP_COMPAREβ compare all parts of the version, and treat missing parts as empty strings.EVRCMP_MATCH_RELEASEβ a special mode for rpm version string matching. If a version misses a release part, it matches all releases. In that case the special values-2and2get returned, depending on which of the two versions didn't have a release part. yes, those are real numbers, no cap.EVRCMP_MATCHβ a generic match where missing parts always match. very forgiving, very demure.EVRCMP_COMPARE_EVONLYβ only compare the epoch and the version parts, ignore the release part entirely. not me ignoring the release π
πΈ Functions πΈ
int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode);
Compare two version Ids. Returns -1 if the first version is less than the second, 0 if they're identical, and 1 if the first is bigger than the second. classic three-way answer, we love a decisive function π
int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
Same as pool_evrcmp(), but with strings instead of Ids. string girlies rise π
int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release);
Match a version Id against an epoch, a version, and a release string. Passing NULL means that part should match everything. wildcard behaviour, periodt.
int pool_match_dep(Pool *pool, Id d1, Id d2);
Returns 1 if the dependency d1 (the provider) is matched by the dependency d2, otherwise 0. For two dependencies to match, both the name parts must match and the version range described by the evr parts must overlap. it's a two-step vibe check and both steps matter π₯
int pool_match_nevr(Pool *pool, Solvable *s, Id d);
Like pool_match_dep, but the provider is the "self-provides" dependency of the Solvable s, i.e. the dependency sβname = sβevr. self-love as a matching strategy, honestly iconic π
int pool_satisfieddep_map(Pool *pool, const Map *map, Id dep);
Returns 1 if the dependency dep is satisfied by the packages specified in map, otherwise 0. the map said yes or the map said no, there is no maybe β¨
β¨ WHATPROVIDES INDEX β¨
Okay bestie, imagine every single dependency in your pool asking "okay but WHO actually provides me tho?" β this is the index that answers that. It maps dependency Ids β the set of packages that provide that dependency. Iconic.
void pool_createwhatprovides(Pool *pool);
Builds that index. Mapping dep Ids β sets of packages providing them. Slay.
void pool_freewhatprovides(Pool *pool);
Yeets the whatprovides index to save memory. Free your RAM, bestie, it's self-care. π
Id pool_whatprovides(Pool *pool, Id d);
Returns an offset into the Pool's whatprovidesdata array. The solvables whose Ids are stored starting at that offset are the ones that provide dependency d. The solvable list is zero terminated β so you know where it stops, no guessing. π
Id *pool_whatprovides_ptr(Pool *pool, Id d);
Instead of handing you the offset, it hands you the pointer to the Ids sitting at that offset. BUT β huge but β this pointer has a very limited validity time. Any call that adds new values to the whatprovidesdata area may reallocate the array, and then your pointer is just... a ghost. π» Not me warning you twice.
Id pool_queuetowhatprovides(Pool *pool, Queue *q);
Takes the contents of Queue q and drops them at the END of the whatprovidesdata array, then gives you back the offset into the array. Off you go. β¨
void pool_addfileprovides(Pool *pool);
Some package managers (looking at you, rpm π) let dependencies point at files contained in other packages. To let libsolv handle those efficiently, you call this method after creating and reading all repositories β not before, bestie, timing matters. What it does: scans all dependencies for file names, then scans all packages for matching files. If a filename gets matched up, it's added to the provides list of the corresponding package. π¦
void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst);
Same energy as pool_addfileprovides, but the added Ids get returned in two Queues instead: idq for every repository except the one containing the "installed" packages, and idqinst for that latter one. Why tho? Because you can stash this info in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides gets called. Efficiency? Ate. π₯
void pool_set_whatprovides(pool, Id id, Id offset);
Manually set an entry in the whatprovides index. And no β you'll never do this for package dependencies, because those entries are created by calling pool_createwhatprovides(). That's not your job. But this function? Super useful for namespace provides if you don't wanna use a namespace callback to lazily set the provides. The offset argument is an offset in the whatprovides array, which means you can flex "1" as a false value and "2" as a true value. Cute little trick. π
void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
Clears the cache of the providers for namespace dependencies matching namespace ns. If the evr argument is non-zero, only the namespace dependency for exactly that dependency gets cleared β otherwise all matching namespace dependencies get cleared. See the section about Namespace dependencies for the full tea. π
void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
So here's the drama: some package managers like rpm report conflicts when a package installation overwrites a file of another installed package with different content. π And because file content info is not stored in the repository metadata, those conflicts can only be detected after the packages are downloaded. Libsolv provides a function to check for such conflicts: pool_findfileconflicts(). If conflicts are found, they can be added as special REL_FILECONFLICT provides dependencies, so that the solver will know about the conflict when it is re-run. Problem detected, problem handled. π
π§° UTILITY FUNCTIONS π§°
char *pool_alloctmpspace(Pool *pool, int len);
Allocates space on the pool's temporary space area. Careful bestie: this space has a limited lifetime β it gets automatically freed after a fixed amount (currently 16) of other pool_alloctmpspace() calls are done. So don't hold onto it like it's forever, because it is not. π
void pool_freetmpspace(Pool *pool, const char *space);
Gives the space allocated with pool_alloctmpspace back to the system. You do not have to use this function, since the space is automatically reclaimed anyway. But it can be useful if you wanna extend the lifetime of other pointers to the pool's temporary space area. Handy. π«Ά
const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
Converts some binary data into hexadecimal, returning a string allocated in the pool's temporary space area. Hex girl summer. π
char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3);
Joins three strings and returns the result in the pool's temporary space area. And yes, you can pass NULL arguments if you just wanna join fewer strings. Flexible queen. β¨
char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
Like pool_tmpjoin(), but if the first argument is the last allocated space in the pool's temporary space area, it will be replaced with the result of the join and no new temporary space slot gets used. So you can join more than three strings with a combo of one pool_tmpjoin() and multiple pool_tmpappend() calls. Note: the str1 pointer is no longer usable after the call. It's gone, bestie, say bye. π
π DATA LOOKUP π
π Constants π
SOLVID_POSβ Use the data position stored in the pool for the lookup instead of looking up the data of a solvable.SOLVID_METAβ Use the data stored in the meta section of a repository (or repodata area) instead of looking up the data of a solvable. Heads up: this constant does not work for the pool's lookup functions β use it for the repo's or repodata's lookup functions instead. It's just listed here for completeness. π
π Functions π
const char *pool_lookup_str(Pool *pool, Id solvid, Id keyname);
Returns the string value stored under the attribute keyname in solvable solvid. String delivered. π
unsigned long long pool_lookup_num(Pool *pool, Id solvid, Id keyname, unsigned long long notfound);
Returns the 64bit unsigned number stored under the attribute keyname in solvable solvid. And if no such number exists? You get the value of the notfound argument instead. So you always get something, no empty-handed moments. β¨
Id pool_lookup_id(Pool *pool, Id solvid, Id keyname);
Returns the Id stored under the attribute keyname in solvable solvid. Short, sweet, an Id. π
int pool_lookup_idarray(Pool *pool, Id solvid, Id keyname, Queue *q);
Fills queue q with the contents of the Id array stored under the attribute keyname in solvable solvid. Returns "1" if an array was found β otherwise the queue will be empty and "0" gets returned. Binary outcome, no in-between. π¦
int pool_lookup_void(Pool *pool, Id solvid, Id keyname);
Returns "1" if a void value is stored under the attribute keyname in solvable solvid, otherwise "0". Void check, queen. πΈ
const char *pool_lookup_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
Returns the checksum stored under the attribute keyname in solvable solvid. The type of the checksum gets returned through the typep pointer. If no such checksum is found, NULL comes back and the type is set to zero. Also ngl, the result is stored in the Pool's temporary space area β so remember the lifetime thing from earlier, okay? π
const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
Returns the checksum stored under the attribute keyname in solvable solvid, but as binary data. You can use the returned type to calculate the length of the checksum. And the best part: no temporary space area is needed. Periodt. π₯
const char *pool_lookup_deltalocation(Pool *pool, Id solvid, unsigned int *medianrp);
This is a utility lookup function that returns the delta location for a delta rpm. Here's the catch: solvables cannot store deltas, so you have to use SOLVID_POS as argument and set the Pool's datapos pointer to point at valid delta rpm data. No shortcuts, bestie. π
void pool_search(Pool *pool, Id solvid, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
Performs a search over all data stored in the pool. You can limit the search area using the solvid and keyname arguments. The values can optionally be matched against the match argument β pass NULL if you do not want that matching to happen. See the Dataiterator manpage for the possible match modes and for the flags argument. For all (matching) values, the callback function gets called with the cbdata callback argument plus the data describing the value. Callback girlies, this one's for you. π
π JOB AND SELECTION FUNCTIONS π
Okay so, a Job consists of two Ids: how and what. The how part describes the action, the job flags, and the selection method β while the what part is the input for the selection. A Selection is a queue consisting of multiple jobs (which means the number of elements in the queue must be a multiple of two β do the math bestie, it has to line up β¨). See the Solver manpage for more info about jobs.
const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
Converts a job into a string. Useful for debugging purposes. The flagmask can be used to mask the flags of the job: use "0" if you don't wanna see such flags, "-1" to see all flags, or a combination of the flags you want to see. Your view, your choice. π
void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
Returns a list of solvables that the specified job selects. Drop them in the queue, boom. π
int pool_isemptyupdatejob(Pool *pool, Id how, Id what);
Returns "1" if the job is an update job that does not work with any installed package β meaning the job is basically a no-op. You can use this to turn no-op update jobs into install jobs (as done by package managers like "zypper"). Sneaky but valid. π
const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
Converts a selection into a string. Useful for debugging purposes. See the pool_job2str() function for the flagmask argument. Same flagmask energy, different day. πΈ
π ODDS AND ENDS π
void pool_freeallrepos(Pool *pool, int reuseids);
Frees all repos from the pool (including all solvables). If reuseids is true, all Ids of the solvables are free to be reused the next time solvables are created. Recycling era, we love to see it. β»οΈ
void pool_clear_pos(Pool *pool);
Clears the data position stored in the pool. Position? Cleared. Gone. π
ποΈ ARCHITECTURE POLICIES ποΈ
An architecture policy defines a list of architectures that can be installed on the system, plus the relationship between them (i.e. the ordering, the hierarchy, the whole vibe). Architectures can be delimited with three different characters:
':'β No relationship between the architectures, like at all. A package of one architecture can not be replaced with one of the other architecture. They're strangers. π«'>'β The first architecture is better than the second one. An installed package of the second architecture may be replaced with one from the first architecture, and vice versa. The solver will select the better architecture if the versions are the same. Main character architecture energy, honestly. π'='β The two architectures are freely exchangeable. Used to define aliases for architectures. Twins basically. π¦
An example would be 'x86_64:i686=athlon>i586'. Let's decode that tea: it means x86_64 packages can only be replaced by other x86_64 packages; i686 packages can be replaced by i686 and i586 packages (but i686 packages will be preferred β¨); and athlon is another name for the i686 architecture. The way that whole string is just architecture lore? Iconic.
You can turn off the architecture replacement checks with the Solver's SOLVER_FLAG_ALLOW_ARCHCHANGE flag. Your pool, your rules. π
π VENDOR POLICIES π
okay so here's the tea bestie: different vendors usually compile their packages with different features, right? so Libsolv is like, no, we're not swapping an installed package from one vendor for a package from a totally different vendor. only same-vendor-to-same-vendor replacements allowed. also β and this is the important part β while the version of a package is normally set by the upstream project, the release chunk of the version is set by the vendor's own package maintainer. so doing version comparisons across different vendors? literally meaningless, don't even try it. π
when we say "vendor" here, we mean the SOLVABLE_VENDOR string stored in each solvable. sometimes a vendor changes its name, or a bunch of vendors form a group and coordinate their package building together β so libsolv gives you a way to declare that a whole squad of vendors is compatible. you do that by defining vendor equivalence classes: packages from a vendor in one class can be replaced by packages from any other vendor in that same class. slay. π
you can have multiple equivalence classes, and the set of allowed vendor changes for one installed package is computed by building the union of all the equivalence classes that the installed package's vendor belongs to. math but make it fashion. β¨
and if you want to just switch the whole vibe off, you can disable the vendor replacement checks with the Solver's SOLVER_FLAG_ALLOW_VENDORCHANGE flag.
π§ BOOLEAN DEPENDENCIES π§
Boolean Dependencies let you build complex expressions out of simple dependencies. heads up though β depending on which package manager you're on, only a subset of these may be useful. for example, debian currently only allows an "OR" expression. noted, no cap.
REL_OR
true if either the first dependency or the second one is true. this is the one you want for package dependencies like "Requires", where you can say that either one of the packages needs to be installed.
REL_AND
true if both dependencies are true. the packages fulfilling them may be totally different ones, i.e. "Supplements: perl REL_AND python" is true if both a package providing perl and a package providing python are installed.
REL_WITH
true if both dependencies are true and they're fulfilled by the same package. so "Supplements: perl REL_WITH python" would only be true if there's a package installed that provides both dependencies β like some kind of multi-language interpreter. one package doing the absolute most. π
REL_COND
true if the first dependency is true or the second dependency is false. "A REL_COND B" is equivalent to "A REL_OR (NOT B)" β except that libsolv doesn't expose "NOT". awkward but we move.
REL_UNLESS
true if the first dependency is true and the second dependency is false. "A REL_UNLESS B" is equivalent to "A REL_AND (NOT B)" β again, except libsolv doesn't expose "NOT".
REL_ELSE
the "else" part of a "REL_COND" or "REL_UNLESS" dependency. it has to sit directly in the evr part of the condition, e.g. "foo REL_COND (bar REL_ELSE baz)".
- for
"REL_COND"this is equivalent to writing"(foo REL_COND bar) REL_AND (bar REL_OR baz)". - for
"REL_UNLESS"this is equivalent to writing"(foo REL_UNLESS bar) REL_OR (bar REL_AND baz)".
each sub-dependency of a boolean dependency can itself be a boolean dependency, so you can chain them together to build truly elaborate dependencies. nesting dolls but make it dependency resolution π
π NAMESPACE DEPENDENCIES π
Namespace dependencies are how you implement dependencies on attributes that live outside of libsolv entirely. the classic example: a dependency on the language the user has set. these types of dependencies are usually only used for "Conflicts" or "Supplements" dependencies, since the underlying package manager has no idea how to deal with them. it's giving "not my department". π
if the library needs to evaluate a namespace dependency, it calls the namespace callback function set in the pool. that callback can return a set of packages that "provide" the dependency. and if the dependency is provided by the system itself, the returned set should consist of just the system solvable β that's Solvable Id 1.
the returned set of packages must be handed back as an offset into the whatprovidesdata array. you can use the pool_queuetowhatprovides function to convert a queue into exactly that kind of offset. to make your life easier when writing the callback, the return values "0" and "1" are not interpreted as an offset:
"0"means there's no package in the return set."1"means just the system solvable is in the set.
the returned set gets cached, so for each namespace dependency the callback is only called once. if you need to flush that cache β say, because the user switched to a different language β use the pool_flush_namespaceproviders() function. cache cleared, fresh start, we love a reset. π¦
β¨ AUTHOR β¨
Michael Schroeder <mls@suse.de>
and that's a wrap on the whole page, bestie!! πΈ you just read the entire LIBSOLV-POOL(3) manual β source and version: libsolv, dated 10/21/2026. iconic behavior, honestly. go forth and pool responsibly. ππ«Ά
π¦ where this page comes from
- arch rolling: libsolv 0.7.41-1 Β· BSD-3-Clause
- fedora 44: libsolv-devel 0.7.41-1.fc44 Β· BSD-3-Clause
- fedora 44: libsolv-devel 0.7.41-1.fc44 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms