SET (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
INSTALL( FILES ${CMAKE_MODULE_PATH}/FindLibSolv.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules )
+# for shared libraries on windows (DLLs), we just export all symbols for now
+SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+
INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake)
SET (have_system x)
ADD_SUBDIRECTORY (src)
ADD_SUBDIRECTORY (ext)
ADD_SUBDIRECTORY (tools)
-IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
+IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_PYTHON3 OR ENABLE_RUBY OR ENABLE_TCL)
ADD_SUBDIRECTORY (bindings)
-ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
+ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_PYTHON3 OR ENABLE_RUBY OR ENABLE_TCL)
ADD_SUBDIRECTORY (examples)
ADD_SUBDIRECTORY (doc)
This file contains the major changes between
libsolv versions:
+Version 0.7.12
+- conda: support packages.conda repositories
+- conda: de-priorize track features
+- allow win32 to build shared lib
+- selected bug fixes:
+ * fix ruleinfo of complex dependencies returning the wrong origin
+
Version 0.7.11
- ENABLE_RPMDB_LIBRPM is now the default
- selected bug fixes:
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "11")
+SET(LIBSOLV_PATCH "12")
Pool *pool;
Repo *repo;
Repodata *data;
+
+ Stringpool fnpool;
+ Queue fndata;
};
static int
}
static int
+parse_trackfeatures(struct parsedata *pd, struct solv_jsonparser *jp, Id handle)
+{
+ int type = JP_ARRAY;
+ while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
+ {
+ if (type == JP_STRING)
+ {
+ char *p = jp->value, *pe;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p)
+ continue;
+ for (pe = p + strlen(p) - 1; pe > p; pe--)
+ if (*pe != ' ' && *pe != '\t')
+ break;
+ repodata_add_idarray(pd->data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pd->pool, p, pe - p + 1, 1));
+ }
+ else
+ type = jsonparser_skip(jp, type);
+ }
+ return type;
+}
+
+static void
+swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb)
+{
+ Pool *pool = repo->pool;
+ Solvable tmp;
+
+ tmp = pool->solvables[pa];
+ pool->solvables[pa] = pool->solvables[pb];
+ pool->solvables[pb] = tmp;
+ repodata_swap_attrs(data, pa, pb);
+}
+
+static Id *
+fn2data(struct parsedata *pd, const char *fn, Id *fntypep, int create)
+{
+ size_t l = strlen(fn), extl = 0;
+ Id fnid;
+ if (l > 6 && !strcmp(fn + l - 6, ".conda"))
+ extl = 6;
+ else if (l > 8 && !strcmp(fn + l - 8, ".tar.bz2"))
+ extl = 8;
+ else
+ return 0;
+ fnid = stringpool_strn2id(&pd->fnpool, fn, l - extl, create);
+ if (!fnid)
+ return 0;
+ if (fnid * 2 + 2 > pd->fndata.count)
+ queue_insertn(&pd->fndata, pd->fndata.count, fnid * 2 + 2 - pd->fndata.count, 0);
+ if (fntypep)
+ *fntypep = extl == 8 ? 1 : 2; /* 1: legacy .tar.bz2 2: .conda */
+ return pd->fndata.elements + 2 * fnid;
+}
+
+static int
parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn)
{
int type = JP_OBJECT;
Pool *pool= pd->pool;
Repodata *data = pd->data;
Solvable *s;
- Id handle = repo_add_solvable(pd->repo);
- s = pool_id2solvable(pool, handle);
+ Id handle;
char *fn = 0;
char *subdir = 0;
+ Id *fndata = 0, fntype = 0;
+ handle = repo_add_solvable(pd->repo);
+ s = pool_id2solvable(pool, handle);
while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
{
if (type == JP_STRING && !strcmp(jp->key, "build"))
ts /= 1000;
repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts);
}
+ else if (type == JP_STRING && !strcmp(jp->key, "track_features"))
+ {
+ char *p = jp->value, *pe;
+ for (; *p; p++)
+ {
+ if (*p == ' ' || *p == '\t' || *p == ',')
+ continue;
+ pe = p + 1;
+ while (*pe && *pe != ' ' && *pe != '\t' && *pe != ',')
+ pe++;
+ repodata_add_idarray(data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pool, p, pe - p, 1));
+ p = pe - 1;
+ }
+ }
+ else if (type == JP_ARRAY && !strcmp(jp->key, "track_features"))
+ type = parse_trackfeatures(pd, jp, handle);
else
type = jsonparser_skip(jp, type);
}
if (fn || kfn)
- repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
+ {
+ repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
+ fndata = fn2data(pd, fn ? fn : kfn, &fntype, 1);
+ }
solv_free(fn);
solv_free(subdir);
if (!s->evr)
s->evr = 1;
if (s->name)
s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+
+ if (fndata)
+ {
+ /* deal with legacy package entries */
+ if (fndata[0] && fndata[0] > fntype)
+ {
+ /* ignore this package */
+ repo_free_solvable(pd->repo, handle, 1);
+ return type;
+ }
+ if (fndata[0] && fndata[0] < fntype)
+ {
+ /* replace old package */
+ swap_solvables(pd->repo, data, handle, fndata[1]);
+ repo_free_solvable(pd->repo, handle, 1);
+ handle = fndata[1];
+ }
+ fndata[0] = fntype;
+ fndata[1] = handle;
+ }
return type;
}
{
if (type == JP_OBJECT && !strcmp("packages", jp->key))
type = parse_packages(pd, jp);
- if (type == JP_ARRAY && !strcmp("packages", jp->key))
+ else if (type == JP_ARRAY && !strcmp("packages", jp->key))
+ type = parse_packages2(pd, jp);
+ else if (type == JP_OBJECT && !strcmp("packages.conda", jp->key))
+ type = parse_packages(pd, jp);
+ else if (type == JP_ARRAY && !strcmp("packages.conda", jp->key))
type = parse_packages2(pd, jp);
else
type = jsonparser_skip(jp, type);
pd.pool = pool;
pd.repo = repo;
pd.data = data;
+ stringpool_init_empty(&pd.fnpool);
+ queue_init(&pd.fndata);
jsonparser_init(&jp, fp);
if ((type = jsonparser_parse(&jp)) != JP_OBJECT)
ret = pool_error(pool, -1, "parse error line %d", jp.line);
jsonparser_free(&jp);
+ queue_free(&pd.fndata);
+ stringpool_free(&pd.fnpool);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
Queue q;
queue_init(&q);
- for (p = 1; p < pool->nsolvables; p++)
+ FOR_REPO_SOLVABLES(repo, p, s)
{
const char *status;
s = pool->solvables + p;
else if (q.elements[i + 1] == retractedname && q.elements[i + 2] == retractedevr)
{
s = pool->solvables + q.elements[i];
- s->provides = repo_addid_dep(repo, s->provides, retractedmarker, 0);
+ s->provides = repo_addid_dep(s->repo, s->provides, retractedmarker, 0);
}
}
queue_free(&q);
static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
{
- return gzread((gzFile)cookie, buf, nbytes);
+ ssize_t r = gzread((gzFile)cookie, buf, nbytes);
+ if (r == 0)
+ {
+ int err = 0;
+ gzerror((gzFile)cookie, &err);
+ if (err == Z_BUF_ERROR)
+ r = -1;
+ }
+ return r;
}
static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
-------------------------------------------------------------------
+Mon Apr 20 17:24:21 CEST 2020 - mls@suse.de
+
+- fix ruleinfo of complex dependencies returning the wrong origin
+- bump version to 0.7.12
+
+-------------------------------------------------------------------
Wed Jan 22 13:52:48 CET 2020 - mls@suse.de
- fixed solv_zchunk decoding error if large chunks are used
ENDIF (HAVE_LINKER_VERSION_SCRIPT)
IF (DISABLE_SHARED)
-ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS})
+ ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS})
ELSE (DISABLE_SHARED)
-ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS})
+ ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS})
ENDIF (DISABLE_SHARED)
+IF (WIN32)
+ IF (DISABLE_SHARED)
+ TARGET_COMPILE_DEFINITIONS(libsolv PUBLIC SOLV_STATIC_LIB)
+ ELSE (DISABLE_SHARED)
+ TARGET_COMPILE_DEFINITIONS(libsolv PRIVATE SOLV_EXPORTS)
+ ENDIF (DISABLE_SHARED)
+ENDIF (WIN32)
+
SET_TARGET_PROPERTIES(libsolv PROPERTIES OUTPUT_NAME "solv")
SET_TARGET_PROPERTIES(libsolv PROPERTIES SOVERSION ${LIBSOLV_SOVERSION})
KNOWNID(LIBSOLV_SELF_DESTRUCT_PKG, "libsolv-self-destruct-pkg()"), /* this package will self-destruct on installation */
KNOWNID(SOLVABLE_CONSTRAINS, "solvable:constrains"), /* conda */
+KNOWNID(SOLVABLE_TRACK_FEATURES, "solvable:track_features"), /* conda */
KNOWNID(ID_NUM_INTERNAL, 0)
static int
pool_buildversioncmp(Pool *pool, Solvable *s1, Solvable *s2)
{
- const char *bv1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION);
- const char *bv2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION);
+ const char *bv1, *bv2;
+ unsigned int cnt1, cnt2;
+ cnt1 = solvable_lookup_count(s1, SOLVABLE_TRACK_FEATURES);
+ cnt2 = solvable_lookup_count(s2, SOLVABLE_TRACK_FEATURES);
+ if (cnt1 != cnt2)
+ return cnt1 > cnt2 ? -1 : 1;
+ bv1 = solvable_lookup_str(s1, SOLVABLE_BUILDVERSION);
+ bv2 = solvable_lookup_str(s2, SOLVABLE_BUILDVERSION);
if (!bv1 && !bv2)
return 0;
return pool_evrcmp_str(pool, bv1 ? bv1 : "" , bv2 ? bv2 : "", EVRCMP_COMPARE);
}
}
+static Offset *
+solvable_offsetptr(Solvable *s, Id keyname)
+{
+ switch(keyname)
+ {
+ case SOLVABLE_PROVIDES:
+ return &s->provides;
+ case SOLVABLE_OBSOLETES:
+ return &s->obsoletes;
+ case SOLVABLE_CONFLICTS:
+ return &s->conflicts;
+ case SOLVABLE_REQUIRES:
+ return &s->requires;
+ case SOLVABLE_RECOMMENDS:
+ return &s->recommends;
+ case SOLVABLE_SUGGESTS:
+ return &s->suggests;
+ case SOLVABLE_SUPPLEMENTS:
+ return &s->supplements;
+ case SOLVABLE_ENHANCES:
+ return &s->enhances;
+ default:
+ return 0;
+ }
+}
+
static void
repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
{
return 0;
}
-static int
-lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
-{
- Id *p;
-
- queue_empty(q);
- if (off)
- for (p = repo->idarraydata + off; *p; p++)
- queue_push(q, *p);
- return 1;
-}
-
int
repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
{
int i;
if (entry >= 0)
{
+ Offset *offp;
switch (keyname)
{
case SOLVABLE_PROVIDES:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
case SOLVABLE_OBSOLETES:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
case SOLVABLE_CONFLICTS:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
case SOLVABLE_REQUIRES:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
case SOLVABLE_RECOMMENDS:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
case SOLVABLE_SUGGESTS:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
case SOLVABLE_SUPPLEMENTS:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
case SOLVABLE_ENHANCES:
- return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
+ offp = solvable_offsetptr(repo->pool->solvables + entry, keyname);
+ if (*offp)
+ {
+ Id *p;
+ for (p = repo->idarraydata + *offp; *p; p++)
+ queue_push(q, *p);
+ }
+ return 1;
}
}
data = repo_lookup_repodata_opt(repo, entry, keyname);
return 0;
}
+unsigned int
+repo_lookup_count(Repo *repo, Id entry, Id keyname)
+{
+ Repodata *data;
+ if (keyname >= SOLVABLE_NAME && keyname <= RPM_RPMDBID)
+ if (entry >= 0 && keyname >= SOLVABLE_NAME && keyname <= RPM_RPMDBID)
+ {
+ Id *p;
+ Offset *offp;
+ unsigned int cnt;
+ switch (keyname)
+ {
+ case SOLVABLE_PROVIDES:
+ case SOLVABLE_OBSOLETES:
+ case SOLVABLE_CONFLICTS:
+ case SOLVABLE_REQUIRES:
+ case SOLVABLE_RECOMMENDS:
+ case SOLVABLE_SUGGESTS:
+ case SOLVABLE_SUPPLEMENTS:
+ case SOLVABLE_ENHANCES:
+ offp = solvable_offsetptr(repo->pool->solvables + entry, keyname);
+ for (cnt = 0, p = repo->idarraydata + *offp; *p; p++)
+ cnt++;
+ return cnt;
+ }
+ return 1;
+ }
+ data = repo_lookup_repodata_opt(repo, entry, keyname);
+ return data ? repodata_lookup_count(data, entry, keyname) : 0;
+}
+
/***********************************************************************/
Repodata *
marker = solv_depmarker(keyname, marker);
if (p >= 0)
{
- Solvable *s = repo->pool->solvables + p;
+ Offset *offp;
switch (keyname)
{
case SOLVABLE_PROVIDES:
- s->provides = repo_addid_dep(repo, s->provides, dep, marker);
- return;
case SOLVABLE_OBSOLETES:
- s->obsoletes = repo_addid_dep(repo, s->obsoletes, dep, marker);
- return;
case SOLVABLE_CONFLICTS:
- s->conflicts = repo_addid_dep(repo, s->conflicts, dep, marker);
- return;
case SOLVABLE_REQUIRES:
- s->requires = repo_addid_dep(repo, s->requires, dep, marker);
- return;
case SOLVABLE_RECOMMENDS:
- s->recommends = repo_addid_dep(repo, s->recommends, dep, marker);
- return;
case SOLVABLE_SUGGESTS:
- s->suggests = repo_addid_dep(repo, s->suggests, dep, marker);
- return;
case SOLVABLE_SUPPLEMENTS:
- s->supplements = repo_addid_dep(repo, s->supplements, dep, marker);
- return;
case SOLVABLE_ENHANCES:
- s->enhances = repo_addid_dep(repo, s->enhances, dep, marker);
+ offp = solvable_offsetptr(repo->pool->solvables + p, keyname);
+ *offp = repo_addid_dep(repo, *offp, dep, marker);
return;
}
}
repo_add_deparray(repo, p, keyname, id, 0);
}
-static Offset
-repo_set_idarray_solvable(Repo *repo, Queue *q)
-{
- Offset o = 0;
- int i;
- for (i = 0; i < q->count; i++)
- repo_addid_dep(repo, o, q->elements[i], 0);
- return o;
-}
-
void
repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker)
{
}
if (p >= 0)
{
- Solvable *s = repo->pool->solvables + p;
+ Offset off, *offp;
+ int i;
switch (keyname)
{
case SOLVABLE_PROVIDES:
- s->provides = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_OBSOLETES:
- s->obsoletes = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_CONFLICTS:
- s->conflicts = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_REQUIRES:
- s->requires = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_RECOMMENDS:
- s->recommends = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_SUGGESTS:
- s->suggests = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_SUPPLEMENTS:
- s->supplements = repo_set_idarray_solvable(repo, q);
- return;
case SOLVABLE_ENHANCES:
- s->enhances = repo_set_idarray_solvable(repo, q);
+ off = 0;
+ for (i = 0; i < q->count; i++)
+ off = repo_addid_dep(repo, off, q->elements[i], 0);
+ offp = solvable_offsetptr(repo->pool->solvables + p, keyname);
+ *offp = off;
return;
}
}
const char *repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
const unsigned char *repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
const void *repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp);
+unsigned int repo_lookup_count(Repo *repo, Id entry, Id keyname); /* internal */
Id solv_depmarker(Id keyname, Id marker);
void repo_set_id(Repo *repo, Id p, Id keyname, Id id);
return dp;
}
+unsigned int
+repodata_lookup_count(Repodata *data, Id solvid, Id keyname)
+{
+ unsigned char *dp;
+ Repokey *key;
+ unsigned int cnt = 0;
+
+ dp = find_key_data(data, solvid, keyname, &key);
+ if (!dp)
+ return 0;
+ switch (key->type)
+ {
+ case REPOKEY_TYPE_IDARRAY:
+ case REPOKEY_TYPE_REL_IDARRAY:
+ for (cnt = 1; (*dp & 0xc0) != 0; dp++)
+ if ((*dp & 0xc0) == 0x40)
+ cnt++;
+ return cnt;
+ case REPOKEY_TYPE_FIXARRAY:
+ case REPOKEY_TYPE_FLEXARRAY:
+ data_read_id(dp, (int *)&cnt);
+ return cnt;
+ case REPOKEY_TYPE_DIRSTRARRAY:
+ for (;;)
+ {
+ cnt++;
+ while (*dp & 0x80)
+ dp++;
+ if (!(*dp++ & 0x40))
+ return cnt;
+ dp += strlen((const char *)dp) + 1;
+ }
+ case REPOKEY_TYPE_DIRNUMNUMARRAY:
+ for (;;)
+ {
+ cnt++;
+ while (*dp++ & 0x80)
+ ;
+ while (*dp++ & 0x80)
+ ;
+ while (*dp & 0x80)
+ dp++;
+ if (!(*dp++ & 0x40))
+ return cnt;
+ }
+ default:
+ break;
+ }
+ return 1;
+}
+
/* highly specialized function to speed up fileprovides adding.
* - repodata must be available
* - solvid must be >= data->start and < data->end
const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep);
int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp);
+unsigned int repodata_lookup_count(Repodata *data, Id solvid, Id keyname); /* internal */
/* internal, used in fileprovides code */
const unsigned char *repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname);
}
else
{
- Id *qele;
+ Id *qele, d;
int qcnt;
qele = bq.elements + i;
break;
if (j < qcnt)
continue;
- addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep);
+ d = pool_ids2whatprovides(pool, qele + 1, qcnt - 1);
+ if (solv->ruleinfoq && qele[0] != p)
+ {
+ int oldcount = solv->ruleinfoq->count;
+ addpkgrule(solv, qele[0], 0, d, type, dep);
+ /* fixup from element of ruleinfo */
+ if (solv->ruleinfoq->count > oldcount)
+ solv->ruleinfoq->elements[oldcount + 1] = p;
+ }
+ else
+ addpkgrule(solv, qele[0], 0, d, type, dep);
if (m)
for (j = 0; j < qcnt; j++)
if (qele[j] > 0 && !MAPTST(m, qele[j]))
if (*odp)
return;
}
- if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS)
+ /* set p2 for multiversion conflicts */
+ if (p < 0 && pool->whatprovidesdata[d] < 0 && pool->whatprovidesdata[d + 1] >= 0 && type == SOLVER_RULE_PKG_CONFLICTS)
p2 = pool->whatprovidesdata[d];
}
else
return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
}
+unsigned int
+solvable_lookup_count(Solvable *s, Id keyname)
+{
+ return s->repo ? repo_lookup_count(s->repo, s - s->repo->pool->solvables, keyname) : 0;
+}
+
static inline const char *
evrid2vrstr(Pool *pool, Id evrid)
{
const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep);
int solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q);
int solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker);
+unsigned int solvable_lookup_count(Solvable *s, Id keyname); /* internal */
/* setter functions */
void solvable_set_id(Solvable *s, Id keyname, Id id);
--- /dev/null
+#ifdef _WIN32
+ #ifdef SOLV_STATIC_LIB
+ #define SOLV_API
+ #else
+ #ifdef SOLV_EXPORTS
+ #define SOLV_API __declspec(dllexport)
+ #else
+ #define SOLV_API __declspec(dllimport)
+ #endif
+ #endif
+#else
+ #define SOLV_API
+#endif
\ No newline at end of file
#include <stdlib.h>
#include <stdio.h>
-char *optarg;
-int optind=1, opterr=1, optopt, __optpos, __optreset=0;
+#include "config.h"
+
+SOLV_API char *optarg;
+SOLV_API int optind=1, opterr=1, optopt, __optpos, __optreset=0;
#define optpos __optpos
extern "C" {
#endif
+#include "config.h"
+
int getopt(int, char * const [], const char *);
-extern char *optarg;
-extern int optind, opterr, optopt, optreset;
+
+SOLV_API extern char *optarg;
+SOLV_API extern int optind, opterr, optopt, optreset;
struct option {
const char *name;