diff --git a/Makefile.am b/Makefile.am index 1f6e60e..24be859 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,7 +55,8 @@ EXTRA_DIST = \ tests/lib1/isystem.pc \ tests/lib1/depgraph-break.pc \ tests/lib1/cflags-whitespace.pc \ - tests/lib1/provides.pc + tests/lib1/provides.pc \ + tests/lib1/provides-request-simple.pc pkginclude_HEADERS = libpkgconf/bsdstubs.h libpkgconf/iter.h libpkgconf/libpkgconf.h libpkgconf/stdinc.h libpkgconf_la_SOURCES = \ diff --git a/libpkgconf/libpkgconf.h b/libpkgconf/libpkgconf.h index 3d11b60..530eb43 100644 --- a/libpkgconf/libpkgconf.h +++ b/libpkgconf/libpkgconf.h @@ -119,6 +119,7 @@ struct pkgconf_pkg_ { #define PKGCONF_PKG_PKGF_MUNGE_SYSROOT_PREFIX 0x080 #define PKGCONF_PKG_PKGF_SKIP_ERRORS 0x100 #define PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE 0x200 +#define PKGCONF_PKG_PKGF_SKIP_PROVIDES 0x400 #define PKGCONF_PKG_ERRF_OK 0x0 #define PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND 0x1 diff --git a/libpkgconf/pkg.c b/libpkgconf/pkg.c index 6ec65ee..866c84a 100644 --- a/libpkgconf/pkg.c +++ b/libpkgconf/pkg.c @@ -876,6 +876,65 @@ pkgconf_pkg_comparator_lookup_by_name(const char *name) return (p != NULL) ? p->compare : PKGCONF_CMP_ANY; } +typedef struct { + pkgconf_dependency_t *pkgdep; + unsigned int flags; +} pkgconf_pkg_scan_providers_ctx_t; + +/* + * pkgconf_pkg_scan_provides_entry(pkg, ctx) + * + * attempt to match a single package's Provides rules against the requested dependency node. + * + * XXX: implement support for version comparisons using backwards dependency version checks, + * right now, we only support Provides rules that are PKGCONF_CMP_ANY as this is still + * proof-of-concept. + */ +static bool +pkgconf_pkg_scan_provides_entry(const pkgconf_pkg_t *pkg, const pkgconf_pkg_scan_providers_ctx_t *ctx) +{ + const pkgconf_dependency_t *pkgdep = ctx->pkgdep; + pkgconf_node_t *node; + + switch (pkgdep->compare) + { + case PKGCONF_CMP_ANY: + PKGCONF_FOREACH_LIST_ENTRY(pkg->provides.head, node) + { + const pkgconf_dependency_t *provider = node->data; + if (!strcmp(provider->package, pkgdep->package)) + return true; + } + break; + } + + return false; +} + +/* + * pkgconf_pkg_scan_providers(pkgdep, flags, eflags) + * + * scan all available packages to see if a Provides rule matches the pkgdep. + */ +static pkgconf_pkg_t * +pkgconf_pkg_scan_providers(pkgconf_dependency_t *pkgdep, unsigned int flags, unsigned int *eflags) +{ + pkgconf_pkg_t *pkg; + pkgconf_pkg_scan_providers_ctx_t ctx = { + .pkgdep = pkgdep, + .flags = flags + }; + + pkg = pkgconf_scan_all(&ctx, (pkgconf_pkg_iteration_func_t) pkgconf_pkg_scan_provides_entry); + if (pkg != NULL) + return pkg; + + if (eflags != NULL) + *eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND; + + return NULL; +} + /* * pkg_verify_dependency(pkgdep, flags) * @@ -893,10 +952,15 @@ pkgconf_pkg_verify_dependency(pkgconf_dependency_t *pkgdep, unsigned int flags, pkg = pkgconf_pkg_find(pkgdep->package, flags); if (pkg == NULL) { - if (eflags != NULL) - *eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND; + if (flags & PKGCONF_PKG_PKGF_SKIP_PROVIDES) + { + if (eflags != NULL) + *eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND; - return NULL; + return NULL; + } + + return pkgconf_pkg_scan_providers(pkgdep, flags, eflags); } if (pkg->id == NULL) diff --git a/tests/lib1/provides-request-simple.pc b/tests/lib1/provides-request-simple.pc new file mode 100644 index 0000000..7e12c2d --- /dev/null +++ b/tests/lib1/provides-request-simple.pc @@ -0,0 +1,6 @@ +Name: provides-request-simple +Description: A testing pkg-config file +Version: 1.2.3 +Libs: -lfoo +Cflags: -I/usr/include/foo +Requires: provides-test-foo diff --git a/tests/run.sh.in b/tests/run.sh.in index e2b320b..7d3c884 100644 --- a/tests/run.sh.in +++ b/tests/run.sh.in @@ -286,16 +286,19 @@ run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} --cflags prefix-foo1 prefix-foo run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} --variable=typelibdir --define-variable='libdir=\${libdir}' typelibdir" \ "\${libdir}/typelibdir" -run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} --print-provides provides" \ - "provides = 1.2.3" "provides-test-foo = 1.0.0" "provides-test-baz >= 1.1.0" "provides-test-moo <= 1.2.0" - run_test "PKG_CONFIG_PATH='${selfdir}/lib1' PKG_CONFIG_SYSROOT_DIR='/test' ${1} --cflags isystem" \ "-isystem /test/opt/bad/include" run_test "PKG_CONFIG_PATH='${selfdir}/lib1' PKG_CONFIG_SYSROOT_DIR='/test' ${1} --cflags cflags-whitespace" \ "-I /test/opt/bad/include" -# 10) tests for internal getopt implementation with options at the end +# 10) tests for Provides system +run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} --print-provides provides" \ + "provides = 1.2.3" "provides-test-foo = 1.0.0" "provides-test-baz >= 1.1.0" "provides-test-moo <= 1.2.0" +run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} --libs provides-request-simple" \ + "-lfoo" + +# 11) tests for internal getopt implementation with options at the end if [ "x@STRICT_MODE@" = "xno" ]; then run_test "PKG_CONFIG_PATH='${selfdir}/lib1' ${1} foo --libs" \ '-lfoo'