Compare commits

..

No commits in common. "master" and "pkgconf-2.1.0" have entirely different histories.

270 changed files with 3875 additions and 10438 deletions

4
.github/FUNDING.yml vendored
View File

@ -1 +1,3 @@
open_collective: pkgconf
github: kaniini
patreon: kaniini
liberapay: kaniini

View File

@ -1,135 +0,0 @@
name: Generate and upload release artifacts
on:
push:
tags:
- 'pkgconf-*'
jobs:
tarball:
runs-on: ubuntu-latest
container:
image: alpine:latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
repository: pkgconf/pkgconf
- name: Update system and add dependencies
run: |
apk update
apk add kyua atf build-base autoconf automake libtool xz gzip tar openssh-client
- name: Bootstrap autotools
run: |
sh autogen.sh
./configure
- name: Run tests and generate dist tarballs
run: |
make distcheck -j$(nproc)
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: tarball
path: pkgconf-*.tar.*
msi:
name: Build MSI
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include: [
{ msystem: MINGW64, arch: x86_64},
]
steps:
- uses: actions/checkout@v4
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
mingw-w64-${{ matrix.arch }}-meson
mingw-w64-${{ matrix.arch }}-ninja
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-msitools
- name: Build
shell: msys2 {0}
run: |
# the code assumes msvc style printf atm
export CFLAGS=-D__USE_MINGW_ANSI_STDIO=0
meson _build --buildtype=release -Dtests=disabled -Db_lto=true
meson compile -C _build msi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: msi
path: _build/pkgconf-*.msi
release:
name: Create Release
runs-on: ubuntu-latest
permissions:
contents: write
needs: [tarball, msi]
steps:
- name: Download tarball artifact
uses: actions/download-artifact@v4
with:
name: tarball
path: dist
- name: Download msi artifact
uses: actions/download-artifact@v4
with:
name: msi
path: dist
- name: Create Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
dist/pkgconf-*.tar.*
dist/pkgconf-*.msi
publish:
name: Publish on distfiles.ariadne.space
runs-on: ubuntu-latest
permissions:
contents: write
needs: [tarball, msi]
steps:
- name: Download tarball artifact
uses: actions/download-artifact@v4
with:
name: tarball
path: dist
- name: Download msi artifact
uses: actions/download-artifact@v4
with:
name: msi
path: dist
- name: Upload dist tarballs to distfiles.ariadne.space
env:
DISTFILES_PRIVATE_KEY: ${{ secrets.DISTFILES_PRIVATE_KEY }}
DISTFILES_HOST_KEYS: ${{ secrets.DISTFILES_HOST_KEYS }}
run: |
mkdir -p $HOME/.ssh
# Ensure the private key is read-only so SSH doesn't reject it.
umask 277
(echo "$DISTFILES_PRIVATE_KEY" | base64 -d) > $HOME/.ssh/id_ed25519
umask 077
(echo "$DISTFILES_HOST_KEYS" | base64 -d) > $HOME/.ssh/known_hosts
# Upload the tarballs.
scp -i "$HOME/.ssh/id_ed25519" -o "UserKnownHostsFile=$HOME/.ssh/known_hosts" dist/* kaniini@distfiles.ariadne.space:distfiles/pkgconf/
# Delete the key material.
rm -rf $HOME/.ssh

View File

@ -13,6 +13,7 @@ jobs:
matrix:
include: [
{ msystem: MINGW64, arch: x86_64},
{ msystem: MINGW32, arch: i686}
]
steps:
- name: Checkout code
@ -27,7 +28,6 @@ jobs:
mingw-w64-${{ matrix.arch }}-meson
mingw-w64-${{ matrix.arch }}-ninja
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-msitools
- name: Build
shell: msys2 {0}
@ -35,22 +35,8 @@ jobs:
# the code assumes msvc style printf atm
export CFLAGS=-D__USE_MINGW_ANSI_STDIO=0
meson _build
meson compile -C _build msi
- name: Run tests
shell: msys2 {0}
run: |
meson test -v -C _build
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: build-output
path: |
_build/*.exe
_build/*.dll
_build/*.msi
meson -Dtests=disabled _build
meson compile -C _build
debian-meson:
runs-on: ubuntu-latest
@ -154,7 +140,7 @@ jobs:
- name: Update system and add dependencies
run: |
apk update
apk add kyua atf build-base autoconf automake libtool xz gzip tar
apk add kyua atf build-base autoconf automake libtool xz gzip
- name: Build
run: |
@ -165,23 +151,3 @@ jobs:
- name: Run tests
run: |
make distcheck
analysis:
runs-on: ubuntu-latest
container:
image: alpine
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apk update
apk add kyua atf build-base autoconf automake libtool xz gzip
- name: Build
run: |
export CFLAGS="-Wall -Werror -O2 -ggdb3 -fanalyzer"
./autogen.sh
./configure
make -j9 CFLAGS="$CFLAGS"

50
.gitignore vendored
View File

@ -1,19 +1,13 @@
Makefile
Makefile.in
.dirstamp
stamp-h*
*.h.in~
*.o
*.og
*.op
*.lo
*.gcno
*.gcda
*.gcov
core
.gdb_history
.libs
.deps
*.exe
@ -22,8 +16,8 @@ core
*.orig
*.patch
*.rej
/tests/run.sh
# autoconf stuff
/aclocal.m4
/autom4te.cache/
/buildsys.mk
@ -32,48 +26,8 @@ core
/config.log
/config.status
/configure
/compile
/config.guess
/config.sub
/depcomp
/install-sh
/missing
# programs
/bomtool
/pkgconf
/pkgconf-gcov
/pkgconf-profile
# libtool
/libtool
/ltmain.sh
/libpkgconf.la
/m4/libtool.m4
/m4/lt~obsolete.m4
/m4/ltoptions.m4
/m4/ltsugar.m4
/m4/ltversion.m4
# pkgconfig file
/libpkgconf.pc
# autoheader
/libpkgconf/config.h
/libpkgconf/config.h.in
# tests
/Kyuafile
/tests/Kyuafile
/tests/basic
/tests/builtins
/tests/conflicts
/tests/framework
/tests/parser
/tests/provides
/tests/regress
/tests/requires
/tests/symlink
/tests/sysroot
/tests/test_env.sh
/tests/version
Makefile

75
.woodpecker.yml Normal file
View File

@ -0,0 +1,75 @@
pipeline:
debian-meson:
image: debian:testing
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential meson
- meson _build -Dwerror=true
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: debian
BUILD: meson
debian-meson-asan:
image: debian:testing
environment:
- ASAN_OPTIONS="exitcode=7"
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential meson
- meson _build -Db_sanitize=address
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: debian
BUILD: meson
debian-autotools:
image: debian:testing
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential autoconf libtool
- ./autogen.sh
- ./configure
- make -j
- make distcheck
when:
matrix:
IMAGE: debian
BUILD: autotools
alpine-meson:
image: alpine
commands:
- apk add -U --no-cache kyua atf build-base meson
- meson _build -Dwerror=true
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: alpine
BUILD: meson
alpine-autotools:
image: alpine
commands:
- apk add -U --no-cache kyua atf build-base autoconf automake libtool xz gzip
- ./autogen.sh
- ./configure
- make -j
- make distcheck
when:
matrix:
IMAGE: alpine
BUILD: autotools
matrix:
IMAGE:
- debian
- alpine
BUILD:
- meson
- autotools

View File

@ -9,190 +9,17 @@ personality_dir = @PERSONALITY_PATH@
pkgconfigdir = $(libdir)/pkgconfig
nodist_pkgconfig_DATA = libpkgconf.pc
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\"
bin_PROGRAMS = pkgconf bomtool spdxtool
bin_PROGRAMS = pkgconf bomtool
lib_LTLIBRARIES = libpkgconf.la
EXTRA_DIST = pkg.m4 \
meson.build \
meson_options.txt \
pkgconf.wxs.in \
txt2rtf.py \
libpkgconf/meson.build \
libpkgconf/config.h.meson \
libpkgconf/win-dirent.h \
t/basic/arbitrary-path.test \
t/basic/builtin-pkg-config-exists.test \
t/basic/builtin-pkg-config-pc_path-variable.test \
t/basic/builtin-pkgconf-exists.test \
t/basic/builtin-pkgconf-pc_path-variable.test \
t/basic/define-prefix.test \
t/basic/define-prefix-child-prefix-env.test \
t/basic/define-prefix-child-prefix.test \
t/basic/direct-query-with-pkg_config_path.test \
t/basic/env-tuple.test \
t/basic/exists-cflags-env.test \
t/basic/exists-cflags.test \
t/basic/exists-nonexistent.test \
t/basic/exists-version-greater-than-with-tilde.test \
t/basic/exists-version-greater-than.test \
t/basic/exists-version-less-than-with-tilde.test \
t/basic/exists-version-malformed.test \
t/basic/exists-version-minimum.test \
t/basic/exists-version-with-tilde.test \
t/basic/incomplete-cflags.test \
t/basic/incomplete-libs.test \
t/basic/keep-system-libs.test \
t/basic/keep-system-libs-2.test \
t/basic/libs.test \
t/basic/libs-cflags.test \
t/basic/libs-cflags-version.test \
t/basic/libs-cflags-version-multiple.test \
t/basic/libs-cflags-version-multiple-comma.test \
t/basic/libs-cflags-version-not.test \
t/basic/libs-cflags-version-not-provided.test \
t/basic/libs-env.test \
t/basic/libs-only.test \
t/basic/malformed-empty-package.test \
t/basic/modversion-fullpath.test \
t/basic/modversion-noflatten.test \
t/basic/modversion-uninstalled.test \
t/basic/modversion-verbose-prefix.test \
t/basic/noargs.test \
t/basic/nocflags.test \
t/basic/nolibs.test \
t/basic/pkg-config-path.test \
t/basic/print-variables-env.test \
t/basic/single-depth-selectors.test \
t/basic/static-archive-libs.test \
t/basic/uninstalled-not.test \
t/basic/uninstalled.test \
t/basic/variable-env.test \
t/basic/variable-no-recursion.test \
t/basic/variable.test \
t/basic/version-atleast-1.test \
t/basic/version-atleast-2.test \
t/basic/version-exact-1.test \
t/basic/version-exact-2.test \
t/basic/version-max-1.test \
t/basic/version-max-2.test \
t/ordering/cflags-never-mergeback.test \
t/ordering/cflags-only.test \
t/ordering/flag-order-1.test \
t/ordering/flag-order-2.test \
t/ordering/flag-order-3.test \
t/ordering/flag-order-4.test \
t/ordering/fragment-collision.test \
t/ordering/framework-1.test \
t/ordering/framework-2.test \
t/ordering/framework-3.test \
t/ordering/idirafter-munge-ordering.test \
t/ordering/idirafter-ordering.test \
t/ordering/isystem-munge-ordering.test \
t/ordering/libs-never-mergeback.test \
t/parser/argv-parse-1.test \
t/parser/argv-parse-2.test \
t/parser/argv-parse-3.test \
t/parser/c-comments-should-warn.test \
t/parser/comments-in-fields.test \
t/parser/comments.test \
t/parser/dos-lineendings.test \
t/parser/escaped-backslashes-in-output.test \
t/parser/fragment-comment.test \
t/parser/fragment-groups-composite.test \
t/parser/fragment-groups.test \
t/parser/malformed-no-newlines.test \
t/parser/malformed-quoting.test \
t/parser/multiline-bogus-header.test \
t/parser/multiline-field.test \
t/parser/no-trailing-newline.test \
t/parser/paren-quoting.test \
t/parser/shell-quoted-output.test \
t/parser/tilde-quoting-1.test \
t/parser/tilde-quoting-2.test \
t/parser/truncated-files-should-fail-to-parse.test \
t/parser/tuple-dequote.test \
t/parser/variable-whitespace.test \
t/solver/circular-reference-1.test \
t/solver/circular-reference-2.test \
t/solver/circular-reference-directpc.test \
t/solver/conflicts-solution-error.test \
t/solver/conflicts-solution-ignore.test \
t/solver/conflicts-solution-is-fine-standalone.test \
t/solver/depgraph-break-1.test \
t/solver/depgraph-break-2.test \
t/solver/depgraph-break-3.test \
t/solver/libs-intermediary.test \
t/solver/libs-metapackage.test \
t/solver/libs-static-ordering.test \
t/solver/missing-required-dep.test \
t/solver/modversion-provides.test \
t/solver/private-libs-duplication-digraph.test \
t/solver/private-libs-duplication.test \
t/solver/provides-bar-any.test \
t/solver/provides-bar-versioned-equal.test \
t/solver/provides-bar-versioned-greater-than-equal.test \
t/solver/provides-bar-versioned-greater-than.test \
t/solver/provides-bar-versioned-less-than-equal.test \
t/solver/provides-bar-versioned-less-than-new.test \
t/solver/provides-bar-versioned-less-than-old.test \
t/solver/provides-bar-versioned-not-equal-old.test \
t/solver/provides-bar-versioned-not-equal.test \
t/solver/provides-foo-any.test \
t/solver/provides-foo-versioned-exact.test \
t/solver/provides-foo-versioned-greater-than-equal.test \
t/solver/provides-foo-versioned-greater-than.test \
t/solver/provides-foo-versioned-less-than-equal.test \
t/solver/provides-foo-versioned-less-than.test \
t/solver/provides-foo-versioned-not-equal.test \
t/solver/provides-indirect-dependency-versioned.test \
t/solver/provides-indirect-dependency.test \
t/solver/provides-print-simple.test \
t/solver/provides-request-simple.test \
t/solver/provides-request-simple-no-provides.test \
t/solver/query-no-space-0.test \
t/solver/query-no-space-1.test \
t/solver/query-order-1.test \
t/solver/query-order-2.test \
t/solver/requires-internal-collision.test \
t/solver/requires-internal-missing-nonstatic-cflags-libs.test \
t/solver/requires-internal-missing-nonstatic.test \
t/solver/requires-internal-missing-static-cflags.test \
t/solver/requires-internal-missing.test \
t/solver/requires-internal.test \
t/solver/requires-private-debounce.test \
t/solver/requires-private-missing.test \
t/sbom/license-file-bar.test \
t/sbom/license-file-foo.test \
t/sbom/license-isc.test \
t/sbom/license-noassertion.test \
t/sbom/source-tag-bar.test \
t/sbom/source-tag-foo.test \
t/sysroot/cflags-rewriting.test \
t/sysroot/idirafter-munge-sysroot.test \
t/sysroot/isystem-munge-sysroot.test \
t/sysroot/no-pc_sysrootdir-rewriting-2.test \
t/sysroot/no-pc_sysrootdir-rewriting-3.test \
t/sysroot/no-pc_sysrootdir-rewriting-4.test \
t/sysroot/no-pc_sysrootdir-rewriting-5.test \
t/sysroot/no-pc_sysrootdir-rewriting-variable.test \
t/sysroot/skip-rewriting-when-sysroot-dir-is-root-dir.test \
t/sysroot/undefined-pc_sysrootdir-should-be-empty.test \
t/sysroot/uninstalled-rewriting-fdo-rules-with-pc_sysrootdir.test \
t/sysroot/uninstalled-rewriting-fdo-rules.test \
t/sysroot/uninstalled-rewriting-pkgconf-1-rules.test \
t/sysroot/uninstalled-rewriting.test \
t/sysroot/variable-rewriting-1.test \
t/sysroot/variable-rewriting-2.test \
t/tuple/billion-laughs.test \
t/tuple/case-sensitivity-1.test \
t/tuple/case-sensitivity-2.test \
t/tuple/define-variable-override.test \
t/tuple/define-variable.test \
t/tuple/duplicate-upsert.test \
t/tuple/empty-tuple.test \
tests/lib-relocatable/lib/pkgconfig/foo.pc \
tests/lib1/argv-parse-2.pc \
tests/lib1/billion-laughs.pc \
@ -262,11 +89,6 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/fragment-quoting-3.pc \
tests/lib1/fragment-quoting-5.pc \
tests/lib1/fragment-quoting-7.pc \
tests/lib1/fragment-groups.pc \
tests/lib1/fragment-groups-2.pc \
tests/lib1/fragment-group-a.pc \
tests/lib1/fragment-group-b.pc \
tests/lib1/fragment-group-c.pc \
tests/lib1/malformed-1.pc \
tests/lib1/malformed-quoting.pc \
tests/lib1/malformed-version.pc \
@ -284,32 +106,10 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/tuple-quoting.pc \
tests/lib1/empty-tuple.pc \
tests/lib1/orphaned-requires-private.pc \
tests/lib1/pcfiledir.pc \
tests/lib1/sysroot-dir-2.pc \
tests/lib1/sysroot-dir-3.pc \
tests/lib1/sysroot-dir-4.pc \
tests/lib1/sysroot-dir-5.pc \
tests/lib1/child-prefix/pkgconfig/child-prefix-1.pc \
tests/lib1/cflags-libs-private-a.pc \
tests/lib1/cflags-libs-private-b.pc \
tests/lib1/cflags-libs-private-c.pc \
tests/lib1/truncated.pc \
tests/lib1/c-comment.pc \
tests/lib1/duplicate-tuple.pc \
tests/lib1/flag-whitespace.pc \
tests/lib1/flag-whitespace-2.pc \
tests/lib-sbom/meta_package.pc \
tests/lib-sbom/test1.pc \
tests/lib-sbom/test2.pc \
tests/lib-sbom/test3.pc \
tests/lib-sbom/test4.pc \
tests/lib-sbom/test5.pc \
tests/lib-sbom/test6.pc \
tests/lib-sbom-files/basic.json \
tests/lib-sbom-files/meta_package.json \
tests/lib-sbom-files/with_dependency.json \
tests/personality-data/i386-linux-gnu.personality \
tests/meson.build \
$(test_scripts) \
doc/conf.py \
doc/extract.py \
@ -326,23 +126,26 @@ EXTRA_DIST = pkg.m4 \
doc/libpkgconf-queue.rst \
doc/libpkgconf-tuple.rst
test_scripts= \
test_scripts= tests/meson.build \
tests/basic.sh \
tests/builtins.sh \
tests/conflicts.sh \
tests/framework.sh \
tests/parser.sh \
tests/personality.sh \
tests/provides.sh \
tests/regress.sh \
tests/requires.sh \
tests/spdxtool.sh \
tests/symlink.sh
tests/sysroot.sh \
tests/version.sh
test_sh = $(test_scripts)
check_SCRIPTS = ${test_sh:.sh=}
test_sh = $(filter-out tests/meson.build, $(test_scripts))
check_SCRIPTS = $(test_sh:.sh=)
SUFFIXES= .sh
nobase_pkginclude_HEADERS = libpkgconf/bsdstubs.h libpkgconf/iter.h libpkgconf/libpkgconf.h libpkgconf/stdinc.h libpkgconf/libpkgconf-api.h
libpkgconf_la_SOURCES = \
libpkgconf/audit.c \
libpkgconf/buffer.c \
libpkgconf/cache.c \
libpkgconf/client.c \
libpkgconf/pkg.c \
@ -353,14 +156,12 @@ libpkgconf_la_SOURCES = \
libpkgconf/tuple.c \
libpkgconf/dependency.c \
libpkgconf/queue.c \
libpkgconf/output.c \
libpkgconf/path.c \
libpkgconf/personality.c \
libpkgconf/parser.c
libpkgconf_la_LDFLAGS = -no-undefined -version-info 7:0:0 -export-symbols-regex '^pkgconf_'
libpkgconf_la_LDFLAGS = -no-undefined -version-info 4:0:0 -export-symbols-regex '^pkgconf_'
dist_man_MANS = \
man/bomtool.1 \
man/pkgconf.1 \
man/pkg.m4.7 \
man/pc.5 \
@ -369,19 +170,12 @@ dist_man_MANS = \
pkgconf_LDADD = libpkgconf.la
pkgconf_SOURCES = \
cli/main.c \
cli/core.c \
cli/getopt_long.c \
cli/renderer-msvc.c
pkgconf_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli
noinst_HEADERS = \
cli/core.h \
cli/getopt_long.h \
cli/renderer-msvc.h \
cli/spdxtool/core.h \
cli/spdxtool/serialize.h \
cli/spdxtool/simplelicensing.h \
cli/spdxtool/software.h \
cli/spdxtool/util.h
cli/getopt_long.h \
cli/renderer-msvc.h
bomtool_LDADD = libpkgconf.la
bomtool_SOURCES = \
@ -389,25 +183,6 @@ bomtool_SOURCES = \
cli/getopt_long.c
bomtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/bomtool
spdxtool_LDADD = libpkgconf.la
spdxtool_SOURCES = \
cli/spdxtool/main.c \
cli/spdxtool/core.c \
cli/spdxtool/software.c \
cli/spdxtool/serialize.c \
cli/spdxtool/simplelicensing.c \
cli/spdxtool/util.c \
cli/getopt_long.c
spdxtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/spdxtool
noinst_PROGRAMS = test-runner
test_runner_LDADD = libpkgconf.la
test_runner_SOURCES = \
cli/core.c \
cli/getopt_long.c \
cli/renderer-msvc.c \
tests/test-runner.c
dist_doc_DATA = README.md AUTHORS
m4datadir = $(datadir)/aclocal
@ -416,14 +191,7 @@ m4data_DATA = pkg.m4
CLEANFILES = $(EXTRA_PROGRAMS) \
$(check_SCRIPTS)
check: pkgconf test-runner $(check_SCRIPTS)
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/basic
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/ordering
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/parser
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/solver
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/sbom
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/sysroot
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests $(top_srcdir)/t/tuple
check: pkgconf $(check_SCRIPTS)
kyua --config=none test --kyuafile='$(top_builddir)/Kyuafile' \
--build-root='$(top_builddir)'

View File

@ -16,13 +16,11 @@ SRCS = \
libpkgconf/argvsplit.c \
libpkgconf/audit.c \
libpkgconf/bsdstubs.c \
libpkgconf/buffer.c \
libpkgconf/cache.c \
libpkgconf/client.c \
libpkgconf/dependency.c \
libpkgconf/fileio.c \
libpkgconf/fragment.c \
libpkgconf/output.c \
libpkgconf/parser.c \
libpkgconf/path.c \
libpkgconf/personality.c \
@ -30,8 +28,7 @@ SRCS = \
libpkgconf/queue.c \
libpkgconf/tuple.c \
cli/getopt_long.c \
cli/main.c \
cli/core.c
cli/main.c
OBJS = ${SRCS:.c=.o}
CFLAGS = ${STATIC} -DPKGCONF_LITE -I. -Ilibpkgconf -Icli -DSYSTEM_LIBDIR=\"${SYSTEM_LIBDIR}\" -DSYSTEM_INCLUDEDIR=\"${SYSTEM_INCLUDEDIR}\" -DPKG_DEFAULT_PATH=\"${PKG_DEFAULT_PATH}\"
STATIC =
@ -42,7 +39,7 @@ all: pkgconf-lite
libpkgconf/config.h:
@echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@
@echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@
@echo '#define PACKAGE_VERSION "2.5.1"' >> $@
@echo '#define PACKAGE_VERSION "2.1.0"' >> $@
@echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@
@echo '#define HAVE_STRLCPY' >> $@
@echo '#define HAVE_STRLCAT' >> $@

160
NEWS
View File

@ -1,164 +1,6 @@
Changes from previous version of pkgconf
========================================
Changes from 2.5.0 to 2.5.1:
----------------------------
* Fix processing of empty dependency lists.
Changes from 2.4.3 to 2.5.0:
----------------------------
* Added a manual page for bomtool.
* Add support for preloaded packages.
These are modules which are preloaded into the package database
and preferred over searching the module search path when present.
* Refactor Windows registry PKG_CONFIG_PATH support so that it
augments the main directory search list instead of being treated
as a special case.
* Processing of `--with-path` arguments by the pkgconf CLI is
now deferred until libpkgconf is fully initialized, effectively
aligning behavior with PKG_CONFIG_PATH processing.
* Fix several minor memory safety bugs which were identified by
the GCC 15 static analyzer.
* Added support for pledge(2) and unveil(2) on systems where
this functionality is available.
* Significant improvements to pkgconf's manual pages.
Patches by Ingo Schwarze and Jonathan Gray (OpenBSD).
* Remove questionable default-static assumption on Windows that
was inherited from the original pkg-config. Most distributions
of pkgconf on Windows were already patching this out.
Patch by Kai Pastor.
* Add -D_POSIX_C_SOURCE=200809L to the build definitions, which
is needed for readlinkat on glibc.
Patch by Filipe Laíns.
Changes from 2.4.2 to 2.4.3:
----------------------------
* Fix additional logic errors relating to the new fragment trees
functionality.
Changes from 2.4.1 to 2.4.2:
----------------------------
* Fix several logic errors in the pkg-config file parser that were
surfaced by recent refactoring work.
* Fix BSD make compatibility so that it generates the test data
before running kyua on BSD make implementations.
Changes from 2.4.0 to 2.4.1:
----------------------------
* Ensure the full DAG is solved for all query types.
Changes from 2.3.0 to 2.4.0:
----------------------------
* Allow multiple package names in solution-based queries such as
`--print-requires`, `--print-requires-private` and `--print-provides`.
* Use `_DEFAULT_SOURCE` where appropriate on Meson.
* Add an abstract buffer type and use it when loading files from disk
instead of a 64KB buffer. This ensures large pkg-config files are
not truncated.
* Disable graph recursion in `--variable` queries as it was generating
duplicate output.
* Add infrastructure for tracking fragment group relations and convert
storage of fragments to use a tree-like structure instead of string
concatenation.
* Add support for tracking linker groups, e.g.
-Wl,--start-group -la -lb -lc -Wl,--end-group
as fragment groups.
* Properly contextualize the sysroot directory when processing package
information, ensuring packages where ${pc_sysrootdir} does not match
the default are properly processed.
Changes from 2.2.0 to 2.3.0:
----------------------------
* Fix compile with Meson on Solaris by defining __EXTENSIONS__.
* Add support for the PKG_CONFIG_RELOCATE_PATHS environmental variable.
When set, the program will act as if --define-prefix is always enabled.
* Color solution nodes that were part of the original query, and use
that coloring to skip over dependencies when generating DocumentNames
in bomtool.
* Enhance --env option to support variables with both --variable=varname
and --print-variables.
* Add --exists-cflags option which creates synthetic preprocessor
definition flags for every queried dependency when found.
* Document that Requires.private is always used for header paths.
Patch by Petr Písař.
* Fix minor documentation typos.
Patch by Pierce.
* Ensure string comparisons using <ctype.h> functions are done with
unsigned bytes to avoid undefined behavior.
Patch by Taylor R Campbell.
* Fix parsing edge-case bugs with dependency versions.
Patch by Kai Pastor.
* Change PKG_PROG_PKG_CONFIG autoconf macro to add a customizable
failure handler if pkg-config is not found.
Patch by Ismael Luceno.
Changes from 2.1.1 to 2.2.0:
----------------------------
* libpkgconf SOVERSION is now 5.
* Significant solver rework to flatten both requires and requires.private
dependencies in a single pass. Improves performance slightly and ensures
proper dependency order.
Patches by Kai Pastor.
* Improve `--digraph` output to reflect more of the solver's state in the
rendered dependency graph.
Patches by Kai Pastor.
* Do not reference the graph root by name when presenting error messages about
directly requested dependency nodes.
Patch by Kai Pastor.
Changes from 2.1.0 to 2.1.1:
----------------------------
* Documentation fixes from Sam James and Stefan Weil.
* Fix --modversion with constraints.
Patch by Kai Pastor.
* Reintroduce an optimization to the dependency graph walker which avoids
revisiting already visited nodes.
Patch by Yi Chou with some modifications.
* Add a regression test to check that the dependency flattener is working
as expected.
Patch by Kai Pastor.
Changes from 2.0.3 to 2.1.0:
----------------------------
@ -167,7 +9,7 @@ Changes from 2.0.3 to 2.1.0:
Patches by Kai Pastor.
* Fix warnings with GCC 14 -Walloc-size.
Patch by Sam James.
Patch by Sam Jones.
* Add --solution to the pkgconf CLI to dump the solver state.

103
README.md
View File

@ -1,75 +1,88 @@
# pkgconf [![test](https://github.com/pkgconf/pkgconf/actions/workflows/test.yml/badge.svg)](https://github.com/pkgconf/pkgconf/actions/workflows/test.yml)
`pkgconf` is a program which helps to configure compiler and linker flags for
development libraries. It is a superset of the functionality provided by
pkg-config from freedesktop.org, but does not provide bug-compatibility with
the original pkg-config.
development libraries. It is similar to pkg-config from freedesktop.org.
`libpkgconf` is a library which provides access to most of `pkgconf`'s functionality,
to allow other tooling such as compilers and IDEs to discover and use libraries
configured by pkgconf.
## release tarballs
## using `pkgconf` with autotools
Release tarballs are available on [distfiles.ariadne.space][distfiles].
Implementations of pkg-config, such as pkgconf, are typically used with the
PKG_CHECK_MODULES autoconf macro. As far as we know, pkgconf is
compatible with all known variations of this macro. pkgconf detects at
runtime whether or not it was started as 'pkg-config', and if so, attempts
to set program options such that its behaviour is similar.
[distfiles]: https://distfiles.ariadne.space/pkgconf/
In terms of the autoconf macro, it is possible to specify the PKG_CONFIG
environment variable, so that you can test pkgconf without overwriting your
pkg-config binary. Some other build systems may also respect the PKG_CONFIG
environment variable.
## build system setup
To set the environment variable on the bourne shell and clones (i.e. bash), you
can run:
If you would like to use the git sources directly, or a snapshot of the
sources from GitHub, you will need to regenerate the autotools build
system artifacts yourself, or use Meson instead. For example, on Alpine:
$ export PKG_CONFIG=/usr/bin/pkgconf
$ apk add autoconf automake libtool build-base
$ sh ./autogen.sh
## comparison of `pkgconf` and `pkg-config` dependency resolvers
## pkgconf-lite
pkgconf builds an acyclic directed dependency graph. This allows for the user
to more conservatively link their binaries -- which may be helpful in some
environments, such as when prelink(1) is being used. As a result of building
a directed dependency graph designed for the specific problem domain provided
by the user, more accurate dependencies can be determined.
If you only need the original pkg-config functionality, there is also pkgconf-lite,
which builds the `pkgconf` frontend and relevant portions of `libpkgconf` functionality
into a single binary:
Current release versions of pkg-config, on the other hand, build a database of all
known pkg-config files on the system before attempting to resolve dependencies, which
is a considerably slower and less efficient design. Efforts have been made recently
to improve this behaviour.
$ make -f Makefile.lite
## why `pkgconf` over original `pkg-config`?
pkgconf builds a flattened directed dependency graph, which allows for more insight
into relationships between dependencies, allowing for some link-time dependency
optimization, which allows for the user to more conservatively link their binaries,
which may be helpful in some environments, such as when prelink(1) is being used.
The solver is also optimized to handle large dependency graphs with hundreds of
thousands of edges, which can be seen in any project using the Abseil frameworks
for example.
In addition, pkgconf has full support for virtual packages, while the original
pkg-config does not, as well as fully supporting `Conflicts` at dependency
resolution time, which is more efficient than checking for `Conflicts` while
walking the dependency graph.
As of the 1.1 series, pkgconf also fully implements support for `Provides` rules,
while pkg-config does not. pkg-config only provides the `--print-provides` functionality
as a stub. There are other intentional implementation differences in pkgconf's dependency
resolver versus pkg-config's dependency resolver in terms of completeness and correctness,
such as, for example, how `Conflicts` rules are processed.
## linker flags optimization
pkgconf, when used effectively, can make optimizations to avoid overlinking binaries.
As previously mentioned, pkgconf makes optimizations to the linker flags in both the
case of static and shared linking in order to avoid overlinking binaries and also
simplifies the `CFLAGS` and `LIBS` output of the pkgconf tool for improved readability.
This functionality depends on the pkg-config module properly declaring its dependency
This functionality depends on the pkg-config module properly declaring it's dependency
tree instead of using `Libs` and `Cflags` fields to directly link against other modules
which have pkg-config metadata files installed.
The practice of using `Libs` and `Cflags` to describe unrelated dependencies is
not recommended in [Dan Nicholson's pkg-config tutorial][fd-tut] for this reason.
Doing so is discouraged by the [freedesktop tutorial][fd-tut] anyway.
[fd-tut]: http://people.freedesktop.org/~dbn/pkg-config-guide.html
## bug compatibility with original pkg-config
## compatibility with pkg-config
In general, we do not provide bug-level compatibility with pkg-config.
I really hate that I have to have this section, I like being a nice person, but we
unfortunately have to say this because otherwise we get passive-aggressive people who
try to argue with us about what pkg-config compatibility means.
We do not provide bug-level compatibility with pkg-config.
What that means is, if you feel that there is a legitimate regression versus pkg-config,
do let us know, but also make sure that the .pc files are valid and follow the rules of
the [pkg-config tutorial][fd-tut], as most likely fixing them to follow the specified
rules will solve the problem.
Additionally, **we do not consider pkgconf doing what you tell it to do, in cases for
which pkg-config fails to do so, to be a bug**.
If, for example, you use environment variables such as `PKG_CONFIG_SYSTEM_[INCLUDE|LIBRARY]_PATH`
and then find yourself surprised that `pkgconf` is stripping `-I` and `-L` flags relating
to those paths, it is not a `pkgconf` problem -- `pkgconf` is doing exactly what you told
it to do.
We will reject bugs like this, and if someone insists on fixing such a non-bug, this
constitutes a violation of our [Code of Conduct](CODE_OF_CONDUCT.md), which may be
addressed by banning from this repository.
## debug output
Please use only the stable interfaces to query pkg-config. Do not screen-scrape the
@ -101,16 +114,17 @@ flags like so:
## compiling `pkgconf` and `libpkgconf` with Meson (usually for Windows)
pkgconf is compiled using [Meson](https://mesonbuild.com) on Windows. In theory, you could also use
Meson to build on UNIX, but this is not recommended at this time as pkgconf is typically built
Meson to build on UNIX, but this is not recommended at this time as it pkgconf is typically built
much earlier than Meson.
$ meson setup build -Dtests=disabled
$ meson compile -C build
$ meson install -C build
There are a few defines such as `SYSTEM_LIBDIR`, `PKGCONFIGDIR` and `SYSTEM_INCLUDEDIR`.
However, on Windows, the default `PKGCONFIGDIR` value is usually overridden at runtime based
There are a few defines such as SYSTEM_LIBDIR, PKGCONFIGDIR and SYSTEM_INCLUDEDIR.
However, on Windows, the default PKGCONFIGDIR value is usually overridden at runtime based
on path relocation.
## pkg-config symlink
@ -121,6 +135,11 @@ to make this determination themselves.
$ ln -sf pkgconf /usr/bin/pkg-config
## release tarballs
Release tarballs are available at <https://distfiles.ariadne.space/pkgconf/>.
Please only use the tarballs from distfiles.ariadne.space.
## contacts
You can report bugs at <https://github.com/pkgconf/pkgconf/issues>.

View File

@ -80,8 +80,8 @@ parse_options "$@"
cd $TOP_DIR
run_or_die $LIBTOOLIZE --install
run_or_die $ACLOCAL
run_or_die $AUTOHEADER
run_or_die $AUTOCONF
run_or_die $LIBTOOLIZE --install
run_or_die $AUTOMAKE --add-missing

View File

@ -31,15 +31,7 @@ static pkgconf_client_t pkg_client;
static uint64_t want_flags;
static size_t maximum_package_count = 0;
static int maximum_traverse_depth = 2000;
static FILE *error_msgout = NULL;
static const char *
environ_lookup_handler(const pkgconf_client_t *client, const char *key)
{
(void) client;
return getenv(key);
}
FILE *error_msgout = NULL;
static bool
error_handler(const char *msg, const pkgconf_client_t *client, void *data)
@ -73,9 +65,6 @@ sbom_name(pkgconf_pkg_t *world)
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY)
continue;
if (!dep->match)
continue;
@ -144,9 +133,6 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
if (pkg->description != NULL)
printf("PackageSummary: <text>%s</text>\n", pkg->description);
if (pkg->source != NULL)
printf("PackageDownloadLocation: %s\n", pkg->source);
printf("\n\n");
}
@ -293,7 +279,7 @@ main(int argc, char *argv[])
}
}
pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler);
pkgconf_client_init(&pkg_client, error_handler, NULL, personality);
/* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags);

1371
cli/core.c

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +0,0 @@
/*
* core.h
* core, printer functions
*
* Copyright (c) 2011-2025 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef __CLI_CORE_H
#define __CLI_CORE_H
#define PKG_CFLAGS_ONLY_I (((uint64_t) 1) << 2)
#define PKG_CFLAGS_ONLY_OTHER (((uint64_t) 1) << 3)
#define PKG_CFLAGS (PKG_CFLAGS_ONLY_I|PKG_CFLAGS_ONLY_OTHER)
#define PKG_LIBS_ONLY_LDPATH (((uint64_t) 1) << 5)
#define PKG_LIBS_ONLY_LIBNAME (((uint64_t) 1) << 6)
#define PKG_LIBS_ONLY_OTHER (((uint64_t) 1) << 7)
#define PKG_LIBS (PKG_LIBS_ONLY_LDPATH|PKG_LIBS_ONLY_LIBNAME|PKG_LIBS_ONLY_OTHER)
#define PKG_MODVERSION (((uint64_t) 1) << 8)
#define PKG_REQUIRES (((uint64_t) 1) << 9)
#define PKG_REQUIRES_PRIVATE (((uint64_t) 1) << 10)
#define PKG_VARIABLES (((uint64_t) 1) << 11)
#define PKG_DIGRAPH (((uint64_t) 1) << 12)
#define PKG_KEEP_SYSTEM_CFLAGS (((uint64_t) 1) << 13)
#define PKG_KEEP_SYSTEM_LIBS (((uint64_t) 1) << 14)
#define PKG_VERSION (((uint64_t) 1) << 15)
#define PKG_ABOUT (((uint64_t) 1) << 16)
#define PKG_ENV_ONLY (((uint64_t) 1) << 17)
#define PKG_ERRORS_ON_STDOUT (((uint64_t) 1) << 18)
#define PKG_SILENCE_ERRORS (((uint64_t) 1) << 19)
#define PKG_IGNORE_CONFLICTS (((uint64_t) 1) << 20)
#define PKG_STATIC (((uint64_t) 1) << 21)
#define PKG_NO_UNINSTALLED (((uint64_t) 1) << 22)
#define PKG_UNINSTALLED (((uint64_t) 1) << 23)
#define PKG_LIST (((uint64_t) 1) << 24)
#define PKG_HELP (((uint64_t) 1) << 25)
#define PKG_PRINT_ERRORS (((uint64_t) 1) << 26)
#define PKG_SIMULATE (((uint64_t) 1) << 27)
#define PKG_NO_CACHE (((uint64_t) 1) << 28)
#define PKG_PROVIDES (((uint64_t) 1) << 29)
#define PKG_VALIDATE (((uint64_t) 1) << 30)
#define PKG_LIST_PACKAGE_NAMES (((uint64_t) 1) << 31)
#define PKG_NO_PROVIDES (((uint64_t) 1) << 32)
#define PKG_PURE (((uint64_t) 1) << 33)
#define PKG_PATH (((uint64_t) 1) << 34)
#define PKG_DEFINE_PREFIX (((uint64_t) 1) << 35)
#define PKG_DONT_DEFINE_PREFIX (((uint64_t) 1) << 36)
#define PKG_DONT_RELOCATE_PATHS (((uint64_t) 1) << 37)
#define PKG_DEBUG (((uint64_t) 1) << 38)
#define PKG_SHORT_ERRORS (((uint64_t) 1) << 39)
#define PKG_EXISTS (((uint64_t) 1) << 40)
#define PKG_MSVC_SYNTAX (((uint64_t) 1) << 41)
#define PKG_INTERNAL_CFLAGS (((uint64_t) 1) << 42)
#define PKG_DUMP_PERSONALITY (((uint64_t) 1) << 43)
#define PKG_SHARED (((uint64_t) 1) << 44)
#define PKG_DUMP_LICENSE (((uint64_t) 1) << 45)
#define PKG_SOLUTION (((uint64_t) 1) << 46)
#define PKG_EXISTS_CFLAGS (((uint64_t) 1) << 47)
#define PKG_FRAGMENT_TREE (((uint64_t) 1) << 48)
#define PKG_DUMP_SOURCE (((uint64_t) 1) << 49)
#define PKG_DUMP_LICENSE_FILE (((uint64_t) 1) << 50)
#define PKG_NEWLINES (((uint64_t) 1) << 51)
typedef struct {
pkgconf_client_t pkg_client;
pkgconf_fragment_render_ops_t *want_render_ops;
uint64_t want_flags;
int verbosity;
int maximum_traverse_depth;
size_t maximum_package_count;
const char *want_variable;
const char *want_fragment_filter;
const char *want_env_prefix;
char *required_pkgconfig_version;
const char *required_exact_module_version;
const char *required_max_module_version;
const char *required_module_version;
FILE *error_msgout;
FILE *logfile_out;
bool opened_error_msgout;
} pkgconf_cli_state_t;
extern void path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim);
extern int pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc);
extern void pkgconf_cli_state_reset(pkgconf_cli_state_t *state);
#endif

1396
cli/main.c

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@ fragment_should_quote(const pkgconf_fragment_t *frag)
for (src = frag->data; *src; src++)
{
if (((*src < ' ') ||
(*src >= (' ' + (frag->children.head != NULL ? 1 : 0)) && *src < '$') ||
(*src >= (' ' + (frag->merged ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') ||
@ -104,50 +104,68 @@ msvc_renderer_render_len(const pkgconf_list_t *list, bool escape)
}
static void
msvc_renderer_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, char delim)
msvc_renderer_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{
pkgconf_node_t *node;
char *bptr = buf;
memset(buf, 0, buflen);
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
size_t buf_remaining = buflen - (bptr - buf);
size_t cnt;
if (!allowed_fragment(frag))
continue;
if (fragment_len(frag) > buf_remaining)
break;
switch(frag->type) {
case 'D':
case 'I':
pkgconf_buffer_append_fmt(buf, "/%c", frag->type);
*bptr++ = '/';
*bptr++ = frag->type;
break;
case 'L':
pkgconf_buffer_append(buf, "/libpath:");
cnt = pkgconf_strlcpy(bptr, "/libpath:", buf_remaining);
bptr += cnt;
buf_remaining -= cnt;
break;
}
escape = fragment_should_quote(frag);
if (escape)
pkgconf_buffer_push_byte(buf, '"');
*bptr++ = '"';
pkgconf_buffer_append(buf, frag->data);
cnt = pkgconf_strlcpy(bptr, frag->data, buf_remaining);
bptr += cnt;
buf_remaining -= cnt;
if (frag->type == 'l')
pkgconf_buffer_append(buf, ".lib");
{
cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining);
bptr += cnt;
}
if (escape)
pkgconf_buffer_push_byte(buf, '"');
*bptr++ = '"';
pkgconf_buffer_push_byte(buf, delim);
*bptr++ = ' ';
}
*bptr = '\0';
}
static pkgconf_fragment_render_ops_t msvc_renderer_ops = {
static const pkgconf_fragment_render_ops_t msvc_renderer_ops = {
.render_len = msvc_renderer_render_len,
.render_buf = msvc_renderer_render_buf
};
pkgconf_fragment_render_ops_t *
const pkgconf_fragment_render_ops_t *
msvc_renderer_get(void)
{
return &msvc_renderer_ops;

View File

@ -18,6 +18,6 @@
#include <libpkgconf/libpkgconf.h>
pkgconf_fragment_render_ops_t *msvc_renderer_get(void);
const pkgconf_fragment_render_ops_t *msvc_renderer_get(void);
#endif

View File

@ -1,690 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "serialize.h"
#include "core.h"
#include "software.h"
#include "simplelicensing.h"
/*
* !doc
*
* .. c:function:: spdxtool_core_agent_t *spdxtool_core_agent_new(pkgconf_client_t *client, char *creation_info_id, char *name)
*
* Create new /Core/Agent struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *creation_info_id: CreationInfo spdxId
* :param char *name: Name of agent
* :return: NULL if some problem occurs and Agent struct if not
*/
spdxtool_core_agent_t *
spdxtool_core_agent_new(pkgconf_client_t *client, char *creation_info_id, char *name)
{
char spdx_id_name[1024];
char *spdx_id = NULL;
spdxtool_core_agent_t *agent_struct = NULL;
if(!client || !creation_info_id || !name)
{
return NULL;
}
agent_struct = calloc(1, sizeof(spdxtool_core_agent_t));
if(!agent_struct)
{
pkgconf_error(client, "Memory exhausted! Can't create agent struct.");
return NULL;
}
agent_struct->type = "Agent";
memset(spdx_id_name, 0x00, 1024);
strncpy(spdx_id_name, name, 1023);
spdxtool_util_string_correction(spdx_id_name);
spdx_id = spdxtool_util_get_spdx_id_string(client, agent_struct->type, spdx_id_name);
agent_struct->creation_info = creation_info_id;
agent_struct->spdx_id = spdx_id;
agent_struct->name = name;
return agent_struct;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_agent_free(spdxtool_core_agent_t *agent_struct)
*
* Free /Core/Agent struct
*
* :param spdxtool_core_agent_t *agent_struct: Agent struct to be freed.
* :return: nothing
*/
void
spdxtool_core_agent_free(spdxtool_core_agent_t *agent_struct)
{
if(!agent_struct)
{
return;
}
if(agent_struct->creation_info)
{
free(agent_struct->creation_info);
agent_struct->creation_info = NULL;
}
if(agent_struct->spdx_id)
{
free(agent_struct->spdx_id);
agent_struct->spdx_id = NULL;
}
if(agent_struct->name)
{
free(agent_struct->name);
agent_struct->name = NULL;
}
free(agent_struct);
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_agent_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_agent_t *agent_struct, bool last)
*
* Serialize /Core/Agent struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_core_agent_t *agent_struct: Agent struct to be serialized
* :param bool last: Is this last Agent struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_core_agent_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_agent_t *agent_struct, bool last)
{
(void) client;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", agent_struct->type, 3, 1);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", agent_struct->creation_info, 3, 1);
spdxtool_serialize_parm_and_string(buffer, "spdxId", agent_struct->spdx_id, 3, 1);
spdxtool_serialize_parm_and_string(buffer, "name", agent_struct->name, 3, 0);
spdxtool_serialize_obj_end(buffer, 2, last);
}
/*
* !doc
*
* .. c:function:: spdxtool_core_creation_info_t *spdxtool_core_creation_info_new(pkgconf_client_t *client, char *agent_id, char *id)
*
* Create new /Core/CreationInfo struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *agent_id: Agent spdxId
* :param char *id: Id for creation info
* :param char *time: If NULL current time is used if not then
* this time string is used. Time string should be
* in ISO8601 format: YYYY-MM-DDTHH:MM:SSZ
* :return: NULL if some problem occurs and CreationInfo struct if not
*/
spdxtool_core_creation_info_t *
spdxtool_core_creation_info_new(pkgconf_client_t *client, char *agent_id, char *id, char *time)
{
spdxtool_core_creation_info_t *creation_struct = NULL;
if(!client || !agent_id || !id)
{
return NULL;
}
creation_struct = calloc(1, sizeof(spdxtool_core_creation_info_t));
if(!creation_struct)
{
pkgconf_error(client, "Memory exhausted! Can't create agent struct.");
return NULL;
}
creation_struct->type = "CreationInfo";
creation_struct->id = id;
if(!time)
{
creation_struct->created = spdxtool_util_get_current_iso8601_time();
}
else
{
creation_struct->created = time;
}
creation_struct->created_by = agent_id;
creation_struct->created_using="pkgconf spdxtool";
creation_struct->spec_version = spdxtool_util_get_spdx_version(client);
return creation_struct;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation_struct)
*
* Free /Core/CreationInfo struct
*
* :param spdxtool_core_creation_info_t *creation_struct: CreationInfo struct to be freed.
* :return: nothing
*/
void
spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation_struct)
{
if(!creation_struct)
{
return;
}
if(creation_struct->id)
{
free(creation_struct->id);
creation_struct->id = NULL;
}
if(creation_struct->created)
{
free(creation_struct->created);
creation_struct->created = NULL;
}
if(creation_struct->created_by)
{
free(creation_struct->created_by);
creation_struct->created_by = NULL;
}
free(creation_struct);
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_creation_info_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_creation_info_t *creation_struct, bool last)
*
* Serialize /Core/CreationInfo struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_core_creation_info_t *creation_struct: CreationInfo struct to be serialized
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_core_creation_info_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_creation_info_t *creation_struct, bool last)
{
(void) client;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", creation_struct->type, 3, true);
spdxtool_serialize_parm_and_string(buffer, "@id", creation_struct->id, 3, true);
spdxtool_serialize_parm_and_string(buffer, "created", creation_struct->created, 3, true);
spdxtool_serialize_parm_and_char(buffer, "createdBy", '[', 3, false);
spdxtool_serialize_string(buffer, creation_struct->created_by, 4, false);
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_string(buffer, "specVersion", (char *)creation_struct->spec_version, 3, false);
spdxtool_serialize_obj_end(buffer, 2, last);
}
/*
* !doc
*
* .. c:function:: spdxtool_core_creation_info_t *spdxtool_core_creation_info_new(pkgconf_client_t *client, char *agent_id, char *id)
*
* Create new /Core/SpdxDocument struct
* In SPDX Lite SBOM there can be only one SpdxDocument
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *spdx_id: Id of this SpdxDocument
* :param char *creation_id: Id for creation info
* :return: NULL if some problem occurs and SpdxDocument struct if not
*/
spdxtool_core_spdx_document_t *
spdxtool_core_spdx_document_new(pkgconf_client_t *client, char *spdx_id, char *creation_id)
{
spdxtool_core_spdx_document_t *spdx_struct = NULL;
if(!client || !spdx_id || !creation_id)
{
return NULL;
}
(void)client;
spdx_struct = calloc(1, sizeof(spdxtool_core_spdx_document_t));
if(!spdx_struct)
{
pkgconf_error(client, "Memory exhausted! Can't create spdx_document struct.");
return NULL;
}
spdx_struct->type = "SpdxDocument";
spdx_struct->spdx_id = spdx_id;
spdx_struct->creation_info = creation_id;
return spdx_struct;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx_struct)
*
* Free /Core/SpdxDocument struct
*
* :param spdxtool_core_spdx_document_t *spdx_struct: SpdxDocument struct to be freed.
* :return: nothing
*/
void
spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx_struct)
{
pkgconf_node_t *iter = NULL;
pkgconf_node_t *iter_last = NULL;
if(!spdx_struct)
{
return;
}
if(spdx_struct->spdx_id)
{
free(spdx_struct->spdx_id);
spdx_struct->spdx_id = NULL;
}
if(spdx_struct->creation_info)
{
free(spdx_struct->creation_info);
spdx_struct->creation_info = NULL;
}
if(spdx_struct->agent)
{
free(spdx_struct->agent);
spdx_struct->agent = NULL;
}
iter_last = NULL;
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->rootElement.head, iter)
{
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
spdxtool_software_sbom_t *sbom = iter->data;
spdxtool_software_sbom_free(sbom);
iter->data = NULL;
iter_last = iter;
}
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
iter_last = NULL;
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->element.head, iter)
{
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
free(iter->data);
iter_last = iter;
}
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
iter_last = NULL;
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->licenses.head, iter)
{
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
spdxtool_simplelicensing_license_expression_t *expression = iter->data;
spdxtool_simplelicensing_licenseExpression_free(expression);
iter->data = NULL;
iter_last = iter;
}
if(iter_last)
{
free(iter_last);
iter_last = NULL;
}
free(spdx_struct);
}
/*
* !doc
*
* .. c:function:: bool spdxtool_core_spdx_document_is_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license)
*
* Find out if specific license is already there.
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param spdxtool_core_spdx_document_t *spdx_struct: SpdxDocument struct being used.
* :param char *license: SPDX name of license
* :return: true is license is there and false if not
*/
bool
spdxtool_core_spdx_document_is_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license)
{
pkgconf_node_t *iter = NULL;
spdxtool_simplelicensing_license_expression_t *expression = NULL;
(void) client;
if(!license)
{
return false;
}
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->licenses.head, iter)
{
expression = iter->data;
if (!strcmp(expression->license_expression, license))
{
return true;
}
}
return false;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license)
*
* Add license to SpdxDocument and make sure that specific license is not already there.
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param spdxtool_core_spdx_document_t *spdx_struct: SpdxDocument struct being used.
* :param char *license: SPDX name of license
* :return: nothing
*/
void
spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license)
{
pkgconf_node_t *node = NULL;
if(!license)
{
return;
}
if(spdxtool_core_spdx_document_is_license(client, spdx_struct, license))
{
return;
}
node = calloc(1, sizeof(pkgconf_node_t));
if(!node)
{
pkgconf_error(client, "Memory exhausted! Cant't add license to spdx_document.");
return;
}
spdxtool_simplelicensing_license_expression_t *expression = spdxtool_simplelicensing_licenseExpression_new(client, license);
pkgconf_node_insert_tail(node, expression, &spdx_struct->licenses);
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *element)
*
* Add element spdxId to SpdxDocument
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param spdxtool_core_spdx_document_t *spdx_struct: SpdxDocument struct being used.
* :param char *element: spdxId of element
* :return: nothing
*/
void
spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *element)
{
pkgconf_node_t *node = NULL;
(void) client;
if(!element)
{
return;
}
node = calloc(1, sizeof(pkgconf_node_t));
if(!node)
{
pkgconf_error(NULL, "Memory exhausted! Can't add spdx_id's to spdx_document.");
return;
}
pkgconf_node_insert_tail(node, element, &spdx_struct->element);
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_creation_info_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_creation_info_t *creation_struct, bool last)
*
* Serialize /Core/SpdxDocument struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_core_spdx_document_t *spdx_struct: SpdxDocument struct to be serialized
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_core_spdx_document_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_spdx_document_t *spdx_struct, bool last)
{
pkgconf_node_t *iter = NULL;
bool is_next = false;
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->rootElement.head, iter)
{
spdxtool_software_sbom_t *sbom = NULL;
sbom = iter->data;
spdxtool_software_sbom_serialize(client, buffer, sbom, true);
}
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", spdx_struct->type, 3, true);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", spdx_struct->creation_info, 3, true);
spdxtool_serialize_parm_and_string(buffer, "spdxId", spdx_struct->spdx_id, 3, true);
spdxtool_serialize_parm_and_char(buffer, "rootElement", '[', 3, false);
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->rootElement.head, iter)
{
spdxtool_software_sbom_t *sbom = NULL;
sbom = iter->data;
is_next = false;
if(iter->next)
{
is_next = true;
}
spdxtool_serialize_string(buffer, sbom->spdx_id, 4, is_next);
}
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_char(buffer, "element", '[', 3, false);
spdxtool_serialize_string(buffer, spdx_struct->agent, 4, true);
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->element.head, iter)
{
char *spdx_id = NULL;
spdx_id = iter->data;
spdxtool_serialize_string(buffer, spdx_id, 4, true);
}
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->rootElement.head, iter)
{
spdxtool_software_sbom_t *sbom = NULL;
sbom = iter->data;
is_next = false;
if(iter->next)
{
is_next = true;
}
spdxtool_serialize_string(buffer, sbom->spdx_id, 4, true);
spdxtool_serialize_string(buffer, pkgconf_tuple_find(client, &sbom->rootElement->vars, "spdxId"), 4, is_next);
}
spdxtool_serialize_array_end(buffer, 3, false);
spdxtool_serialize_obj_end(buffer, 2, last);
}
/*
* !doc
*
* .. c:function:: spdxtool_core_relationship_t *spdxtool_core_relationship_new(pkgconf_client_t *client, char *creation_info_id, char *spdx_id, char *from, char *to, char *relationship_type)
*
* Create new /Core/Relationship struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *creation_id: Id for creation info
* :param char *spdx_id: Id of this SpdxDocument
* :param char *from: from spdxId
* :param char *to: to spdxId
* :param char *relationship_type: These can be found on SPDX documentation
* :return: NULL if some problem occurs and SpdxDocument struct if not
*/
spdxtool_core_relationship_t *
spdxtool_core_relationship_new(pkgconf_client_t *client, char *creation_info_id, char *spdx_id, char *from, char *to, char *relationship_type)
{
spdxtool_core_relationship_t *relationship = NULL;
if(!client || !creation_info_id || !spdx_id || !from || !to || !relationship_type)
{
return NULL;
}
(void) client;
relationship = calloc(1, sizeof(spdxtool_core_relationship_t));
if(!relationship)
{
pkgconf_error(client, "Memory exhausted! Can't create relationship struct.");
return NULL;
}
relationship->type = "Relationship";
relationship->creation_info = creation_info_id;
relationship->spdx_id = spdx_id;
relationship->from = from;
relationship->to = to;
relationship->relationship_type = relationship_type;
return relationship;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship_struct)
*
* Free /Core/Relationship struct
*
* :param spdxtool_core_relationship_t *relationship_struct: Relationship struct to be freed.
* :return: nothing
*/
void
spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship_struct)
{
if(!relationship_struct)
{
return;
}
if(relationship_struct->spdx_id)
{
free(relationship_struct->spdx_id);
relationship_struct->spdx_id = NULL;
}
if(relationship_struct->creation_info)
{
free(relationship_struct->creation_info);
relationship_struct->creation_info = NULL;
}
if(relationship_struct->from)
{
free(relationship_struct->from);
relationship_struct->from = NULL;
}
if(relationship_struct->to)
{
free(relationship_struct->to);
relationship_struct->to = NULL;
}
if(relationship_struct->relationship_type)
{
free(relationship_struct->relationship_type);
relationship_struct->relationship_type = NULL;
}
free(relationship_struct);
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_creation_info_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_creation_info_t *creation_struct, bool last)
*
* Serialize /Core/Relationship struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_core_relationship_t *relationship_struct: Relationship struct to be serialized
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_core_relationship_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_relationship_t *relationship_struct, bool last)
{
(void) client;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", relationship_struct->type, 3, true);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", relationship_struct->creation_info, 3, true);
spdxtool_serialize_parm_and_string(buffer, "spdxId", relationship_struct->spdx_id, 3, true);
spdxtool_serialize_parm_and_string(buffer, "from", relationship_struct->from, 3, true);
spdxtool_serialize_parm_and_char(buffer, "to", '[', 3, false);
spdxtool_serialize_string(buffer, relationship_struct->to, 4, false);
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_string(buffer, "relationshipType", relationship_struct->relationship_type, 3, false);
spdxtool_serialize_obj_end(buffer, 2, last);
}

View File

@ -1,73 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#ifndef CLI__SPDXTOOL__CORE_H
#define CLI__SPDXTOOL__CORE_H
#include <stdlib.h>
#include "util.h"
#ifdef __cplusplus
extern "C" {
#endif
spdxtool_core_agent_t *
spdxtool_core_agent_new(pkgconf_client_t *client, char *creation_id, char *name);
void
spdxtool_core_agent_free(spdxtool_core_agent_t *agent_struct);
void
spdxtool_core_agent_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_agent_t *agent_struct, bool last);
spdxtool_core_creation_info_t *
spdxtool_core_creation_info_new(pkgconf_client_t *client, char *agent_id, char *id, char *time);
void
spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation_struct);
void
spdxtool_core_creation_info_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_creation_info_t *creation_struct, bool last);
spdxtool_core_spdx_document_t *
spdxtool_core_spdx_document_new(pkgconf_client_t *client, char *spdx_id, char *creation_id);
bool
spdxtool_core_spdx_document_is_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license);
void
spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *license);
void
spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx_struct, char *element);
void
spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx_struct);
void
spdxtool_core_spdx_document_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_spdx_document_t *spdx_struct, bool last);
spdxtool_core_relationship_t *
spdxtool_core_relationship_new(pkgconf_client_t *client, char *creation_info_id, char *spdx_id, char *from, char *to, char *relationship_type);
void
spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship_struct);
void
spdxtool_core_relationship_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_relationship_t *relationship_struct, bool last);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,356 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include "libpkgconf/config.h"
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include "getopt_long.h"
#include "util.h"
#include "core.h"
#include "software.h"
#include "serialize.h"
#include "simplelicensing.h"
#define PKG_VERSION (((uint64_t) 1) << 1)
#define PKG_ABOUT (((uint64_t) 1) << 2)
#define PKG_HELP (((uint64_t) 1) << 3)
static const char *spdx_version = "3.0.1";
static const char *bom_license = "CC0-1.0";
static const char *xsd_any_uri_default_base = "https://github.com/pkgconf/pkgconf";
static int maximum_traverse_depth = 2000;
static pkgconf_client_t pkg_client;
static uint64_t want_flags;
static size_t maximum_package_count = 0;
// static int maximum_traverse_depth = 2000;
static FILE *error_msgout = NULL;
static const char *
environ_lookup_handler(const pkgconf_client_t *client, const char *key)
{
(void) client;
return getenv(key);
}
static bool
error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{
(void) client;
(void) data;
fprintf(error_msgout, "%s", msg);
return true;
}
static void
write_jsonld_end(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_buffer_t *buffer)
{
(void) client;
(void) world;
spdxtool_serialize_array_end(buffer, 1, false);
spdxtool_serialize_obj_end(buffer, 0, false);
}
static void
write_jsonld_header(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_buffer_t *buffer)
{
(void) client;
(void) world;
spdxtool_serialize_obj_start(buffer, 0);
spdxtool_serialize_parm_and_string(buffer, "@context", "https://spdx.org/rdf/3.0.1/spdx-context.jsonld", 1, true);
spdxtool_serialize_parm_and_char(buffer, "@graph", '[', 1, false);
}
static void
generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
{
(void) client;
pkgconf_node_t *node = NULL;
spdxtool_core_spdx_document_t *document = (spdxtool_core_spdx_document_t *)ptr;
char *package_spdx = NULL;
char spdx_id_name[1024];
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return;
spdxtool_software_sbom_t *sbom = spdxtool_software_sbom_new(client, spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->realname), strdup(document->creation_info), strdup("build"));
sbom->spdx_document = document;
sbom->rootElement = pkg;
package_spdx = spdxtool_util_get_spdx_id_string(client, "Package", pkg->realname);
pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0);
free(package_spdx);
package_spdx = NULL;
pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0);
pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0);
if (pkg->license != NULL)
{
snprintf(spdx_id_name, 1024, "%s/hasDeclaredLicense", pkg->realname);
package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0);
free(package_spdx);
package_spdx = NULL;
snprintf(spdx_id_name, 1024, "%s/hasConcludedLicense", pkg->realname);
package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0);
free(package_spdx);
package_spdx = NULL;
spdxtool_core_spdx_document_add_license(client, document, pkg->license);
}
node = calloc(1, sizeof(pkgconf_node_t));
if(!node)
{
pkgconf_error(NULL, "Memory exhausted!");
return;
}
pkgconf_node_insert_tail(node, sbom, &document->rootElement);
}
static bool
generate_spdx(pkgconf_client_t *client, pkgconf_pkg_t *world, char *creation_time, char *creation_id, char *agent_name)
{
int eflag;
pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER;
char *agent_name_string = "Default";
char *creation_id_string = "_:creationinfo_1";
char *creation_time_string = NULL;
if(agent_name)
{
agent_name_string = agent_name;
}
if(creation_time)
{
creation_time_string = strdup(creation_time);
}
if(creation_id)
{
creation_id_string = creation_id;
}
spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, strdup(creation_id_string), strdup(agent_name_string));
spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(&pkg_client, strdup(agent->spdx_id), strdup(creation_id_string), creation_time_string);
spdxtool_core_spdx_document_t *document = spdxtool_core_spdx_document_new(&pkg_client, spdxtool_util_get_spdx_id_int(&pkg_client, "spdxDocument"), strdup(creation_id_string));
document->agent = strdup(agent->spdx_id);
eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maximum_traverse_depth, 0);
if (eflag != PKGCONF_PKG_ERRF_OK)
return false;
write_jsonld_header(client, world, &buffer);
spdxtool_core_agent_serialize(client, &buffer, agent, true);
spdxtool_core_creation_info_serialize(client, &buffer, creation, true);
spdxtool_simplelicensing_licenseExpression_serialize(client, &buffer, document, true);
spdxtool_core_spdx_document_serialize(client, &buffer, document, false);
write_jsonld_end(client, world, &buffer);
spdxtool_core_spdx_document_free(document);
spdxtool_core_agent_free(agent);
spdxtool_core_creation_info_free(creation);
printf("%s\n", pkgconf_buffer_str(&buffer));
pkgconf_buffer_finalize(&buffer);
return true;
}
static int
version(void)
{
printf("spdxtool %s\n", PACKAGE_VERSION);
return EXIT_SUCCESS;
}
static int
about(void)
{
printf("spdxtool (%s %s)\n\n", PACKAGE_NAME, PACKAGE_VERSION);
printf("SPDX-License-Identifier: BSD-2-Clause\n\n");
printf("Copyright (c) 2025 The FreeBSD Foundation\n\n");
printf("Portions of this software were developed by\n");
printf("Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from\n");
printf("the FreeBSD Foundation\n\n");
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
return EXIT_SUCCESS;
}
static int
usage(void)
{
printf("usage: spdxtool [modules]\n");
printf("\nOptions:\n");
printf(" --agent-name Set agent name [default: 'Default']\n");
printf(" --creation-time Use string as creation time (Should be in ISO8601 format) [default: current time]\n");
printf(" --creation-id Use string as creation id [default: '_:creationinfo_1']\n");
printf(" --help this message\n");
printf(" --about print bomtool version and license to stdout\n");
printf(" --version print bomtool version to stdout\n");
return EXIT_SUCCESS;
}
int
main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
pkgconf_list_t pkgq = PKGCONF_LIST_INITIALIZER;
unsigned int want_client_flags = PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
pkgconf_cross_personality_t *personality = pkgconf_cross_personality_default();
char *creation_time = NULL;
char *creation_id = NULL;
char *agent_name = NULL;
pkgconf_pkg_t world =
{
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
error_msgout = stderr;
struct pkg_option options[] =
{
{ "agent-name", required_argument, NULL, 100, },
{ "creation-time", required_argument, NULL, 101, },
{ "creation-id", required_argument, NULL, 102, },
{ "version", no_argument, &want_flags, PKG_VERSION, },
{ "about", no_argument, &want_flags, PKG_ABOUT, },
{ "help", no_argument, &want_flags, PKG_HELP, },
{ NULL, 0, NULL, 0 }
};
while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1)
{
switch (ret)
{
case 100:
agent_name = pkg_optarg;
break;
case 101:
creation_time = pkg_optarg;
break;
case 102:
creation_id = pkg_optarg;
break;
case '?':
case ':':
return EXIT_FAILURE;
default:
break;
}
}
pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler);
/* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags);
/* at this point, want_client_flags should be set, so build the dir list */
pkgconf_client_dir_list_build(&pkg_client, personality);
if ((want_flags & PKG_ABOUT) == PKG_ABOUT)
return about();
if ((want_flags & PKG_VERSION) == PKG_VERSION)
return version();
if ((want_flags & PKG_HELP) == PKG_HELP)
return usage();
while (1)
{
const char *package = argv[pkg_optind];
if (package == NULL)
break;
/* check if there is a limit to the number of packages allowed to be included, if so and we have hit
* the limit, stop adding packages to the queue.
*/
if (maximum_package_count > 0 && pkgq.length > maximum_package_count)
break;
while (isspace((unsigned char)package[0]))
package++;
/* skip empty packages */
if (package[0] == '\0')
{
pkg_optind++;
continue;
}
if (argv[pkg_optind + 1] == NULL || !PKGCONF_IS_OPERATOR_CHAR(*(argv[pkg_optind + 1])))
{
pkgconf_queue_push(&pkgq, package);
pkg_optind++;
}
else
{
char packagebuf[PKGCONF_BUFSIZE];
snprintf(packagebuf, sizeof packagebuf, "%s %s %s", package, argv[pkg_optind + 1], argv[pkg_optind + 2]);
pkg_optind += 3;
pkgconf_queue_push(&pkgq, packagebuf);
}
}
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{
ret = EXIT_FAILURE;
goto out;
}
spdxtool_util_set_uri_root(&pkg_client, xsd_any_uri_default_base);
spdxtool_util_set_spdx_license(&pkg_client, bom_license);
spdxtool_util_set_spdx_version(&pkg_client, spdx_version);
if (!generate_spdx(&pkg_client, &world, creation_time, creation_id, agent_name))
{
ret = EXIT_FAILURE;
goto out;
}
ret = EXIT_SUCCESS;
out:
pkgconf_solution_free(&pkg_client, &world);
pkgconf_queue_free(&pkgq);
pkgconf_cross_personality_deinit(personality);
pkgconf_client_deinit(&pkg_client);
return ret;
}

View File

@ -1,206 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "core.h"
static inline void
serialize_add_indent(pkgconf_buffer_t *buffer, unsigned int level)
{
for (; level; level--)
pkgconf_buffer_append(buffer, " ");
}
static inline void
serialize_next_line(pkgconf_buffer_t *buffer, bool more)
{
if (more)
pkgconf_buffer_push_byte(buffer, ',');
pkgconf_buffer_push_byte(buffer, '\n');
}
static inline void
serialize_begin_object(pkgconf_buffer_t *buffer, char ch, unsigned int level)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_push_byte(buffer, ch);
serialize_next_line(buffer, false);
}
static inline void
serialize_end_object(pkgconf_buffer_t *buffer, char ch, unsigned int level, bool more)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_push_byte(buffer, ch);
serialize_next_line(buffer, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_parm_and_string(pkgconf_buffer_t *buffer, char *parm, char *string, unsigned int level, bool more)
*
* Add paramter, string and optional comma to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param char *param: Parameter name
* :param char *string: String to add
* :param unsigned int level: Indent level
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_parm_and_string(pkgconf_buffer_t *buffer, char *parm, char *string, unsigned int level, bool more)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_append_fmt(buffer, "\"%s\": \"%s\"", parm, string);
serialize_next_line(buffer, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_parm_and_char(pkgconf_buffer_t *buffer, char *parm, char ch, unsigned int level, bool more)
*
* Add paramter, char and optional comma to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param char *param: Parameter name
* :param char ch: Char to add
* :param unsigned int level: Indent level
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_parm_and_char(pkgconf_buffer_t *buffer, char *parm, char ch, unsigned int level, bool more)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_append_fmt(buffer, "\"%s\": %c", parm, ch);
serialize_next_line(buffer, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_parm_and_int(pkgconf_buffer_t *buffer, char *parm, int integer, unsigned int level, bool more)
*
* Add paramter, integer and optional comma to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param char *param: Parameter name
* :param int integer: Int to add
* :param unsigned int level: Indent level
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_parm_and_int(pkgconf_buffer_t *buffer, char *parm, int integer, unsigned int level, bool more)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_append_fmt(buffer, "\"%s\": %d", parm, integer);
serialize_next_line(buffer, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_string(pkgconf_buffer_t *buffer, char *string, unsigned int level, bool more)
*
* Add just string.
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param char *param: Parameter name
* :param char *ch: String to add
* :param unsigned int: level Indent level
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_string(pkgconf_buffer_t *buffer, char *string, unsigned int level, bool more)
{
serialize_add_indent(buffer, level);
pkgconf_buffer_push_byte(buffer, '"');
pkgconf_buffer_append(buffer, string);
pkgconf_buffer_push_byte(buffer, '"');
serialize_next_line(buffer, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_obj_start(pkgconf_buffer_t *buffer, unsigned int level)
*
* Start JSON object to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param unsigned int level: Indent level
* :return: nothing
*/
void
spdxtool_serialize_obj_start(pkgconf_buffer_t *buffer, unsigned int level)
{
serialize_begin_object(buffer, '{', level);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_obj_end(pkgconf_buffer_t *buffer, unsigned int level, bool more)
*
* End JSON object to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param unsigned int level: Level which is added
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_obj_end(pkgconf_buffer_t *buffer, unsigned int level, bool more)
{
serialize_end_object(buffer, '}', level, more);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_obj_start(pkgconf_buffer_t *buffer, unsigned int level)
*
* Start JSON array to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param unsigned int level: Level which is added
* :return: nothing
*/
void
spdxtool_serialize_array_start(pkgconf_buffer_t *buffer, unsigned int level)
{
serialize_begin_object(buffer, '[', level);
}
/*
* !doc
*
* .. c:function:: void spdxtool_serialize_array_end(pkgconf_buffer_t *buffer, unsigned int level, bool more)
*
* End JSON array to buffer
*
* :param pkgconf_buffer_t *buffer: Buffer to add.
* :param unsigned int level: Level which is added
* :param bool more: true if more fields are expected, else false
* :return: nothing
*/
void
spdxtool_serialize_array_end(pkgconf_buffer_t *buffer, unsigned int level, bool more)
{
serialize_end_object(buffer, ']', level, more);
}

View File

@ -1,50 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#ifndef CLI__SPDXTOOL__SERIALIZE_H
#define CLI__SPDXTOOL__SERIALIZE_H
#ifdef __cplusplus
extern "C" {
#endif
void
spdxtool_serialize_parm_and_string(pkgconf_buffer_t *buffer, char *parm, char *string, unsigned int level, bool comma);
void
spdxtool_serialize_parm_and_char(pkgconf_buffer_t *buffer, char *parm, char ch, unsigned int level, bool comma);
void
spdxtool_serialize_parm_and_int(pkgconf_buffer_t *buffer, char *parm, int integer, unsigned int level, bool comma);
void
spdxtool_serialize_string(pkgconf_buffer_t *buffer, char *string, unsigned int level, bool comma);
void
spdxtool_serialize_obj_start(pkgconf_buffer_t *buffer, unsigned int level);
void
spdxtool_serialize_obj_end(pkgconf_buffer_t *buffer, unsigned int level, bool comma);
void
spdxtool_serialize_array_start(pkgconf_buffer_t *buffer, unsigned int level);
void
spdxtool_serialize_array_end(pkgconf_buffer_t *buffer, unsigned int level, bool comma);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,120 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "serialize.h"
#include "software.h"
#include "core.h"
/*
* !doc
*
* .. c:function:: spdxtool_simplelicensing_license_expression_t *spdxtool_simplelicensing_licenseExpression_new(pkgconf_client_t *client, char *license)
*
* Create new /SimpleLicensing/SimpleLicensingText struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *license: SPDX name of license
* :return: NULL if some problem occurs and SimpleLicensingText struct if not
*/
spdxtool_simplelicensing_license_expression_t *
spdxtool_simplelicensing_licenseExpression_new(pkgconf_client_t *client, char *license)
{
spdxtool_simplelicensing_license_expression_t *expression = NULL;
if(!client || !license)
{
return NULL;
}
expression = calloc(1, sizeof(spdxtool_simplelicensing_license_expression_t));
if(!expression)
{
pkgconf_error(client, "Memory exhausted! Can't create simplelicense_expression struct!");
return NULL;
}
expression->type = "simplelicensing_LicenseExpression";
expression->license_expression = strdup(license);
expression->spdx_id = spdxtool_util_get_spdx_id_string(client, expression->type, license);
return expression;
}
/*
* !doc
*
* .. c:function:: void spdxtool_simplelicensing_licenseExpression_free(spdxtool_simplelicensing_license_expression_t *expression_struct)
*
* Free /SimpleLicensing/SimpleLicensingText struct
*
* :param spdxtool_simplelicensing_license_expression_t *expression_struct: SimpleLicensingText struct to be freed.
* :return: nothing
*/
void
spdxtool_simplelicensing_licenseExpression_free(spdxtool_simplelicensing_license_expression_t *expression_struct)
{
if(!expression_struct)
{
return;
}
if(expression_struct->spdx_id)
{
free(expression_struct->spdx_id);
expression_struct->spdx_id = NULL;
}
if(expression_struct->license_expression)
{
free(expression_struct->license_expression);
expression_struct->license_expression = NULL;
}
free(expression_struct);
}
/*
* !doc
*
* .. c:function:: void spdxtool_simplelicensing_licenseExpression_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_spdx_document_t *spdx_struct, bool last)
*
* Serialize /SimpleLicensing/SimpleLicensingText struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_core_spdx_document_t *spdx_struct: SimpleLicensingText struct to be serialized
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_simplelicensing_licenseExpression_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_spdx_document_t *spdx_struct, bool last)
{
pkgconf_node_t *iter = NULL;
(void) last;
PKGCONF_FOREACH_LIST_ENTRY(spdx_struct->licenses.head, iter)
{
spdxtool_simplelicensing_license_expression_t *expression = iter->data;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", "simplelicensing_LicenseExpression", 3, true);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", spdx_struct->creation_info, 3, true);
spdxtool_serialize_parm_and_string(buffer, "spdxId",expression->spdx_id, 3, true);
spdxtool_serialize_parm_and_string(buffer, "simplelicensing_licenseExpression", expression->license_expression, 3, false);
spdxtool_serialize_obj_end(buffer, 2, true);
spdxtool_core_spdx_document_add_element(client, spdx_struct, strdup(expression->spdx_id));
}
}

View File

@ -1,38 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#ifndef CLI__SPDXTOOL__SIMPLELICENSING_H
#define CLI__SPDXTOOL__SIMPLELICENSING_H
#ifdef __cplusplus
extern "C" {
#endif
spdxtool_simplelicensing_license_expression_t *
spdxtool_simplelicensing_licenseExpression_new(pkgconf_client_t *client, char *license);
void
spdxtool_simplelicensing_licenseExpression_free(spdxtool_simplelicensing_license_expression_t *expression_struct);
void
spdxtool_simplelicensing_licenseExpression_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_core_spdx_document_t *spdx_struct, bool last);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,241 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "serialize.h"
#include "software.h"
#include "core.h"
/*
* !doc
*
* .. c:function:: spdxtool_software_sbom_t *spdxtool_software_sbom_new(pkgconf_client_t *client, char *spdx_id, char *creation_id, char *sbom_type)
*
* Create new /Software/Sbom struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *spdx_id: spdxId for this SBOM element
* :param char *creation_id: id for CreationInfo
* :param char *sbom_type: Sbom types can be found SPDX documention
* :return: NULL if some problem occurs and Sbom struct if not
*/
spdxtool_software_sbom_t *
spdxtool_software_sbom_new(pkgconf_client_t *client, char *spdx_id, char *creation_id, char *sbom_type)
{
spdxtool_software_sbom_t *sbom_struct = NULL;
if(!client || !spdx_id || !creation_id || !sbom_type)
{
return NULL;
}
(void)client;
sbom_struct = calloc(1, sizeof(spdxtool_software_sbom_t));
if(!sbom_struct)
{
pkgconf_error(client, "Memory exhausted! Can't create sbom struct.");
return NULL;
}
sbom_struct->type="software_Sbom";
sbom_struct->spdx_id = spdx_id;
sbom_struct->creation_info = creation_id;
sbom_struct->sbom_type = sbom_type;
return sbom_struct;
}
/*
* !doc
*
* .. c:function:: void spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom_struct)
*
* Free /Software/Sbom struct
*
* :param spdxtool_software_sbom_t *sbom_struct: Sbom struct to be freed.
* :return: nothing
*/
void
spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom_struct)
{
if(!sbom_struct)
{
return;
}
if(sbom_struct->spdx_id)
{
free(sbom_struct->spdx_id);
sbom_struct->spdx_id = NULL;
}
if(sbom_struct->creation_info)
{
free(sbom_struct->creation_info);
sbom_struct->creation_info = NULL;
}
if(sbom_struct->sbom_type)
{
free(sbom_struct->sbom_type);
sbom_struct->sbom_type = NULL;
}
free(sbom_struct);
}
/*
* !doc
*
* .. c:function:: void spdxtool_software_sbom_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_software_sbom_t *sbom_struct, bool last)
*
* Serialize /Software/Sbom struct to JSON
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param spdxtool_software_sbom_t *sbom_struct: SimpleLicensingText struct to be serialized
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_software_sbom_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_software_sbom_t *sbom_struct, bool last)
{
pkgconf_node_t *node = NULL;
char *value;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", sbom_struct->type, 3, true);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", sbom_struct->creation_info, 3, true);
spdxtool_serialize_parm_and_string(buffer, "spdxId", sbom_struct->spdx_id, 3, true);
spdxtool_serialize_parm_and_char(buffer, "software_sbomType", '[', 3, false);
spdxtool_serialize_string(buffer, sbom_struct->sbom_type, 4, false);
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_char(buffer, "rootElement", '[', 3, false);
spdxtool_serialize_string(buffer, pkgconf_tuple_find(client, &sbom_struct->rootElement->vars, "spdxId"), 4, false);
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_char(buffer, "element", '[', 3, false);
PKGCONF_FOREACH_LIST_ENTRY(sbom_struct->rootElement->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
char *spdx_id_relation = NULL;
char tmp_str[1024];
// New relation spdxId
snprintf(tmp_str, 1024, "%s/dependsOn/%s", sbom_struct->rootElement->realname, match->realname);
spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Releationship", tmp_str);
spdxtool_serialize_string(buffer, spdx_id_relation, 4, true);
spdxtool_core_spdx_document_add_element(client, sbom_struct->spdx_document, strdup(spdx_id_relation));
free(spdx_id_relation);
}
value = pkgconf_tuple_find(client, &sbom_struct->rootElement->vars, "hasDeclaredLicense");
if (value != NULL)
{
spdxtool_serialize_string(buffer, value, 4, true);
spdxtool_core_spdx_document_add_element(client, sbom_struct->spdx_document, strdup(value));
}
value = pkgconf_tuple_find(client, &sbom_struct->rootElement->vars, "hasConcludedLicense");
if (value != NULL)
{
spdxtool_serialize_string(buffer, value, 4, false);
spdxtool_core_spdx_document_add_element(client, sbom_struct->spdx_document, strdup(value));
}
spdxtool_serialize_array_end(buffer, 3, false);
spdxtool_serialize_obj_end(buffer, 2, last);
spdxtool_software_package_serialize(client, buffer, sbom_struct->rootElement, false);
}
/*
* !doc
*
* .. c:function:: void spdxtool_software_sbom_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_software_sbom_t *sbom_struct, bool last)
*
* Serialize /Software/Package struct to JSON
* This is bit special case as it takes pkgconf pkg struct and serializes that one
* There is not new or free for this stype
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param pkgconf_buffer_t *buffer: Buffer where struct is serialized
* :param pkgconf_pkg_t *pkg: Pkgconf package
* :param bool last: Is this last CreationInfo struct or does it need comma at the end. True comma False not
* :return: nothing
*/
void
spdxtool_software_package_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, pkgconf_pkg_t *pkg, bool last)
{
spdxtool_core_relationship_t *relationship_struct = NULL;
char *spdx_id_license = NULL, *tuple_license;
pkgconf_node_t *node = NULL;
(void) last;
spdxtool_serialize_obj_start(buffer, 2);
spdxtool_serialize_parm_and_string(buffer, "@type", "software_Package", 3, true);
spdxtool_serialize_parm_and_string(buffer, "creationInfo", pkgconf_tuple_find(client, &pkg->vars, "creationInfo"), 3, true);
spdxtool_serialize_parm_and_string(buffer, "spdxId", pkgconf_tuple_find(client, &pkg->vars, "spdxId"), 3, true);
spdxtool_serialize_parm_and_string(buffer, "name", pkg->realname, 3, true);
spdxtool_serialize_parm_and_char(buffer, "originatedBy", '[', 3, false);
spdxtool_serialize_string(buffer, pkgconf_tuple_find(client, &pkg->vars, "agent"), 4, false);
spdxtool_serialize_array_end(buffer, 3, true);
spdxtool_serialize_parm_and_string(buffer, "software_copyrightText", "NOASSERTION", 3, true);
spdxtool_serialize_parm_and_string(buffer, "software_packageVersion", pkg->version, 3, false);
spdxtool_serialize_obj_end(buffer, 2, true);
/* These are must so add them right a way */
spdx_id_license = spdxtool_util_get_spdx_id_string(client, "simplelicensing_LicenseExpression", pkg->license);
tuple_license = pkgconf_tuple_find(client, &pkg->vars, "hasDeclaredLicense");
if (tuple_license != NULL)
{
relationship_struct = spdxtool_core_relationship_new(client, strdup(pkgconf_tuple_find(client, &pkg->vars, "creationInfo")), strdup(tuple_license), strdup(pkgconf_tuple_find(client, &pkg->vars, "spdxId")), strdup(spdx_id_license), strdup("hasDeclaredLicense"));
spdxtool_core_relationship_serialize(client, buffer, relationship_struct, true);
spdxtool_core_relationship_free(relationship_struct);
}
tuple_license = pkgconf_tuple_find(client, &pkg->vars, "hasConcludedLicense");
if (tuple_license != NULL)
{
relationship_struct = spdxtool_core_relationship_new(client, strdup(pkgconf_tuple_find(client, &pkg->vars, "creationInfo")), strdup(tuple_license), strdup(pkgconf_tuple_find(client, &pkg->vars, "spdxId")), spdx_id_license, strdup("hasConcludedLicense"));
spdxtool_core_relationship_serialize(client, buffer, relationship_struct, true);
spdxtool_core_relationship_free(relationship_struct);
}
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
char *spdx_id_relation = NULL;
char *spdx_id_package = NULL;
char tmp_str[1024];
// New relation spdxId
snprintf(tmp_str, 1024, "%s/dependsOn/%s", pkg->realname, match->realname);
spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Releationship", tmp_str);
// new package spdxId which will be hopefully come later on
spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->realname);
relationship_struct = spdxtool_core_relationship_new(client, strdup(pkgconf_tuple_find(client, &pkg->vars, "creationInfo")), spdx_id_relation, strdup(pkgconf_tuple_find(client, &pkg->vars, "spdxId")), spdx_id_package, strdup("dependsOn"));
spdxtool_core_relationship_serialize(client, buffer, relationship_struct, true);
spdxtool_core_relationship_free(relationship_struct);
}
}

View File

@ -1,37 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#ifndef CLI__SPDXTOOL_SOFTWARE_H
#define CLI__SPDXTOOL_SOFTWARE_H
#include <stdlib.h>
#include "util.h"
#ifdef __cplusplus
extern "C" {
#endif
spdxtool_software_sbom_t *
spdxtool_software_sbom_new(pkgconf_client_t *client, char *spdx_id, char *creation_id, char *sbom_type);
void
spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom_struct);
void
spdxtool_software_sbom_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, spdxtool_software_sbom_t *sbom_struct, bool last);
void
spdxtool_software_package_serialize(pkgconf_client_t *client, pkgconf_buffer_t *buffer, pkgconf_pkg_t *pkg, bool last);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,255 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#include <libpkgconf/libpkgconf.h>
#include <libpkgconf/stdinc.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
/*
* !doc
*
* .. c:function:: void spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default)
*
* Set key wit default value. Default value is used if key is NULL
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param const char *key: Key to be preserved
* :param const char *key_value: Value for key
* :param const char *key_default: Default value if key_value is NULL
* :return: nothing
*/
void
spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default)
{
PKGCONF_TRACE(client, "set uri_root to: %s", key_value != NULL ? key_value : key_default);
pkgconf_tuple_add_global(client, key, key_value != NULL ? key_value : key_default);
}
/*
* !doc
*
* .. c:function:: void spdxtool_util_set_uri_root(pkgconf_client_t *client, const char *uri_root)
*
* Set URI/URL root for spdxId. Type for this is 'xsd:anyURI' which means
* it can they may be absolute or relative.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param const char *uri_root: URI root.
* :return: nothing
*/
void
spdxtool_util_set_uri_root(pkgconf_client_t *client, const char *uri_root)
{
spdxtool_util_set_key(client, "spdx_uri_root", uri_root, "https://github.com/pkgconf/pkgconf");
}
/*
* !doc
*
* .. c:function:: const char *spdxtool_util_get_uri_root(pkgconf_client_t *client)
*
* Get current URI
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :return: URI or NULL
*/
const char *
spdxtool_util_get_uri_root(pkgconf_client_t *client)
{
return pkgconf_tuple_find_global(client, "spdx_uri_root");
}
/*
* !doc
*
* .. c:function:: void spdxtool_util_set_spdx_version(pkgconf_client_t *client, const char *spdx_version)
*
* Set current SPDX SBOM Spec version. If not set it's 3.0.1
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param char* spdx_version: SPDX specification version.
* :return: nothing
*/
void
spdxtool_util_set_spdx_version(pkgconf_client_t *client, const char *spdx_version)
{
spdxtool_util_set_key(client, "spdx_version", spdx_version, "3.0.1");
}
/*
* !doc
*
* .. c:function:: const char *spdxtool_util_get_spdx_version(pkgconf_client_t *client)
*
* Get SPDX SBOM specification version in use
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :return: Spec version
*/
const char *
spdxtool_util_get_spdx_version(pkgconf_client_t *client)
{
return pkgconf_tuple_find_global(client, "spdx_version");
}
/*
* !doc
*
* .. c:function:: void spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license)
*
* Under which license SBOM is released. License string should be in
* SPDX style. Something like: FreeBSD-DOC, CC0-1.0 or MIT
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param const char *spdx_license: SPDX compatible license
* :return: nothing
*/
void
spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license)
{
spdxtool_util_set_key(client, "spdx_license", spdx_license, "CC0-1.0");
}
/*
* !doc
*
* .. c:function:: const char *spdxtool_util_get_spdx_license(pkgconf_client_t *client)
*
* Get license which SBOM is release in
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :return: SPDX license
*/
const char *
spdxtool_util_get_spdx_license(pkgconf_client_t *client)
{
return pkgconf_tuple_find_global(client, "spdx_license");
}
static size_t last_id = 0;
/*
* !doc
*
* .. c:function:: char *spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, char *part)
*
* Get spdxId with current URI.
* URI is lookg like https://test/part/1
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param char *part: Addition subdir part before number
* :return: URI
*/
char *
spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, char *part)
{
const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client);
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_join(&current_uri, '/', global_xsd_any_uri, part, NULL);
pkgconf_buffer_append_fmt(&current_uri, "/" SIZE_FMT_SPECIFIER, ++last_id);
return pkgconf_buffer_freeze(&current_uri);
}
/*
* !doc
*
* .. c:function:: char *spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, char *part, char *string_id)
*
* Get string id URI
* looks something like: https://test/part/string_id
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param char* part: subdir part of URI.
* :param char* string_id: String ID.
* :return: URI
*/
char *
spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, char *part, char *string_id)
{
const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client);
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_join(&current_uri, '/', global_xsd_any_uri, part, string_id, NULL);
return pkgconf_buffer_freeze(&current_uri);
}
/*
* !doc
*
* .. c:function:: char *spdxtool_util_get_iso8601_time(time_t *wanted_time)
*
* Get ISO8601 time string
*
* :param time_t *wanted_time: Time to be converted
* :return: Time string in ISO8601 format
*/
char *
spdxtool_util_get_iso8601_time(time_t *wanted_time)
{
char buf[PKGCONF_ITEM_SIZE];
struct tm *tm_info = gmtime(wanted_time);
if(!wanted_time)
return NULL;
/* ISO8601 time with Z at the end */
strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", tm_info);
return strdup(buf);
}
/*
* !doc
*
* .. c:function:: char *spdxtool_util_get_current_iso8601_time()
*
* Get ISO8601 current timestamp
*
* :return: Time string in ISO8601 format
*/
char *
spdxtool_util_get_current_iso8601_time()
{
time_t now;
time(&now);
return spdxtool_util_get_iso8601_time(&now);
}
/*
* !doc
*
* .. c:function:: char *spdxtool_util_string_correction(char *str)
*
* Lowercase string and change spaces to '_'
*
* :param char *str: String to be converted
* :return: Converted string
*/
char *
spdxtool_util_string_correction(char *str)
{
char *ptr = str;
/* Lowecase string and make spaces '_' */
for ( ; *ptr; ++ptr)
{
*ptr = tolower(*ptr);
if(isspace((unsigned char) *ptr))
{
*ptr = '_';
}
}
return str;
}

View File

@ -1,123 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 The FreeBSD Foundation
*
* Portions of this software were developed by
* Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
* the FreeBSD Foundation
*/
#ifndef CLI__SPDXTOOL__UTIL_H
#define CLI__SPDXTOOL__UTIL_H
#include <libpkgconf/libpkgconf.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct spdxtool_core_agent_
{
int refcount;
char *spdx_id;
char *type;
char *creation_info;
char *name;
} spdxtool_core_agent_t;
typedef struct spdxtool_core_creation_info_
{
int refcount;
char *id;
char *type;
char *created;
char *created_by;
char *created_using;
const char *spec_version;
} spdxtool_core_creation_info_t;
typedef struct spdxtool_core_spdx_document
{
int refcount;
char *type;
char *spdx_id;
char *creation_info;
char *agent;
pkgconf_list_t licenses;
pkgconf_list_t element;
pkgconf_list_t rootElement;
} spdxtool_core_spdx_document_t;
typedef struct spdxtool_software_sbom_
{
int refcount;
char *spdx_id;
char *type;
char *creation_info;
char *sbom_type;
spdxtool_core_spdx_document_t *spdx_document;
pkgconf_pkg_t *rootElement;
} spdxtool_software_sbom_t;
typedef struct spdxtool_simplelicensing_license_expression_
{
int refcount;
char *type;
char *spdx_id;
char *license_expression;
} spdxtool_simplelicensing_license_expression_t;
typedef struct spdxtool_core_relationship_
{
int refcount;
char *type;
char *spdx_id;
char *creation_info;
char *from;
char *to;
char *relationship_type;
} spdxtool_core_relationship_t;
void
spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default);
void
spdxtool_util_set_uri_root(pkgconf_client_t *client, const char *uri_root);
const char *
spdxtool_util_get_uri_root(pkgconf_client_t *client);
void
spdxtool_util_set_spdx_version(pkgconf_client_t *client, const char *spdx_version);
const char *
spdxtool_util_get_spdx_version(pkgconf_client_t *client);
void
spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license);
const char *
spdxtool_util_get_spdx_license(pkgconf_client_t *client);
char *
spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, char *part);
char *
spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, char *part, char *string_id);
char *
spdxtool_util_get_iso8601_time(time_t *wanted_time);
char *
spdxtool_util_get_current_iso8601_time();
char *
spdxtool_util_string_correction(char *str);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -12,7 +12,7 @@ dnl implied. In no event shall the authors be liable for any damages arising
dnl from the use of this software.
AC_PREREQ([2.71])
AC_INIT([pkgconf],[2.5.1],[https://github.com/pkgconf/pkgconf/issues/new])
AC_INIT([pkgconf],[2.1.0],[https://github.com/pkgconf/pkgconf/issues/new])
AC_CONFIG_SRCDIR([cli/main.c])
AC_CONFIG_MACRO_DIR([m4])
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
@ -23,9 +23,7 @@ AX_CHECK_COMPILE_FLAG([-std=gnu99], [CFLAGS="$CFLAGS -std=gnu99"], [
])
AC_CONFIG_HEADERS([libpkgconf/config.h])
AC_CHECK_DECLS([strlcpy, strlcat, strndup], [], [], [[#include <string.h>]])
AC_CHECK_DECLS([pledge, unveil], [], [], [[#include <unistd.h>]])
AC_CHECK_DECLS([readlinkat], [], [], [[#include <unistd.h>]])
AC_CHECK_DECLS([reallocarray], [], [], [[#include <stdlib.h>]])
AC_CHECK_DECLS([reallocarray])
AC_CHECK_HEADERS([sys/stat.h])
AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@ -48,21 +46,13 @@ AC_SUBST([PKG_DEFAULT_PATH])
AC_ARG_WITH([system-libdir],[AS_HELP_STRING([--with-system-libdir],[specify the
system library directory (default LIBDIR)])],
[SYSTEM_LIBDIR="$withval"], [
AC_MSG_WARN([--with-system-libdir is not set, assuming ${libdir}])
AC_MSG_WARN([It is important that this value be properly set for correct behavior!])
SYSTEM_LIBDIR="${libdir}"
])
SYSTEM_LIBDIR="$withval", SYSTEM_LIBDIR="${libdir}")
AC_SUBST([SYSTEM_LIBDIR])
AC_ARG_WITH([system-includedir],[AS_HELP_STRING([--with-system-includedir],[specify the
system include directory (default INCLUDEDIR)])],
[SYSTEM_INCLUDEDIR="$withval"], [
AC_MSG_WARN([--with-system-includedir is not set, assuming ${includedir}])
AC_MSG_WARN([It is important that this value be properly set for correct behavior!])
SYSTEM_INCLUDEDIR="${includedir}"
])
SYSTEM_INCLUDEDIR="$withval", SYSTEM_INCLUDEDIR="${includedir}")
AC_SUBST([SYSTEM_INCLUDEDIR])
@ -73,14 +63,3 @@ AC_PROG_LN_S
AC_CONFIG_FILES([Makefile Kyuafile libpkgconf.pc tests/Kyuafile tests/test_env.sh])
AC_OUTPUT
cat << EOF
Build configuration:
Default personality search paths: ${PERSONALITY_PATH}
Default package search paths: ${PKG_DEFAULT_PATH}
Default include search paths: ${SYSTEM_INCLUDEDIR}
Default library search paths: ${SYSTEM_LIBDIR}
Incorrect paths may result in unexpected behavior from pkgconf.
EOF

View File

@ -51,7 +51,7 @@ The `dependency` module provides support for building `dependency lists` (the ba
.. c:function:: void pkgconf_dependency_free(pkgconf_list_t *list)
Release a dependency list and its child dependency nodes.
Release a dependency list and it's child dependency nodes.
:param pkgconf_list_t* list: The dependency list to release.
:return: nothing

View File

@ -7,8 +7,6 @@ Name: libpkgconf
Description: a library for accessing and manipulating development framework configuration
URL: https://gitea.treehouse.systems/ariadne/pkgconf
License: ISC
License.file: https://raw.githubusercontent.com/pkgconf/pkgconf/refs/heads/master/COPYING
Source: https://github.com/pkgconf/pkgconf
Version: @PACKAGE_VERSION@
CFlags: -I${includedir}/pkgconf
Libs: -L${libdir} -lpkgconf

View File

@ -59,10 +59,7 @@ pkgconf_argv_free(char **argv)
int
pkgconf_argv_split(const char *src, int *argc, char ***argv)
{
char *buf = calloc(1, strlen(src) + 1);
if (buf == NULL)
return -1;
char *buf = malloc(strlen(src) + 1);
const char *src_iter;
char *dst_iter;
int argc_count = 0;
@ -73,13 +70,9 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
src_iter = src;
dst_iter = buf;
*argv = calloc(argv_size, sizeof (void *));
if (*argv == NULL)
{
free(buf);
return -1;
}
memset(buf, 0, strlen(src) + 1);
*argv = calloc(argv_size, sizeof (void *));
(*argv)[argc_count] = dst_iter;
while (*src_iter)

View File

@ -17,7 +17,11 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <libpkgconf/stdinc.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <libpkgconf/bsdstubs.h>
#include <libpkgconf/config.h>
@ -117,28 +121,6 @@ strndup(const char *src, size_t len)
}
#endif
#if !HAVE_DECL_PLEDGE
static inline int
pledge(const char *promises, const char *execpromises)
{
(void) promises;
(void) execpromises;
return 0;
}
#endif
#if !HAVE_DECL_UNVEIL
static inline int
unveil(const char *path, const char *permissions)
{
(void) path;
(void) permissions;
return 0;
}
#endif
size_t
pkgconf_strlcpy(char *dst, const char *src, size_t siz)
{
@ -176,15 +158,3 @@ pkgconf_reallocarray(void *ptr, size_t m, size_t n)
{
return reallocarray(ptr, m, n);
}
int
pkgconf_pledge(const char *promises, const char *execpromises)
{
return pledge(promises, execpromises);
}
int
pkgconf_unveil(const char *path, const char *permissions)
{
return unveil(path, permissions);
}

View File

@ -26,8 +26,6 @@ PKGCONF_API extern size_t pkgconf_strlcpy(char *dst, const char *src, size_t siz
PKGCONF_API extern size_t pkgconf_strlcat(char *dst, const char *src, size_t siz);
PKGCONF_API extern char *pkgconf_strndup(const char *src, size_t len);
PKGCONF_API extern void *pkgconf_reallocarray(void *ptr, size_t m, size_t n);
PKGCONF_API extern int pkgconf_pledge(const char *promises, const char *execpromises);
PKGCONF_API extern int pkgconf_unveil(const char *path, const char *permissions);
#ifdef __cplusplus
}

View File

@ -1,246 +0,0 @@
/*
* buffer.c
* dynamically-managed buffers
*
* Copyright (c) 2024 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `buffer` module
* ==========================
*
* The libpkgconf `buffer` module contains the functions related to managing
* dynamically-allocated buffers.
*/
static inline size_t
target_allocation_size(size_t target_size)
{
return 4096 + (4096 * (target_size / 4096));
}
#if 0
static void
buffer_debug(pkgconf_buffer_t *buffer)
{
for (char *c = buffer->base; c <= buffer->end; c++) {
fprintf(stderr, "%02x ", (unsigned char) *c);
}
fprintf(stderr, "\n");
}
#endif
void
pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
{
size_t needed = strlen(text) + 1;
size_t newsize = pkgconf_buffer_len(buffer) + needed;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
/* XXX: silently failing here is antisocial */
if (newbase == NULL)
return;
char *newend = newbase + pkgconf_buffer_len(buffer);
pkgconf_strlcpy(newend, text, needed);
buffer->base = newbase;
buffer->end = newend + (needed - 1);
*buffer->end = '\0';
}
void
pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list src_va)
{
va_list va;
char *buf;
size_t needed;
va_copy(va, src_va);
needed = vsnprintf(NULL, 0, fmt, va) + 1;
va_end(va);
buf = malloc(needed);
va_copy(va, src_va);
vsnprintf(buf, needed, fmt, va);
va_end(va);
pkgconf_buffer_append(buffer, buf);
free(buf);
}
void
pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
pkgconf_buffer_append_vfmt(buffer, fmt, va);
va_end(va);
}
void
pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte)
{
size_t newsize = pkgconf_buffer_len(buffer) + 1;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
/* XXX: silently failing here remains antisocial */
if (newbase == NULL)
return;
char *newend = newbase + newsize;
*(newend - 1) = byte;
*newend = '\0';
buffer->base = newbase;
buffer->end = newend;
}
void
pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer)
{
size_t newsize = pkgconf_buffer_len(buffer) - 1;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
buffer->base = newbase;
buffer->end = newbase + newsize;
*(buffer->end) = '\0';
}
void
pkgconf_buffer_finalize(pkgconf_buffer_t *buffer)
{
free(buffer->base);
buffer->base = buffer->end = NULL;
}
void
pkgconf_buffer_fputs(pkgconf_buffer_t *buffer, FILE *out)
{
if (pkgconf_buffer_len(buffer) != 0)
fputs(pkgconf_buffer_str(buffer), out);
fputc('\n', out);
}
void
pkgconf_buffer_vjoin(pkgconf_buffer_t *buffer, char delim, va_list src_va)
{
va_list va;
const char *arg;
va_copy(va, src_va);
while ((arg = va_arg(va, const char *)) != NULL)
{
if (pkgconf_buffer_str(buffer) != NULL)
pkgconf_buffer_push_byte(buffer, delim);
pkgconf_buffer_append(buffer, arg);
}
va_end(va);
}
// NOTE: due to C's rules regarding promotion in variable args and permissible variables, delim must
// be an int here.
void
pkgconf_buffer_join(pkgconf_buffer_t *buffer, int delim, ...)
{
va_list va;
va_start(va, delim);
pkgconf_buffer_vjoin(buffer, (char)delim, va);
va_end(va);
}
bool
pkgconf_buffer_contains(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle)
{
const char *haystack_str = pkgconf_buffer_str_or_empty(haystack);
const char *needle_str = pkgconf_buffer_str_or_empty(needle);
return strstr(haystack_str, needle_str) != NULL;
}
bool
pkgconf_buffer_contains_byte(const pkgconf_buffer_t *haystack, char needle)
{
const char *haystack_str = pkgconf_buffer_str_or_empty(haystack);
return strchr(haystack_str, needle) != NULL;
}
bool
pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle)
{
const char *haystack_str = pkgconf_buffer_str_or_empty(haystack);
const char *needle_str = pkgconf_buffer_str_or_empty(needle);
if (pkgconf_buffer_len(haystack) != pkgconf_buffer_len(needle))
return false;
return memcmp(haystack_str, needle_str, pkgconf_buffer_len(haystack)) == 0;
}
void
pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pattern, const char *value)
{
const char *iter = src->base;
size_t pattern_len = strlen(pattern);
if (!pkgconf_buffer_len(src))
return;
if (!pattern_len)
{
pkgconf_buffer_append(dest, pkgconf_buffer_str(src));
return;
}
while (iter < src->end)
{
if ((size_t)(src->end - iter) >= pattern_len && !memcmp(iter, pattern, pattern_len))
{
pkgconf_buffer_append(dest, value);
iter += pattern_len;
}
else
pkgconf_buffer_push_byte(dest, *iter++);
}
}
void
pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans)
{
const char *p = pkgconf_buffer_str(src);
if (!pkgconf_buffer_len(src))
return;
for (; *p; p++)
{
if (pkgconf_span_contains((unsigned char) *p, spans, nspans))
pkgconf_buffer_push_byte(dest, '\\');
pkgconf_buffer_push_byte(dest, *p);
}
}

View File

@ -60,22 +60,17 @@ trace_path_list(const pkgconf_client_t *client, const char *desc, pkgconf_list_t
void
pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
{
pkgconf_path_build_from_environ(client, "PKG_CONFIG_PATH", NULL, &client->dir_list, true);
pkgconf_path_build_from_environ("PKG_CONFIG_PATH", NULL, &client->dir_list, true);
if (!(client->flags & PKGCONF_PKG_PKGF_ENV_ONLY))
{
pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER;
const pkgconf_list_t *prepend_list = &personality->dir_list;
#ifdef _WIN32
(void) pkgconf_path_build_from_registry(HKEY_CURRENT_USER, &client->dir_list, true);
(void) pkgconf_path_build_from_registry(HKEY_LOCAL_MACHINE, &client->dir_list, true);
#endif
if (pkgconf_client_getenv(client, "PKG_CONFIG_LIBDIR") != NULL)
if (getenv("PKG_CONFIG_LIBDIR") != NULL)
{
/* PKG_CONFIG_LIBDIR= should empty the search path entirely. */
(void) pkgconf_path_build_from_environ(client, "PKG_CONFIG_LIBDIR", NULL, &dir_list, true);
(void) pkgconf_path_build_from_environ("PKG_CONFIG_LIBDIR", NULL, &dir_list, true);
prepend_list = &dir_list;
}
@ -87,7 +82,7 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers
/*
* !doc
*
* .. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler)
* .. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
*
* Initialise a pkgconf client object.
*
@ -95,16 +90,11 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers
* :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
* :param void* error_handler_data: user data passed to optional error handler
* :param pkgconf_cross_personality_t* personality: the cross-compile personality to use for defaults
* :param void* client_data: user data associated with the client
* :param pkgconf_environ_lookup_handler_func_t environ_lookup_handler: the lookup handler to use for environment variables
* :return: nothing
*/
void
pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler)
pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
{
client->personality = personality;
client->client_data = client_data;
client->environ_lookup_handler = environ_lookup_handler;
client->error_handler_data = error_handler_data;
client->error_handler = error_handler;
client->auditf = NULL;
@ -116,9 +106,6 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
pkgconf_client_set_trace_handler(client, NULL, NULL);
#endif
if (client->unveil_handler == NULL)
pkgconf_client_set_unveil_handler(client, NULL);
pkgconf_client_set_error_handler(client, error_handler, error_handler_data);
pkgconf_client_set_warn_handler(client, NULL, NULL);
@ -126,38 +113,36 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
pkgconf_client_set_buildroot_dir(client, NULL);
pkgconf_client_set_prefix_varname(client, NULL);
if(pkgconf_client_getenv(client, "PKG_CONFIG_SYSTEM_LIBRARY_PATH") == NULL)
if(getenv("PKG_CONFIG_SYSTEM_LIBRARY_PATH") == NULL)
pkgconf_path_copy_list(&client->filter_libdirs, &personality->filter_libdirs);
else
pkgconf_path_build_from_environ(client, "PKG_CONFIG_SYSTEM_LIBRARY_PATH", NULL, &client->filter_libdirs, false);
pkgconf_path_build_from_environ("PKG_CONFIG_SYSTEM_LIBRARY_PATH", NULL, &client->filter_libdirs, false);
if(pkgconf_client_getenv(client, "PKG_CONFIG_SYSTEM_INCLUDE_PATH") == NULL)
if(getenv("PKG_CONFIG_SYSTEM_INCLUDE_PATH") == NULL)
pkgconf_path_copy_list(&client->filter_includedirs, &personality->filter_includedirs);
else
pkgconf_path_build_from_environ(client, "PKG_CONFIG_SYSTEM_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("PKG_CONFIG_SYSTEM_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
/* GCC uses these environment variables to define system include paths, so we should check them. */
#ifdef __HAIKU__
pkgconf_path_build_from_environ(client, "BELIBRARIES", NULL, &client->filter_libdirs, false);
pkgconf_path_build_from_environ("BELIBRARIES", NULL, &client->filter_libdirs, false);
#else
pkgconf_path_build_from_environ(client, "LIBRARY_PATH", NULL, &client->filter_libdirs, false);
pkgconf_path_build_from_environ("LIBRARY_PATH", NULL, &client->filter_libdirs, false);
#endif
pkgconf_path_build_from_environ(client, "CPATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ(client, "C_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ(client, "CPLUS_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ(client, "OBJC_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("CPATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("C_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("CPLUS_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("OBJC_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
#ifdef _WIN32
/* also use the path lists that MSVC uses on windows */
pkgconf_path_build_from_environ(client, "INCLUDE", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("INCLUDE", NULL, &client->filter_includedirs, false);
#endif
PKGCONF_TRACE(client, "initialized client @%p", client);
trace_path_list(client, "filtered library paths", &client->filter_libdirs);
trace_path_list(client, "filtered include paths", &client->filter_includedirs);
client->output = pkgconf_output_default();
}
/*
@ -170,34 +155,17 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
* :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
* :param void* error_handler_data: user data passed to optional error handler
* :param pkgconf_cross_personality_t* personality: cross-compile personality to use
* :param void* client_data: user data associated with the client
* :param pkgconf_environ_lookup_handler_func_t environ_lookup_handler: the lookup handler to use for environment variables
* :return: A pkgconf client object.
* :rtype: pkgconf_client_t*
*/
pkgconf_client_t *
pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler)
pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
{
pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t));
if (out == NULL)
return NULL;
pkgconf_client_init(out, error_handler, error_handler_data, personality, client_data, environ_lookup_handler);
pkgconf_client_init(out, error_handler, error_handler_data, personality);
return out;
}
static void
unref_preload_list(pkgconf_client_t *client)
{
pkgconf_node_t *n, *tn;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(client->preloaded_pkgs.head, tn, n)
{
pkgconf_pkg_t *pkg = n->data;
pkgconf_pkg_unref(client, pkg);
}
}
/*
* !doc
*
@ -213,8 +181,6 @@ pkgconf_client_deinit(pkgconf_client_t *client)
{
PKGCONF_TRACE(client, "deinit @%p", client);
unref_preload_list(client);
if (client->prefix_varname != NULL)
free(client->prefix_varname);
@ -230,8 +196,6 @@ pkgconf_client_deinit(pkgconf_client_t *client)
pkgconf_tuple_free_global(client);
pkgconf_path_free(&client->dir_list);
pkgconf_cache_free(client);
memset(client, '\0', sizeof(*client));
}
/*
@ -292,7 +256,7 @@ pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir
PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : "<default>");
pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : "");
pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : "/");
}
/*
@ -354,32 +318,14 @@ pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot
bool
pkgconf_error(const pkgconf_client_t *client, const char *format, ...)
{
char *errbuf;
ssize_t msgsize = 0;
bool ret;
char errbuf[PKGCONF_BUFSIZE];
va_list va;
va_start(va, format);
msgsize = vsnprintf(NULL, 0, format, va);
vsnprintf(errbuf, sizeof errbuf, format, va);
va_end(va);
if (msgsize < 0)
return false;
msgsize++;
errbuf = calloc(1, msgsize);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, msgsize, format, va);
va_end(va);
ret = client->error_handler(errbuf, client, client->error_handler_data);
free(errbuf);
return ret;
return client->error_handler(errbuf, client, client->error_handler_data);
}
/*
@ -397,32 +343,14 @@ pkgconf_error(const pkgconf_client_t *client, const char *format, ...)
bool
pkgconf_warn(const pkgconf_client_t *client, const char *format, ...)
{
char *errbuf;
ssize_t msgsize = 0;
bool ret;
char errbuf[PKGCONF_BUFSIZE];
va_list va;
va_start(va, format);
msgsize = vsnprintf(NULL, 0, format, va);
vsnprintf(errbuf, sizeof errbuf, format, va);
va_end(va);
if (msgsize < 0)
return false;
msgsize++;
errbuf = calloc(1, msgsize);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, msgsize, format, va);
va_end(va);
ret = client->warn_handler(errbuf, client, client->warn_handler_data);
free(errbuf);
return ret;
return client->warn_handler(errbuf, client, client->warn_handler_data);
}
/*
@ -443,56 +371,22 @@ pkgconf_warn(const pkgconf_client_t *client, const char *format, ...)
bool
pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...)
{
char prefix[PKGCONF_ITEM_SIZE];
char *errbuf = NULL;
ssize_t errlen;
char *finalbuf = NULL;
ssize_t finallen;
bool ret;
char errbuf[PKGCONF_BUFSIZE];
size_t len;
va_list va;
if (client == NULL || client->trace_handler == NULL)
return false;
snprintf(prefix, sizeof prefix, "%s:" SIZE_FMT_SPECIFIER " [%s]:", filename, lineno, funcname);
len = snprintf(errbuf, sizeof errbuf, "%s:" SIZE_FMT_SPECIFIER " [%s]: ", filename, lineno, funcname);
va_start(va, format);
errlen = vsnprintf(NULL, 0, format, va);
vsnprintf(errbuf + len, sizeof(errbuf) - len, format, va);
va_end(va);
if (errlen < 0)
return false;
pkgconf_strlcat(errbuf, "\n", sizeof errbuf);
errlen++;
errbuf = calloc(1, errlen);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, errlen, format, va);
va_end(va);
finallen = snprintf(NULL, 0, "%s %s\n", prefix, errbuf);
if (finallen < 0)
{
free(errbuf);
return false;
}
finallen++;
finalbuf = calloc(1, finallen);
if (finalbuf == NULL)
{
free(errbuf);
return false;
}
snprintf(finalbuf, finallen, "%s %s\n", prefix, errbuf);
ret = client->trace_handler(finalbuf, client, client->trace_handler_data);
free(errbuf);
free(finalbuf);
return ret;
return client->trace_handler(errbuf, client, client->trace_handler_data);
}
/*
@ -518,14 +412,6 @@ pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, v
return true;
}
static void
default_unveil_handler(const pkgconf_client_t *client, const char *path, const char *permissions)
{
(void) client;
(void) path;
(void) permissions;
}
/*
* !doc
*
@ -685,45 +571,6 @@ pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler
}
}
/*
* !doc
*
* .. c:function:: pkgconf_client_get_unveil_handler(const pkgconf_client_t *client)
*
* Returns the unveil handler if one is set, else ``NULL``.
*
* :param pkgconf_client_t* client: The client object to get the unveil handler from.
* :return: a function pointer to the error handler or ``NULL``
*/
pkgconf_unveil_handler_func_t
pkgconf_client_get_unveil_handler(const pkgconf_client_t *client)
{
return client->unveil_handler;
}
/*
* !doc
*
* .. c:function:: pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler)
*
* Sets an unveil handler on a client object or uninstalls one if set to ``NULL``.
*
* :param pkgconf_client_t* client: The client object to set the error handler on.
* :param pkgconf_unveil_handler_func_t unveil_handler: The unveil handler to set.
* :return: nothing
*/
void
pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler)
{
client->unveil_handler = unveil_handler;
if (client->unveil_handler == NULL)
{
PKGCONF_TRACE(client, "installing default unveil handler");
client->unveil_handler = default_unveil_handler;
}
}
#ifndef PKGCONF_LITE
/*
* !doc
@ -766,131 +613,3 @@ pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler
}
}
#endif
/*
* !doc
*
* .. c:function:: bool pkgconf_client_preload_one(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
*
* Adds a package to the preloaded packages set.
*
* :param pkgconf_client_t* client: The client object for preloading.
* :param pkgconf_pkg_t* pkg: The package to preload.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_client_preload_one(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
{
PKGCONF_TRACE(client, "preloading pkg %s@%p", pkg->id, pkg);
pkg->flags |= PKGCONF_PKG_PROPF_PRELOADED;
pkgconf_pkg_ref(client, pkg);
pkgconf_node_insert_tail(&pkg->preload_node, pkg, &client->preloaded_pkgs);
return true;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
*
* Loads a pkg-config file into the preloaded packages set.
*
* :param pkgconf_client_t* client: The client object for preloading.
* :param char* path: The path to the pkg-config file to preload.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
{
pkgconf_pkg_t *pkg = pkgconf_pkg_new_from_path(client, path, PKGCONF_PKG_PROPF_PRELOADED);
if (pkg == NULL)
return false;
return pkgconf_client_preload_one(client, pkg);
}
/*
* !doc
*
* .. c:function:: bool pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env)
*
* Loads zero or more pkg-config files specified in the given environmental
* variable.
*
* :param pkgconf_client_t* client: The client object for preloading.
* :param char* environ: The environment variable to use for preloading.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env)
{
const char *data;
pkgconf_list_t pathlist = PKGCONF_LIST_INITIALIZER;
pkgconf_node_t *n;
bool ret = true;
data = getenv(env);
if (data == NULL)
return true;
pkgconf_path_split(data, &pathlist, true);
PKGCONF_FOREACH_LIST_ENTRY(pathlist.head, n)
{
pkgconf_path_t *pn = n->data;
ret = pkgconf_client_preload_path(client, pn->path);
if (!ret)
break;
}
pkgconf_path_free(&pathlist);
return ret;
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output)
*
* Sets the client's output object. This is mainly a convenience function for clients
* to use.
*
* :param pkgconf_client_t* client: The client object to set the output object for.
* :param pkgconf_output_t* output: The output object to use.
* :return: nothing
*/
void
pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output)
{
client->output = output;
}
/*
* !doc
*
* .. c:function:: const char *pkgconf_client_getenv(const pkgconf_client_t *client, const char *key)
*
* Looks up an environmental variable which may be mocked, otherwise fetches
* from the main environment.
*
* :param pkgconf_client_t* client: yhe client object to use for looking up environmental variables.
* :param char* key: the environmental variable to look up.
* :return: the environmental variable contents else NULL
* :rtype: const char*
*/
const char *
pkgconf_client_getenv(const pkgconf_client_t *client, const char *key)
{
if (client != NULL && client->environ_lookup_handler != NULL)
return client->environ_lookup_handler(client, key);
return getenv(key);
}

View File

@ -24,12 +24,6 @@
/* Define to 1 if you have the `reallocarray' function. */
#mesondefine HAVE_DECL_REALLOCARRAY
/* Define to 1 if you have the `pledge' function. */
#mesondefine HAVE_DECL_PLEDGE
/* Define to 1 if you have the `unveil' function. */
#mesondefine HAVE_DECL_UNVEIL
/* Name of package */
#mesondefine PACKAGE
@ -72,8 +66,3 @@
#mesondefine SYSTEM_INCLUDEDIR
#mesondefine SYSTEM_LIBDIR
#mesondefine PERSONALITY_PATH
/* Enable Solaris extensions. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif

View File

@ -131,9 +131,6 @@ pkgconf_dependency_addraw(pkgconf_client_t *client, pkgconf_list_t *list, const
pkgconf_dependency_t *dep;
dep = calloc(1, sizeof(pkgconf_dependency_t));
if (dep == NULL)
return NULL;
dep->package = pkgconf_strndup(package, package_sz);
if (version_sz != 0)
@ -211,9 +208,6 @@ pkgconf_dependency_free_one(pkgconf_dependency_t *dep)
if (dep->version != NULL)
free(dep->version);
if (dep->why != NULL)
free(dep->why);
free(dep);
}
@ -268,7 +262,7 @@ pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep)
*
* .. c:function:: void pkgconf_dependency_free(pkgconf_list_t *list)
*
* Release a dependency list and its child dependency nodes.
* Release a dependency list and it's child dependency nodes.
*
* :param pkgconf_list_t* list: The dependency list to release.
* :return: nothing
@ -310,29 +304,19 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
parse_state_t state = OUTSIDE_MODULE;
pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY;
char cmpname[PKGCONF_ITEM_SIZE];
size_t package_sz = 0, version_sz = 0, buf_sz = 0;
char *buf;
char *start = NULL;
char *ptr = NULL;
char buf[PKGCONF_BUFSIZE];
size_t package_sz = 0, version_sz = 0;
char *start = buf;
char *ptr = buf;
char *vstart = NULL;
char *package = NULL, *version = NULL;
char *cnameptr = cmpname;
char *cnameend = cmpname + PKGCONF_ITEM_SIZE - 1;
if (!*depends)
return;
memset(cmpname, '\0', sizeof cmpname);
buf_sz = (strlen(depends) * 2) + 1;
buf = calloc(1, buf_sz);
if (buf == NULL)
return;
pkgconf_strlcpy(buf, depends, buf_sz);
pkgconf_strlcat(buf, " ", buf_sz);
start = ptr = buf;
pkgconf_strlcpy(buf, depends, sizeof buf);
pkgconf_strlcat(buf, " ", sizeof buf);
while (*ptr)
{
@ -402,16 +386,15 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
break;
case INSIDE_OPERATOR:
if (PKGCONF_IS_OPERATOR_CHAR(*ptr))
if (!PKGCONF_IS_OPERATOR_CHAR(*ptr))
{
if (cnameptr < cnameend)
*cnameptr++ = *ptr;
break;
state = AFTER_OPERATOR;
compare = pkgconf_pkg_comparator_lookup_by_name(cmpname);
}
else if (cnameptr < cnameend)
*cnameptr++ = *ptr;
state = AFTER_OPERATOR;
compare = pkgconf_pkg_comparator_lookup_by_name(cmpname);
// fallthrough
break;
case AFTER_OPERATOR:
if (!isspace((unsigned char)*ptr))
@ -443,8 +426,6 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
ptr++;
}
free(buf);
}
/*
@ -489,9 +470,6 @@ pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *de
pkgconf_dependency_t *new_dep;
new_dep = calloc(1, sizeof(pkgconf_dependency_t));
if (new_dep == NULL)
return NULL;
new_dep->package = strdup(dep->package);
if (dep->version != NULL)

View File

@ -2,7 +2,7 @@
* fileio.c
* File reading utilities
*
* Copyright (c) 2012, 2025 pkgconf authors (see AUTHORS).
* Copyright (c) 2012 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -16,13 +16,18 @@
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
bool
pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
char *
pkgconf_fgetline(char *line, size_t size, FILE *stream)
{
char *s = line;
char *end = line + size - 2;
bool quoted = false;
int c = '\0', c2;
while ((c = getc(stream)) != EOF)
if (s == NULL)
return NULL;
while (s < end && (c = getc(stream)) != EOF)
{
if (c == '\\' && !quoted)
{
@ -36,11 +41,11 @@ pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
do {
c = getc(stream);
} while (c != '\n' && c != EOF);
pkgconf_buffer_push_byte(buffer, c);
*s++ = c;
break;
}
else
pkgconf_buffer_push_byte(buffer, c);
*s++ = c;
quoted = false;
continue;
@ -61,14 +66,14 @@ pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
}
else
{
pkgconf_buffer_push_byte(buffer, c);
*s++ = c;
}
break;
}
else if (c == '\r')
{
pkgconf_buffer_push_byte(buffer, '\n');
*s++ = '\n';
if ((c2 = getc(stream)) == '\n')
{
@ -94,20 +99,26 @@ pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
else
{
if (quoted) {
pkgconf_buffer_push_byte(buffer, '\\');
*s++ = '\\';
quoted = false;
}
pkgconf_buffer_push_byte(buffer, c);
*s++ = c;
}
}
if (c == EOF && (s == line || ferror(stream)))
return NULL;
*s = '\0';
/* Remove newline character. */
if (pkgconf_buffer_lastc(buffer) == '\n')
pkgconf_buffer_trim_byte(buffer);
if (s > line && *(--s) == '\n') {
*s = '\0';
if (pkgconf_buffer_lastc(buffer) == '\r')
pkgconf_buffer_trim_byte(buffer);
if (s > line && *(--s) == '\r')
*s = '\0';
}
return !(c == EOF || ferror(stream));
return line;
}

View File

@ -32,31 +32,6 @@ struct pkgconf_fragment_check {
size_t len;
};
static inline bool
pkgconf_fragment_is_greedy(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-F", 2},
{"-I", 2},
{"-L", 2},
{"-D", 2},
{"-l", 2},
};
if (*string != '-')
return false;
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
{
/* if it is the bare flag, then we want the next token to be the data */
if (!*(string + check_fragments[i].len))
return true;
}
return false;
}
static inline bool
pkgconf_fragment_is_unmergeable(const char *string)
{
@ -77,7 +52,6 @@ pkgconf_fragment_is_unmergeable(const char *string)
{"-nostdinc", 9},
{"-nostdlibinc", 12},
{"-nobuiltininc", 13},
{"-nodefaultlibs", 14},
};
if (*string != '-')
@ -106,38 +80,6 @@ pkgconf_fragment_should_munge(const char *string, const char *sysroot_dir)
return false;
}
static inline bool
pkgconf_fragment_is_groupable(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-Wl,--start-group", 17},
{"-framework", 10},
{"-isystem", 8},
{"-idirafter", 10},
{"-include", 8},
};
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
return true;
return false;
}
static inline bool
pkgconf_fragment_is_terminus(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-Wl,--end-group", 15},
};
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
return true;
return false;
}
static inline bool
pkgconf_fragment_is_special(const char *string)
{
@ -178,38 +120,6 @@ pkgconf_fragment_copy_munged(const pkgconf_client_t *client, const char *source,
return strdup(mungebuf);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
*
* Adds a `fragment` of text to a `fragment list` directly without interpreting it.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The fragment list.
* :param char type: The type of the fragment.
* :param char* data: The data of the fragment.
* :param bool tail: Whether to place the fragment at the beginning of the list or the end.
* :return: nothing
*/
void
pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
{
pkgconf_fragment_t *frag;
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = type;
frag->data = pkgconf_fragment_copy_munged(client, data, 0);
if (tail)
{
pkgconf_node_insert_tail(&frag->iter, frag, list);
return;
}
pkgconf_node_insert(&frag->iter, frag, list);
}
/*
* !doc
*
@ -226,41 +136,15 @@ pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, ch
void
pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
{
pkgconf_list_t *target = list;
pkgconf_fragment_t *frag;
if (*string == '\0')
return;
if (list->tail != NULL && list->tail->data != NULL &&
!(client->flags & PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS))
{
pkgconf_fragment_t *parent = list->tail->data;
/* only attempt to merge 'special' fragments together */
if (!parent->type && parent->data != NULL &&
pkgconf_fragment_is_unmergeable(parent->data) &&
!(parent->flags & PKGCONF_PKG_FRAGF_TERMINATED))
{
if (pkgconf_fragment_is_groupable(parent->data))
target = &parent->children;
if (pkgconf_fragment_is_terminus(string))
parent->flags |= PKGCONF_PKG_FRAGF_TERMINATED;
PKGCONF_TRACE(client, "adding fragment as child to list @%p", target);
}
}
frag = calloc(1, sizeof(pkgconf_fragment_t));
if (frag == NULL)
{
PKGCONF_TRACE(client, "failed to add new fragment due to allocation failure to list @%p", target);
return;
}
if (strlen(string) > 1 && !pkgconf_fragment_is_special(string))
{
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = *(string + 1);
frag->data = pkgconf_fragment_copy_munged(client, string + 2, flags);
@ -268,13 +152,55 @@ pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const
}
else
{
frag->type = 0;
frag->data = pkgconf_fragment_copy_munged(client, string, flags);
char mungebuf[PKGCONF_ITEM_SIZE];
PKGCONF_TRACE(client, "created special fragment {'%s'} in list @%p", frag->data, target);
if (list->tail != NULL && list->tail->data != NULL &&
!(client->flags & PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS))
{
pkgconf_fragment_t *parent = list->tail->data;
/* only attempt to merge 'special' fragments together */
if (!parent->type && parent->data != NULL && pkgconf_fragment_is_unmergeable(parent->data))
{
size_t len;
char *newdata;
pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, string, NULL, flags);
len = strlen(parent->data) + strlen(mungebuf) + 2;
newdata = malloc(len);
pkgconf_strlcpy(newdata, parent->data, len);
pkgconf_strlcat(newdata, " ", len);
pkgconf_strlcat(newdata, mungebuf, len);
PKGCONF_TRACE(client, "merging '%s' to '%s' to form fragment {'%s'} in list @%p", mungebuf, parent->data, newdata, list);
free(parent->data);
parent->data = newdata;
parent->merged = true;
/* use a copy operation to force a dedup */
pkgconf_node_delete(&parent->iter, list);
pkgconf_fragment_copy(client, list, parent, false);
/* the fragment list now (maybe) has the copied node, so free the original */
free(parent->data);
free(parent);
return;
}
}
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = 0;
frag->data = strdup(string);
PKGCONF_TRACE(client, "created special fragment {'%s'} in list @%p", frag->data, list);
}
pkgconf_node_insert_tail(&frag->iter, frag, target);
pkgconf_node_insert_tail(&frag->iter, frag, list);
}
static inline pkgconf_fragment_t *
@ -327,9 +253,6 @@ pkgconf_fragment_can_merge(const pkgconf_fragment_t *base, unsigned int flags, b
if (is_private)
return false;
if (base->children.head != NULL)
return false;
return pkgconf_fragment_is_unmergeable(base->data);
}
@ -433,7 +356,7 @@ pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, cons
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = base->type;
pkgconf_fragment_copy_list(client, &frag->children, &base->children);
frag->merged = base->merged;
if (base->data != NULL)
frag->data = strdup(base->data);
@ -494,27 +417,49 @@ pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pk
}
}
static void
fragment_quote(pkgconf_buffer_t *out, const pkgconf_fragment_t *frag)
static inline char *
fragment_quote(const pkgconf_fragment_t *frag)
{
const char *src = frag->data;
ssize_t outlen = strlen(src) + 10;
char *out, *dst;
if (frag->data == NULL)
return;
return NULL;
const pkgconf_buffer_t *src = PKGCONF_BUFFER_FROM_STR(frag->data);
const pkgconf_span_t quote_spans[] = {
{ 0x00, 0x1f },
{ (unsigned char)' ', (unsigned char)'#' },
{ (unsigned char)'%', (unsigned char)'\'' },
{ (unsigned char)'*', (unsigned char)'*' },
{ (unsigned char)';', (unsigned char)'<' },
{ (unsigned char)'>', (unsigned char)'?' },
{ (unsigned char)'[', (unsigned char)']' },
{ (unsigned char)'`', (unsigned char)'`' },
{ (unsigned char)'{', (unsigned char)'}' },
{ 0x7f, 0xff },
};
out = dst = calloc(1, outlen);
pkgconf_buffer_escape(out, src, quote_spans, PKGCONF_ARRAY_SIZE(quote_spans));
for (; *src; src++)
{
if (((*src < ' ') ||
(*src >= (' ' + (frag->merged ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') ||
(*src > '=' && *src < '@') ||
(*src > 'Z' && *src < '\\') ||
#ifndef _WIN32
(*src == '\\') ||
#endif
(*src > '\\' && *src < '^') ||
(*src == '`') ||
(*src > 'z' && *src < '~') ||
(*src > '~')))
*dst++ = '\\';
*dst++ = *src;
if ((ptrdiff_t)(dst - out) + 2 > outlen)
{
ptrdiff_t offset = dst - out;
outlen *= 2;
out = realloc(out, outlen);
dst = out + offset;
}
}
*dst = 0;
return out;
}
static inline size_t
@ -527,18 +472,9 @@ pkgconf_fragment_len(const pkgconf_fragment_t *frag)
if (frag->data != NULL)
{
pkgconf_node_t *iter;
pkgconf_buffer_t quoted = PKGCONF_BUFFER_INITIALIZER;
fragment_quote(&quoted, frag);
len += pkgconf_buffer_len(&quoted);
pkgconf_buffer_finalize(&quoted);
PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
{
const pkgconf_fragment_t *child_frag = iter->data;
len += pkgconf_fragment_len(child_frag) + 1;
}
char *quoted = fragment_quote(frag);
len += strlen(quoted);
free(quoted);
}
return len;
@ -561,46 +497,45 @@ fragment_render_len(const pkgconf_list_t *list, bool escape)
return out;
}
static inline size_t
fragment_render_item(const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf, char delim)
{
const pkgconf_node_t *iter;
pkgconf_buffer_t quoted = PKGCONF_BUFFER_INITIALIZER;
fragment_quote(&quoted, frag);
if (frag->type)
pkgconf_buffer_append_fmt(buf, "-%c", frag->type);
pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(&quoted));
pkgconf_buffer_finalize(&quoted);
PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
{
const pkgconf_fragment_t *child_frag = iter->data;
pkgconf_buffer_push_byte(buf, delim);
fragment_render_item(child_frag, buf, delim);
}
return pkgconf_buffer_len(buf);
}
static void
fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, char delim)
fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{
(void) escape;
pkgconf_node_t *node;
char *bptr = buf;
memset(buf, 0, buflen);
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
fragment_render_item(frag, buf, delim);
size_t buf_remaining = buflen - (bptr - buf);
char *quoted = fragment_quote(frag);
if (strlen(quoted) > buf_remaining)
{
free(quoted);
break;
}
if (frag->type)
{
*bptr++ = '-';
*bptr++ = frag->type;
}
if (quoted != NULL)
{
bptr += pkgconf_strlcpy(bptr, quoted, buf_remaining);
free(quoted);
}
if (node->next != NULL)
pkgconf_buffer_push_byte(buf, delim);
*bptr++ = ' ';
}
*bptr = '\0';
}
static const pkgconf_fragment_render_ops_t default_render_ops = {
@ -633,7 +568,7 @@ pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgco
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim)
* .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
*
* Renders a `fragment list` into a buffer.
*
@ -642,16 +577,41 @@ pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgco
* :param size_t buflen: The length of the buffer.
* :param bool escape: Whether or not to escape special shell characters (deprecated).
* :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :param char delim: The delimiter to use between fragments.
* :return: nothing
*/
void
pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim)
pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
(void) escape;
ops = ops != NULL ? ops : &default_render_ops;
ops->render_buf(list, buf, true, delim);
ops->render_buf(list, buf, buflen, true);
}
/*
* !doc
*
* .. c:function:: char *pkgconf_fragment_render(const pkgconf_list_t *list)
*
* Allocate memory and render a `fragment list` into it.
*
* :param pkgconf_list_t* list: The `fragment list` being rendered.
* :param bool escape: Whether or not to escape special shell characters (deprecated).
* :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :return: An allocated string containing the rendered `fragment list`.
* :rtype: char *
*/
char *
pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
(void) escape;
size_t buflen = pkgconf_fragment_render_len(list, true, ops);
char *buf = calloc(1, buflen);
pkgconf_fragment_render_buf(list, buf, buflen, true, ops);
return buf;
}
/*
@ -693,7 +653,6 @@ pkgconf_fragment_free(pkgconf_list_t *list)
{
pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_free(&frag->children);
free(frag->data);
free(frag);
}
@ -732,6 +691,8 @@ pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkg
for (i = 0; i < argc; i++)
{
PKGCONF_TRACE(client, "processing %s", argv[i]);
if (argv[i] == NULL)
{
PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i);
@ -740,24 +701,7 @@ pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkg
return false;
}
bool greedy = pkgconf_fragment_is_greedy(argv[i]);
PKGCONF_TRACE(client, "processing [%s] greedy=%d", argv[i], greedy);
if (greedy && i + 1 < argc)
{
pkgconf_buffer_t greedybuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&greedybuf, argv[i]);
pkgconf_buffer_append(&greedybuf, argv[i + 1]);
pkgconf_fragment_add(client, list, pkgconf_buffer_str(&greedybuf), flags);
pkgconf_buffer_finalize(&greedybuf);
/* skip over next arg as we combined them */
i++;
}
else
pkgconf_fragment_add(client, list, argv[i], flags);
pkgconf_fragment_add(client, list, argv[i], flags);
}
pkgconf_argv_free(argv);

View File

@ -22,7 +22,6 @@
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <libpkgconf/libpkgconf-api.h>
#include <libpkgconf/iter.h>
#include <libpkgconf/bsdstubs.h>
@ -31,6 +30,23 @@
extern "C" {
#endif
/* pkg-config uses ';' on win32 as ':' is part of path */
#ifdef _WIN32
#define PKG_CONFIG_PATH_SEP_S ";"
#else
#define PKG_CONFIG_PATH_SEP_S ":"
#endif
#ifdef _WIN32
#define PKG_DIR_SEP_S '\\'
#else
#define PKG_DIR_SEP_S '/'
#endif
#ifdef _WIN32
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
#endif
#define PKGCONF_BUFSIZE (65535)
typedef enum {
@ -48,14 +64,11 @@ typedef enum {
typedef struct pkgconf_pkg_ pkgconf_pkg_t;
typedef struct pkgconf_dependency_ pkgconf_dependency_t;
typedef struct pkgconf_tuple_ pkgconf_tuple_t;
typedef struct pkgconf_buffer_ pkgconf_buffer_t;
typedef struct pkgconf_span_ pkgconf_span_t;
typedef struct pkgconf_fragment_ pkgconf_fragment_t;
typedef struct pkgconf_path_ pkgconf_path_t;
typedef struct pkgconf_client_ pkgconf_client_t;
typedef struct pkgconf_cross_personality_ pkgconf_cross_personality_t;
typedef struct pkgconf_queue_ pkgconf_queue_t;
typedef struct pkgconf_output_ pkgconf_output_t;
#define PKGCONF_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
@ -68,14 +81,12 @@ typedef struct pkgconf_output_ pkgconf_output_t;
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
#define LIBPKGCONF_VERSION 20501
#define LIBPKGCONF_VERSION_STR "2.5.1"
#define LIBPKGCONF_VERSION 20003
#define LIBPKGCONF_VERSION_STR "2.0.3"
struct pkgconf_queue_ {
pkgconf_node_t iter;
char *package;
unsigned int flags;
};
struct pkgconf_fragment_ {
@ -84,12 +95,9 @@ struct pkgconf_fragment_ {
char type;
char *data;
pkgconf_list_t children;
unsigned int flags;
bool merged;
};
#define PKGCONF_PKG_FRAGF_TERMINATED 0x1
struct pkgconf_dependency_ {
pkgconf_node_t iter;
@ -103,8 +111,6 @@ struct pkgconf_dependency_ {
int refcount;
pkgconf_client_t *owner;
char *why;
};
struct pkgconf_tuple_ {
@ -116,11 +122,6 @@ struct pkgconf_tuple_ {
unsigned int flags;
};
struct pkgconf_buffer_ {
char *base;
char *end;
};
#define PKGCONF_PKG_TUPLEF_OVERRIDE 0x1
struct pkgconf_path_ {
@ -129,8 +130,6 @@ struct pkgconf_path_ {
char *path;
void *handle_path;
void *handle_device;
unsigned int flags;
};
#define PKGCONF_PKG_PROPF_NONE 0x00
@ -138,9 +137,6 @@ struct pkgconf_path_ {
#define PKGCONF_PKG_PROPF_CACHED 0x02
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10
#define PKGCONF_PKG_PROPF_ANCESTOR 0x20
#define PKGCONF_PKG_PROPF_VISITED_PRIVATE 0x40
#define PKGCONF_PKG_PROPF_PRELOADED 0x80
struct pkgconf_pkg_ {
int refcount;
@ -154,8 +150,6 @@ struct pkgconf_pkg_ {
char *license;
char *maintainer;
char *copyright;
char *source;
char *license_file;
char *why;
pkgconf_list_t libs;
@ -182,16 +176,12 @@ struct pkgconf_pkg_ {
uint64_t serial;
uint64_t identifier;
pkgconf_node_t preload_node;
};
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data);
typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data);
typedef bool (*pkgconf_queue_apply_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth);
typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data);
typedef void (*pkgconf_unveil_handler_func_t)(const pkgconf_client_t *client, const char *path, const char *permissions);
typedef const char *(*pkgconf_environ_lookup_handler_func_t)(const pkgconf_client_t *client, const char *variable);
struct pkgconf_client_ {
pkgconf_list_t dir_list;
@ -201,7 +191,6 @@ struct pkgconf_client_ {
pkgconf_list_t global_vars;
void *client_data;
void *error_handler_data;
void *warn_handler_data;
void *trace_handler_data;
@ -210,8 +199,6 @@ struct pkgconf_client_ {
pkgconf_error_handler_func_t warn_handler;
pkgconf_error_handler_func_t trace_handler;
pkgconf_environ_lookup_handler_func_t environ_lookup_handler;
FILE *auditf;
char *sysroot_dir;
@ -228,18 +215,10 @@ struct pkgconf_client_ {
pkgconf_pkg_t **cache_table;
size_t cache_count;
pkgconf_unveil_handler_func_t unveil_handler;
pkgconf_list_t preloaded_pkgs;
pkgconf_output_t *output;
const pkgconf_cross_personality_t *personality;
};
struct pkgconf_cross_personality_ {
char *name;
const char *name;
pkgconf_list_t dir_list;
@ -253,8 +232,8 @@ struct pkgconf_cross_personality_ {
};
/* client.c */
PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler);
PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler);
PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality);
PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality);
PKGCONF_API void pkgconf_client_deinit(pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_free(pkgconf_client_t *client);
PKGCONF_API const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client);
@ -271,14 +250,7 @@ PKGCONF_API pkgconf_error_handler_func_t pkgconf_client_get_error_handler(const
PKGCONF_API void pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data);
PKGCONF_API pkgconf_error_handler_func_t pkgconf_client_get_trace_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data);
PKGCONF_API pkgconf_unveil_handler_func_t pkgconf_client_get_unveil_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler);
PKGCONF_API void pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality);
PKGCONF_API bool pkgconf_client_preload_one(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API bool pkgconf_client_preload_path(pkgconf_client_t *client, const char *path);
PKGCONF_API bool pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env);
PKGCONF_API void pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output);
PKGCONF_API const char *pkgconf_client_getenv(const pkgconf_client_t *client, const char *key);
/* personality.c */
PKGCONF_API pkgconf_cross_personality_t *pkgconf_cross_personality_default(void);
@ -306,11 +278,10 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p
#define PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS 0x4000
#define PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES 0x8000
#define PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES 0x10000
#define PKGCONF_PKG_PKGF_REQUIRE_INTERNAL 0x20000
#define PKGCONF_PKG_PKGF_ANCESTOR 0x20000
#define PKGCONF_PKG_DEPF_INTERNAL 0x1
#define PKGCONF_PKG_DEPF_PRIVATE 0x2
#define PKGCONF_PKG_DEPF_QUERY 0x4
#define PKGCONF_PKG_ERRF_OK 0x0
#define PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND 0x1
@ -318,23 +289,21 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p
#define PKGCONF_PKG_ERRF_PACKAGE_CONFLICT 0x4
#define PKGCONF_PKG_ERRF_DEPGRAPH_BREAK 0x8
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
# define PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (gnu_printf, fmtarg, firstvararg)))
#elif defined(__clang__) || defined(__INTEL_COMPILER) || __GNUC__ > 2 || (_GNUC__ == 2 && __GNUC_MINOR__ >= 5)
# define PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#define DEPRECATED \
__attribute__((deprecated))
#else
# define PRINTFLIKE(fmtarg, firstvararg)
#endif
#define PRINTFLIKE(fmtarg, firstvararg)
#define DEPRECATED
#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */
#if defined(__clang__) || defined(__INTEL_COMPILER) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
# define DEPRECATED __declspec(deprecated)
#else
# define DEPRECATED
#endif
/* parser.c */
typedef void (*pkgconf_parser_operand_func_t)(void *data, const size_t lineno, const char *key, const char *value);
typedef void (*pkgconf_parser_warn_func_t)(void *data, const char *fmt, ...);
PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename);
/* pkg.c */
PKGCONF_API bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
@ -361,19 +330,19 @@ PKGCONF_API void pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_API void pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_find(pkgconf_client_t *client, const char *name);
PKGCONF_API unsigned int pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, unsigned int skip_flags);
PKGCONF_API unsigned int pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *deplist);
PKGCONF_API unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth);
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags);
PKGCONF_API const char *pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep);
PKGCONF_API unsigned int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth);
PKGCONF_API unsigned int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth);
PKGCONF_API pkgconf_pkg_comparator_t pkgconf_pkg_comparator_lookup_by_name(const char *name);
PKGCONF_API pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name);
PKGCONF_API int pkgconf_compare_version(const char *a, const char *b);
PKGCONF_API pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *ptr, pkgconf_pkg_iteration_func_t func);
/* parse.c */
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *path, unsigned int flags);
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *path, FILE *f, unsigned int flags);
PKGCONF_API void pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags);
PKGCONF_API void pkgconf_dependency_parse(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags);
PKGCONF_API void pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail);
@ -391,12 +360,11 @@ PKGCONF_API void pkgconf_argv_free(char **argv);
/* fragment.c */
typedef struct pkgconf_fragment_render_ops_ {
size_t (*render_len)(const pkgconf_list_t *list, bool escape);
void (*render_buf)(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, char delim);
void (*render_buf)(const pkgconf_list_t *list, char *buf, size_t len, bool escape);
} pkgconf_fragment_render_ops_t;
typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data);
PKGCONF_API bool pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags);
PKGCONF_API void pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail);
PKGCONF_API void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags);
PKGCONF_API void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private);
PKGCONF_API void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base);
@ -404,9 +372,13 @@ PKGCONF_API void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_
PKGCONF_API void pkgconf_fragment_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data);
PKGCONF_API size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API void pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim);
PKGCONF_API void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t len, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API char *pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag);
/* fileio.c */
PKGCONF_API char *pkgconf_fgetline(char *line, size_t size, FILE *stream);
/* tuple.c */
PKGCONF_API pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *parent, const char *key, const char *value, bool parse, unsigned int flags);
PKGCONF_API char *pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key);
@ -420,7 +392,6 @@ PKGCONF_API void pkgconf_tuple_define_global(pkgconf_client_t *client, const cha
/* queue.c */
PKGCONF_API void pkgconf_queue_push(pkgconf_list_t *list, const char *package);
PKGCONF_API void pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t *dep);
PKGCONF_API bool pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list);
PKGCONF_API bool pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth);
PKGCONF_API void pkgconf_queue_free(pkgconf_list_t *list);
@ -443,113 +414,11 @@ PKGCONF_API void pkgconf_audit_log_dependency(pkgconf_client_t *client, const pk
PKGCONF_API void pkgconf_path_add(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API void pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API size_t pkgconf_path_build_from_environ(const pkgconf_client_t *client, const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter);
#ifdef _WIN32
PKGCONF_API size_t pkgconf_path_build_from_registry(/* HKEY -> HANDLE -> PVOID */ void *hKey, pkgconf_list_t *dirlist, bool filter);
#endif
PKGCONF_API size_t pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist);
PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist);
PKGCONF_API bool pkgconf_path_relocate(char *buf, size_t buflen);
PKGCONF_API void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
PKGCONF_API void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
/* buffer.c */
struct pkgconf_span_ {
unsigned char lo;
unsigned char hi; /* inclusive */
};
static inline bool pkgconf_span_contains(unsigned char c, const pkgconf_span_t *spans, size_t nspans) {
for (size_t i = 0; i < nspans; i++)
if (c >= spans[i].lo && c <= spans[i].hi)
return true;
return false;
}
PKGCONF_API void pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text);
PKGCONF_API void pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...) PRINTFLIKE(2, 3);
PKGCONF_API void pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list va);
PKGCONF_API void pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte);
PKGCONF_API void pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer);
PKGCONF_API void pkgconf_buffer_finalize(pkgconf_buffer_t *buffer);
PKGCONF_API void pkgconf_buffer_fputs(pkgconf_buffer_t *buffer, FILE *out);
PKGCONF_API void pkgconf_buffer_vjoin(pkgconf_buffer_t *buffer, char delim, va_list va);
PKGCONF_API void pkgconf_buffer_join(pkgconf_buffer_t *buffer, int delim, ...);
PKGCONF_API bool pkgconf_buffer_contains(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle);
PKGCONF_API bool pkgconf_buffer_contains_byte(const pkgconf_buffer_t *haystack, char needle);
PKGCONF_API bool pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle);
PKGCONF_API void pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pattern, const char *value);
PKGCONF_API void pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans);
static inline const char *pkgconf_buffer_str(const pkgconf_buffer_t *buffer) {
return buffer->base;
}
static inline const char *pkgconf_buffer_str_or_empty(const pkgconf_buffer_t *buffer) {
return buffer->base != NULL ? buffer->base : "";
}
static inline size_t pkgconf_buffer_len(const pkgconf_buffer_t *buffer) {
return (size_t)(ptrdiff_t)(buffer->end - buffer->base);
}
static inline char pkgconf_buffer_lastc(const pkgconf_buffer_t *buffer) {
if (buffer->base == buffer->end)
return '\0';
return *(buffer->end - 1);
}
#define PKGCONF_BUFFER_INITIALIZER { NULL, NULL }
#define PKGCONF_BUFFER_FROM_STR(str) &(const pkgconf_buffer_t){ .base = str, .end = str + strlen(str) }
static inline void pkgconf_buffer_reset(pkgconf_buffer_t *buffer) {
pkgconf_buffer_finalize(buffer);
buffer->base = buffer->end = NULL;
}
static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) {
if (buffer->base == NULL)
return NULL;
char *out = strdup(pkgconf_buffer_str(buffer));
pkgconf_buffer_reset(buffer);
return out;
}
static inline void pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr)
{
pkgconf_buffer_reset(newptr);
pkgconf_buffer_append(newptr, pkgconf_buffer_str(buffer));
}
/* fileio.c */
PKGCONF_API bool pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream);
/* parser.c */
typedef void (*pkgconf_parser_operand_func_t)(void *data, const char *warnprefix, const char *key, const char *value);
typedef void (*pkgconf_parser_warn_func_t)(void *data, const char *fmt, ...);
PKGCONF_API void pkgconf_parser_parse_buffer(void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, pkgconf_buffer_t *buffer, const char *warnprefix);
PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename);
/* output.c */
typedef enum {
PKGCONF_OUTPUT_STDOUT,
PKGCONF_OUTPUT_STDERR,
} pkgconf_output_stream_t;
struct pkgconf_output_ {
void *privdata;
bool (*write)(pkgconf_output_t *output, pkgconf_output_stream_t stream, const pkgconf_buffer_t *buffer);
};
PKGCONF_API bool pkgconf_output_putbuf(pkgconf_output_t *output, pkgconf_output_stream_t stream, const pkgconf_buffer_t *buffer, bool newline);
PKGCONF_API bool pkgconf_output_puts(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *str);
PKGCONF_API bool pkgconf_output_fmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *fmt, ...);
PKGCONF_API bool pkgconf_output_vfmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *fmt, va_list va);
PKGCONF_API pkgconf_output_t *pkgconf_output_default(void);
#ifdef __cplusplus
}

View File

@ -1,110 +0,0 @@
/*
* output.c
* I/O abstraction layer
*
* Copyright (c) 2025 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
bool
pkgconf_output_putbuf(pkgconf_output_t *output, pkgconf_output_stream_t stream, const pkgconf_buffer_t *buffer, bool newline)
{
bool ret;
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
if (pkgconf_buffer_len(buffer) != 0)
pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer));
if (newline)
pkgconf_buffer_push_byte(&buf, '\n');
ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf);
return ret;
}
bool
pkgconf_output_puts(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *str)
{
bool ret;
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&buf, str);
pkgconf_buffer_push_byte(&buf, '\n');
ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf);
return ret;
}
bool
pkgconf_output_fmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *fmt, ...)
{
bool ret;
va_list va;
va_start(va, fmt);
ret = pkgconf_output_vfmt(output, stream, fmt, va);
va_end(va);
return ret;
}
bool
pkgconf_output_vfmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, const char *fmt, va_list src_va)
{
va_list va;
bool ret;
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
va_copy(va, src_va);
pkgconf_buffer_append_vfmt(&buf, fmt, va);
va_end(va);
ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf);
return ret;
}
static bool
pkgconf_output_stdio_write(pkgconf_output_t *output, pkgconf_output_stream_t stream, const pkgconf_buffer_t *buffer)
{
(void) output;
FILE *target = stream == PKGCONF_OUTPUT_STDERR ? stderr : stdout;
if (buffer != NULL)
{
const char *str = pkgconf_buffer_str(buffer);
size_t size = pkgconf_buffer_len(buffer);
if (size > 0 && !fwrite(str, size, 1, target))
return false;
}
fflush(target);
return true;
}
static pkgconf_output_t pkgconf_default_output = {
.privdata = NULL,
.write = pkgconf_output_stdio_write,
};
pkgconf_output_t *
pkgconf_output_default(void)
{
return &pkgconf_default_output;
}

View File

@ -2,7 +2,7 @@
* parser.c
* rfc822 message parser
*
* Copyright (c) 2018, 2025 pkgconf authors (see AUTHORS).
* Copyright (c) 2018 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,84 +17,90 @@
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
void
pkgconf_parser_parse_buffer(void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, pkgconf_buffer_t *buffer, const char *warnprefix)
{
char op, *p, *key, *value;
p = buffer->base;
if (p == NULL)
return;
while (*p && isspace((unsigned char)*p))
p++;
if (*p && p != buffer->base)
{
warnfunc(data, "%s: warning: whitespace encountered while parsing key section\n",
warnprefix);
}
key = p;
while (*p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || *p == '_' || *p == '.'))
p++;
if (!isalpha((unsigned char)*key) &&
!isdigit((unsigned char)*p))
return;
while (*p && isspace((unsigned char)*p))
{
warnfunc(data, "%s: warning: whitespace encountered while parsing key section\n",
warnprefix);
/* set to null to avoid trailing spaces in key */
*p = '\0';
p++;
}
op = *p;
if (*p != '\0')
{
*p = '\0';
p++;
}
while (*p && isspace((unsigned char)*p))
p++;
value = p;
p = value + (strlen(value) - 1);
while (*p && isspace((unsigned char) *p) && p > value)
{
if (op == '=')
{
warnfunc(data, "%s: warning: trailing whitespace encountered while parsing value section\n",
warnprefix);
}
*p = '\0';
p--;
}
if (ops[(unsigned char) op])
ops[(unsigned char) op](data, warnprefix, key, value);
}
/*
* !doc
*
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f)
*
* Parse a .pc file into a pkgconf_pkg_t object structure.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param char* filename: The filename of the package file (including full path).
* :param FILE* f: The file object to read from.
* :returns: A ``pkgconf_pkg_t`` object which contains the package data.
* :rtype: pkgconf_pkg_t *
*/
void
pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename)
{
pkgconf_buffer_t readbuf = PKGCONF_BUFFER_INITIALIZER;
char readbuf[PKGCONF_BUFSIZE];
size_t lineno = 0;
bool continue_reading = true;
while (continue_reading)
while (pkgconf_fgetline(readbuf, PKGCONF_BUFSIZE, f) != NULL)
{
char warnprefix[PKGCONF_ITEM_SIZE];
char op, *p, *key, *value;
bool warned_key_whitespace = false, warned_value_whitespace = false;
continue_reading = pkgconf_fgetline(&readbuf, f);
lineno++;
snprintf(warnprefix, sizeof warnprefix, "%s:" SIZE_FMT_SPECIFIER, filename, lineno);
pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix);
pkgconf_buffer_reset(&readbuf);
p = readbuf;
while (*p && isspace((unsigned char)*p))
p++;
if (*p && p != readbuf)
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
filename, lineno);
warned_key_whitespace = true;
}
key = p;
while (*p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || *p == '_' || *p == '.'))
p++;
if (!isalpha((unsigned char)*key) &&
!isdigit((unsigned char)*p))
continue;
while (*p && isspace((unsigned char)*p))
{
if (!warned_key_whitespace)
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
filename, lineno);
warned_key_whitespace = true;
}
/* set to null to avoid trailing spaces in key */
*p = '\0';
p++;
}
op = *p;
if (*p != '\0')
{
*p = '\0';
p++;
}
while (*p && isspace((unsigned char)*p))
p++;
value = p;
p = value + (strlen(value) - 1);
while (*p && isspace((unsigned char) *p) && p > value)
{
if (!warned_value_whitespace && op == '=')
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n",
filename, lineno);
warned_value_whitespace = true;
}
*p = '\0';
p--;
}
if (ops[(unsigned char) op])
ops[(unsigned char) op](data, lineno, key, value);
}
pkgconf_buffer_finalize(&readbuf);
fclose(f);
}

View File

@ -91,9 +91,6 @@ prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
#endif
node = calloc(1, sizeof(pkgconf_path_t));
if (node == NULL)
return NULL;
node->path = strdup(path);
#ifdef PKGCONF_CACHE_INODES
@ -192,7 +189,6 @@ pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
* Adds the paths specified in an environment variable to a path list. If the environment variable is not set,
* an optional default set of paths is added.
*
* :param pkgconf_client_t* client: The client to use for environmental variable lookup (can be NULL).
* :param char* envvarname: The environment variable to look up.
* :param char* fallback: The fallback paths to use if the environment variable is not set.
* :param pkgconf_list_t* dirlist: The path list to add the path nodes to.
@ -201,11 +197,11 @@ pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
* :rtype: size_t
*/
size_t
pkgconf_path_build_from_environ(const pkgconf_client_t *client, const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
{
const char *data;
data = pkgconf_client_getenv(client, envvarname);
data = getenv(envvarname);
if (data != NULL)
return pkgconf_path_split(data, dirlist, filter);
@ -271,9 +267,6 @@ pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
pkgconf_path_t *srcpath = n->data, *path;
path = calloc(1, sizeof(pkgconf_path_t));
if (path == NULL)
continue;
path->path = strdup(srcpath->path);
#ifdef PKGCONF_CACHE_INODES
@ -285,41 +278,6 @@ pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
*
* Copies a path list to another path list.
*
* :param pkgconf_list_t* dst: The path list to copy to.
* :param pkgconf_list_t* src: The path list to copy from.
* :return: nothing
*/
void
pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
{
pkgconf_node_t *n;
PKGCONF_FOREACH_LIST_ENTRY(src->head, n)
{
pkgconf_path_t *srcpath = n->data, *path;
path = calloc(1, sizeof(pkgconf_path_t));
if (path == NULL)
continue;
path->path = strdup(srcpath->path);
#ifdef PKGCONF_CACHE_INODES
path->handle_path = srcpath->handle_path;
path->handle_device = srcpath->handle_device;
#endif
pkgconf_node_insert(&path->lnode, path, dst);
}
}
/*
* !doc
*
@ -388,6 +346,10 @@ normpath(const char *path)
bool
pkgconf_path_relocate(char *buf, size_t buflen)
{
#ifdef _WIN32
char *ti;
#endif
char *tmpbuf;
if ((tmpbuf = normpath(buf)) != NULL)
@ -405,53 +367,3 @@ pkgconf_path_relocate(char *buf, size_t buflen)
return true;
}
#ifdef _WIN32
#define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
/*
* !doc
*
* .. c:function:: void pkgconf_path_build_from_registry(HKEY hKey, pkgconf_list_t *dir_list, bool filter)
*
* Adds paths to a directory list discovered from a given registry key.
*
* :param HKEY hKey: The registry key to enumerate.
* :param pkgconf_list_t* dir_list: The directory list to append enumerated paths to.
* :param bool filter: Whether duplicate paths should be filtered.
* :return: number of path nodes added to the list
* :rtype: size_t
*/
size_t
pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filter)
{
HKEY key;
int i = 0;
size_t added = 0;
char buf[16384]; /* per registry limits */
DWORD bufsize = sizeof buf;
if (RegOpenKeyEx(hKey, PKG_CONFIG_REG_KEY,
0, KEY_READ, &key) != ERROR_SUCCESS)
return 0;
while (RegEnumValue(key, i++, buf, &bufsize, NULL, NULL, NULL, NULL)
== ERROR_SUCCESS)
{
char pathbuf[PKGCONF_ITEM_SIZE];
DWORD type;
DWORD pathbuflen = sizeof pathbuf;
if (RegQueryValueEx(key, buf, NULL, &type, (LPBYTE) pathbuf, &pathbuflen)
== ERROR_SUCCESS && type == REG_SZ)
{
pkgconf_path_add(pathbuf, dir_list, filter);
added++;
}
bufsize = sizeof buf;
}
RegCloseKey(key);
return added;
}
#endif

View File

@ -24,6 +24,10 @@
* =========================
*/
#ifdef _WIN32
# define strcasecmp _stricmp
#endif
/*
* Increment each time the default personality is inited, decrement each time
* it's deinited. Whenever it is 0, then the deinit frees the personality. In
@ -33,6 +37,10 @@ static unsigned default_personality_init = 0;
static pkgconf_cross_personality_t default_personality = {
.name = "default",
#ifdef _WIN32
.want_default_static = true,
.want_default_pure = true,
#endif
};
static inline void
@ -79,7 +87,7 @@ build_default_search_path(pkgconf_list_t* dirlist)
paths = NULL;
}
#else
pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, false);
pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, true);
#endif
}
@ -117,8 +125,7 @@ pkgconf_cross_personality_default(void)
*
* .. c:function:: void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *)
*
* Destroys a cross personality object and/or decreases the reference count on the
* default cross personality object.
* Decrements the count of default cross personality instances.
*
* Not thread safe.
*
@ -127,28 +134,11 @@ pkgconf_cross_personality_default(void)
void
pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *personality)
{
/* allow NULL parameter for API backwards compatibility */
if (personality == NULL)
return;
/* XXX: this hack is rather ugly, but it works for now... */
if (personality == &default_personality && --default_personality_init > 0)
return;
pkgconf_path_free(&personality->dir_list);
pkgconf_path_free(&personality->filter_libdirs);
pkgconf_path_free(&personality->filter_includedirs);
if (personality->sysroot_dir != NULL)
free(personality->sysroot_dir);
if (personality == &default_personality)
return;
if (personality->name != NULL)
free(personality->name);
free(personality);
if (--default_personality_init == 0) {
pkgconf_path_free(&personality->dir_list);
pkgconf_path_free(&personality->filter_libdirs);
pkgconf_path_free(&personality->filter_includedirs);
}
}
#ifndef PKGCONF_LITE
@ -164,7 +154,7 @@ valid_triplet(const char *triplet)
return true;
}
typedef void (*personality_keyword_func_t)(pkgconf_cross_personality_t *p, const char *keyword, const char *warnprefix, const ptrdiff_t offset, char *value);
typedef void (*personality_keyword_func_t)(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value);
typedef struct {
const char *keyword;
const personality_keyword_func_t func;
@ -172,30 +162,30 @@ typedef struct {
} personality_keyword_pair_t;
static void
personality_bool_func(pkgconf_cross_personality_t *p, const char *keyword, const char *warnprefix, const ptrdiff_t offset, char *value)
personality_bool_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) warnprefix;
(void) lineno;
bool *dest = (bool *)((char *) p + offset);
*dest = strcasecmp(value, "true") || strcasecmp(value, "yes") || *value == '1';
}
static void
personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const char *warnprefix, const ptrdiff_t offset, char *value)
personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) warnprefix;
(void) lineno;
char **dest = (char **)((char *) p + offset);
*dest = strdup(value);
}
static void
personality_fragment_func(pkgconf_cross_personality_t *p, const char *keyword, const char *warnprefix, const ptrdiff_t offset, char *value)
personality_fragment_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) warnprefix;
(void) lineno;
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) p + offset);
pkgconf_path_split(value, dest, false);
@ -220,7 +210,7 @@ personality_keyword_pair_cmp(const void *key, const void *ptr)
}
static void
personality_keyword_set(pkgconf_cross_personality_t *p, const char *warnprefix, const char *keyword, char *value)
personality_keyword_set(pkgconf_cross_personality_t *p, const size_t lineno, const char *keyword, char *value)
{
const personality_keyword_pair_t *pair = bsearch(keyword,
personality_keyword_pairs, PKGCONF_ARRAY_SIZE(personality_keyword_pairs),
@ -229,7 +219,7 @@ personality_keyword_set(pkgconf_cross_personality_t *p, const char *warnprefix,
if (pair == NULL || pair->func == NULL)
return;
pair->func(p, keyword, warnprefix, pair->offset, value);
pair->func(p, keyword, lineno, pair->offset, value);
}
static const pkgconf_parser_operand_func_t personality_parser_ops[256] = {
@ -265,19 +255,13 @@ load_personality_with_path(const char *path, const char *triplet, bool datadir)
else
snprintf(pathbuf, sizeof pathbuf, "%s/%s.personality", path, triplet);
p = calloc(1, sizeof(pkgconf_cross_personality_t));
if (p == NULL)
f = fopen(pathbuf, "r");
if (f == NULL)
return NULL;
p = calloc(1, sizeof(pkgconf_cross_personality_t));
if (triplet != NULL)
p->name = strdup(triplet);
f = fopen(pathbuf, "r");
if (f == NULL) {
pkgconf_cross_personality_deinit(p);
return NULL;
}
pkgconf_parser_parse(f, p, personality_parser_ops, personality_warn_func, pathbuf);
return p;
@ -324,7 +308,7 @@ pkgconf_cross_personality_find(const char *triplet)
}
}
pkgconf_path_build_from_environ(NULL, "XDG_DATA_DIRS", "/usr/local/share" PKG_CONFIG_PATH_SEP_S "/usr/share", &plist, true);
pkgconf_path_build_from_environ("XDG_DATA_DIRS", "/usr/local/share" PKG_CONFIG_PATH_SEP_S "/usr/share", &plist, true);
PKGCONF_FOREACH_LIST_ENTRY(plist.head, n)
{

File diff suppressed because it is too large Load Diff

View File

@ -29,32 +29,6 @@
* Using the `queue` module functions is the recommended way of working with dependency graphs.
*/
/*
* !doc
*
* .. c:function:: void pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t *dep)
*
* Pushes a requested dependency onto the dependency resolver's queue which is described by
* a pkgconf_dependency_t node.
*
* :param pkgconf_list_t* list: the dependency resolution queue to add the package request to.
* :param pkgconf_dependency_t* dep: the dependency requested
* :return: nothing
*/
void
pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t *dep)
{
pkgconf_buffer_t depbuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_queue_t *pkgq = calloc(1, sizeof(pkgconf_queue_t));
pkgconf_buffer_append(&depbuf, dep->package);
if (dep->version != NULL)
pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version);
pkgq->package = pkgconf_buffer_freeze(&depbuf);
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
}
/*
* !doc
*
@ -98,7 +72,7 @@ pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_li
pkgconf_queue_t *pkgq;
pkgq = iter->data;
pkgconf_dependency_parse(client, world, &world->required, pkgq->package, PKGCONF_PKG_DEPF_QUERY);
pkgconf_dependency_parse(client, world, &world->required, pkgq->package, 0);
}
return (world->required.head != NULL);
@ -129,169 +103,134 @@ pkgconf_queue_free(pkgconf_list_t *list)
}
static void
pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
pkgconf_queue_collect_dependents(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
{
if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
{
pkgconf_list_t *list = data;
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
pkgconf_dependency_t *dep = node->data;
if (dep->match == pkg)
dep->flags &= ~PKGCONF_PKG_DEPF_PRIVATE;
}
pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
PKGCONF_TRACE(client, "%s: updated, public", pkg->id);
}
}
static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth);
static inline unsigned int
pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
pkgconf_list_t *deplist,
void *data,
int depth)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node;
pkgconf_pkg_t *world = data;
PKGCONF_FOREACH_LIST_ENTRY_REVERSE(deplist->tail, node)
if (pkg == world)
return;
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *parent_dep = node->data;
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, parent_dep);
if ((client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) != PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE)
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
else
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->requires_private);
}
if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
{
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{
pkgconf_dependency_t *parent_dep = node->data;
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, parent_dep);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->requires_private);
}
}
}
static int
dep_sort_cmp(const void *a, const void *b)
{
const pkgconf_dependency_t *depA = *(void **) a;
const pkgconf_dependency_t *depB = *(void **) b;
return depB->match->identifier - depA->match->identifier;
}
static inline void
flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
{
pkgconf_node_t *node, *next;
pkgconf_dependency_t **deps = NULL;
size_t dep_count = 0, i;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_dependency_t *flattened_dep;
pkgconf_pkg_t *pkg = dep->match;
if (*dep->package == '\0')
continue;
pkgconf_pkg_t *pkg = pkgconf_pkg_verify_dependency(client, dep, NULL);
if (pkg == NULL)
{
PKGCONF_TRACE(client, "WTF: unmatched dependency %p <%s>", dep, dep->package);
continue;
}
if (pkg->serial == client->serial)
continue;
{
pkgconf_node_delete(node, list);
pkgconf_dependency_unref(client, dep);
goto next;
}
if (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE)
pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE;
else
pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1);
flattened_dep = pkgconf_dependency_copy(client, dep);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
}
return eflags;
}
static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
if (maxdepth == 0)
return eflags;
/* Short-circuit if we have already visited this node.
*/
if (root->serial == client->serial)
return eflags;
root->serial = client->serial;
PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth);
/* XXX: ugly */
const unsigned int saved_flags = client->flags;
client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth);
client->flags = saved_flags;
if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags;
PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth);
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth);
if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags;
PKGCONF_TRACE(client, "%s: finished, %s", root->id, (root->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) ? "private" : "public");
return eflags;
}
static inline unsigned int
pkgconf_queue_collect_dependencies(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth)
{
++client->serial;
return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth);
}
static inline unsigned int
pkgconf_queue_collect_conflicts(pkgconf_client_t *client,
pkgconf_pkg_t *root,
pkgconf_pkg_t *world,
int maxdepth)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node;
PKGCONF_TRACE(client, "%s: collecting conflicts, level %d", root->id, maxdepth);
PKGCONF_FOREACH_LIST_ENTRY(root->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *pkg = dep->match;
pkgconf_node_t *cnode;
if (*dep->package == '\0')
continue;
if (pkg == NULL)
if (dep->match == NULL)
{
PKGCONF_TRACE(client, "WTF: unmatched dependency %p <%s>", dep, dep->package);
continue;
abort();
}
PKGCONF_FOREACH_LIST_ENTRY(pkg->conflicts.head, cnode)
/* for virtuals, we need to check to see if there are dupes */
for (i = 0; i < dep_count; i++)
{
pkgconf_dependency_t *conflict = cnode->data;
pkgconf_dependency_t *flattened_conflict = pkgconf_dependency_copy(client, conflict);
pkgconf_dependency_t *other_dep = deps[i];
flattened_conflict->why = strdup(pkg->id);
pkgconf_node_insert(&flattened_conflict->iter, flattened_conflict, &world->conflicts);
PKGCONF_TRACE(client, "dedup %s = %s?", dep->package, other_dep->package);
if (!strcmp(dep->package, other_dep->package))
{
PKGCONF_TRACE(client, "skipping, "SIZE_FMT_SPECIFIER" deps", dep_count);
goto next;
}
}
pkg->serial = client->serial;
/* copy to the deps table */
dep_count++;
deps = pkgconf_reallocarray(deps, dep_count, sizeof (void *));
deps[dep_count - 1] = dep;
PKGCONF_TRACE(client, "added %s to dep table", dep->package);
next:
pkgconf_pkg_unref(client, pkg);
}
return eflags;
if (deps == NULL)
return;
qsort(deps, dep_count, sizeof (void *), dep_sort_cmp);
/* zero the list and start readding */
pkgconf_list_zero(list);
for (i = 0; i < dep_count; i++)
{
pkgconf_dependency_t *dep = deps[i];
if (dep->match == NULL)
continue;
memset(&dep->iter, '\0', sizeof (dep->iter));
pkgconf_node_insert(&dep->iter, dep, list);
PKGCONF_TRACE(client, "slot "SIZE_FMT_SPECIFIER": dep %s matched to %p<%s> id %"PRIu64, i, dep->package, dep->match, dep->match->id, dep->match->identifier);
}
free(deps);
}
static inline unsigned int
pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth)
{
unsigned int result;
const unsigned int saved_flags = client->flags;
pkgconf_pkg_t initial_world = {
.id = "user:request",
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
@ -302,58 +241,31 @@ pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_lis
return PKGCONF_PKG_ERRF_DEPGRAPH_BREAK;
}
PKGCONF_TRACE(client, "solving");
result = pkgconf_pkg_traverse(client, &initial_world, NULL, NULL, maxdepth, 0);
/* collect all the dependencies */
result = pkgconf_pkg_traverse(client, &initial_world, pkgconf_queue_collect_dependents, world, maxdepth, 0);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
PKGCONF_TRACE(client, "flattening");
result = pkgconf_queue_collect_dependencies(client, &initial_world, world, maxdepth);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
result = pkgconf_queue_collect_conflicts(client, world, world, maxdepth);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
{
PKGCONF_TRACE(client, "marking public deps");
client->flags &= ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
client->flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
result = pkgconf_pkg_traverse(client, &initial_world, pkgconf_queue_mark_public, &world->required, maxdepth, 0);
client->flags = saved_flags;
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
}
if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS))
{
PKGCONF_TRACE(client, "checking for conflicts");
result = pkgconf_pkg_walk_conflicts_list(client, world, &world->conflicts);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
}
/* free the initial solution */
pkgconf_solution_free(client, &initial_world);
/* flatten the dependency set using serials.
* we copy the dependencies to a vector, and then erase the list.
* then we copy them back to the list.
*/
++client->serial;
PKGCONF_TRACE(client, "flattening requires deps");
flatten_dependency_set(client, &world->required);
++client->serial;
PKGCONF_TRACE(client, "flattening requires.private deps");
flatten_dependency_set(client, &world->requires_private);
return PKGCONF_PKG_ERRF_OK;
}
@ -377,7 +289,6 @@ pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world)
{
pkgconf_dependency_free(&world->required);
pkgconf_dependency_free(&world->requires_private);
pkgconf_dependency_free(&world->conflicts);
}
}
@ -402,13 +313,7 @@ pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_
if (!maxdepth)
maxdepth = -1;
unsigned int flags = client->flags;
client->flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
unsigned int ret = pkgconf_queue_verify(client, world, list, maxdepth);
client->flags = flags;
return ret == PKGCONF_PKG_ERRF_OK;
return pkgconf_queue_verify(client, world, list, maxdepth) == PKGCONF_PKG_ERRF_OK;
}
/*

View File

@ -25,21 +25,14 @@
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <errno.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <malloc.h>
# include <io.h> /* for _setmode() */
# include <fcntl.h>
# define PATH_DEV_NULL "nul"
# ifdef _WIN64
# ifndef __MINGW32__
# define SIZE_FMT_SPECIFIER "%I64u"
# else
# define SIZE_FMT_SPECIFIER "%llu"
# endif
# define SIZE_FMT_SPECIFIER "%I64u"
# else
# define SIZE_FMT_SPECIFIER "%u"
# endif
@ -54,14 +47,9 @@
# ifndef __MINGW32__
# include "win-dirent.h"
# else
# include <dirent.h>
# include <dirent.h>
# endif
# define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024)
# define PKG_CONFIG_PATH_SEP_S ";"
# define PKG_DIR_SEP_S '\\'
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
#else
# define PATH_DEV_NULL "/dev/null"
# define SIZE_FMT_SPECIFIER "%zu"
@ -72,18 +60,11 @@
# include <unistd.h>
# include <limits.h>
# include <strings.h>
# include <fcntl.h> // open
# include <libgen.h> // basename/dirname
# include <sys/stat.h> // lstat, S_ISLNK
# include <unistd.h> // close, readlinkat
# include <string.h>
# ifdef PATH_MAX
# define PKGCONF_ITEM_SIZE (PATH_MAX + 1024)
# else
# define PKGCONF_ITEM_SIZE (4096 + 1024)
# endif
# define PKG_CONFIG_PATH_SEP_S ":"
# define PKG_DIR_SEP_S '/'
#endif
#endif

View File

@ -199,7 +199,7 @@ should_rewrite_sysroot(const pkgconf_client_t *client, pkgconf_list_t *vars, con
return false;
sysroot_dir = find_sysroot(client, vars);
if (sysroot_dir == NULL || !*sysroot_dir)
if (sysroot_dir == NULL)
return false;
if (*buf != '/')
@ -238,6 +238,8 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch
char *dequote_value;
pkgconf_tuple_t *tuple = calloc(1, sizeof(pkgconf_tuple_t));
pkgconf_tuple_find_delete(list, key);
dequote_value = dequote(value);
tuple->key = strdup(key);
@ -248,8 +250,6 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch
PKGCONF_TRACE(client, "adding tuple to @%p: %s => %s (parsed? %d)", list, key, tuple->value, parse);
pkgconf_tuple_find_delete(list, key);
pkgconf_node_insert(&tuple->iter, tuple, list);
free(dequote_value);
@ -314,13 +314,12 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
char buf[PKGCONF_BUFSIZE];
const char *ptr;
char *bptr = buf;
const char *sysroot_dir = find_sysroot(client, vars);
if (!(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) &&
(!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES)))
{
if (*value == '/' && sysroot_dir != NULL && *sysroot_dir && strncmp(value, sysroot_dir, strlen(sysroot_dir)))
bptr += pkgconf_strlcpy(buf, sysroot_dir, sizeof buf);
if (*value == '/' && client->sysroot_dir != NULL && strncmp(value, client->sysroot_dir, strlen(client->sysroot_dir)))
bptr += pkgconf_strlcpy(buf, client->sysroot_dir, sizeof buf);
}
for (ptr = value; *ptr != '\0' && bptr - buf < PKGCONF_BUFSIZE; ptr++)
@ -422,6 +421,7 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
if (should_rewrite_sysroot(client, vars, buf, flags))
{
char cleanpath[PKGCONF_ITEM_SIZE];
const char *sysroot_dir = find_sysroot(client, vars);
pkgconf_strlcpy(cleanpath, buf + strlen(sysroot_dir), sizeof cleanpath);
pkgconf_path_relocate(cleanpath, sizeof cleanpath);

View File

@ -1,100 +0,0 @@
.\" Copyright (c) 2025 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd June 4, 2025
.Dt BOMTOOL 1
.Os
.Sh NAME
.Nm bomtool
.Nd a tool for generating SPDX-based software bills of material
.Sh SYNOPSIS
.Nm
.Op Ar options
.Ar module ...
.Sh DESCRIPTION
.Nm
is a program which generates a textual SPDX 2.0 software bill of
materials (SBOM) for a given set of pkg-config modules.
The output of this tool can then be translated into other SBOM
formats as necessary.
.Pp
The
.Ar options
are as follows:
.Bl -tag -width indent
.It Fl -about
Print the version number, the Copyright notice, and the license of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -version
Print the version number of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.El
.Sh ENVIRONMENT
.Bl -tag -width indent
.It Ev PKG_CONFIG_DEBUG_SPEW
If set, print debugging messages to stderr.
.It Ev PKG_CONFIG_IGNORE_CONFLICTS
If set, ignore
.Ic Conflicts
rules in modules.
Has the same effect as the
.Fl -ignore-conflicts
option in
.Xr pkgconf 1
.
.It Ev PKG_CONFIG_LIBDIR
A colon-separated list of low-priority directories where
.Xr pc 5
files are looked up.
The module search path is constructed by appending this list to
.Ev PKG_CONFIG_PATH ,
which enjoys higher priority.
If
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list compiled into the
.Nm
program from the
.Dv PKG_DEFAULT_PATH
preprocessor macro is appended instead.
If
.Ev PKG_CONFIG_LIBDIR
is defined but empty, nothing is appended.
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
Impose a limit on the allowed depth in the dependency graph.
.It Ev PKG_CONFIG_PATH
A colon-separated list of high-priority directories where
.Xr pc 5
files are looked up.
.It Ev PKG_CONFIG_PRELOADED_FILES
Colon-separated list of
.Xr pc 5
files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Generating an SBOM for the package named foo:
.Dl $ bomtool foo
.Dl SPDXVersion: SPDX-2.2
.Dl DataLicense: CC0-1.0
.Dl SPDXID: SPDXRef-DOCUMENT
.Dl DocumentName: SBOM-SPDX-fooC641.2.3
.Dl DocumentNamespace: https://spdx.org/spdxdocs/bomtool-2.4.3
.Dl Creator: Tool: bomtool 2.4.3
.Dl [...]
.Sh SEE ALSO
.Xr pc 5 ,
.Xr pkgconf 1

View File

@ -116,36 +116,19 @@ not described as dependencies should be specified here.
.It License
The asserted SPDX license tag that should be applied to the given package.
(optional; literal; pkgconf extension)
.It License.file
License file location for whole license text.
(optional; literal; pkgconf extension)
.It Maintainer
The preferred contact for the maintainer. This should be in the format of a
name followed by an e-mail address or website.
(optional; literal; pkgconf extension)
.It Source
The asserted SPDX downloadLocation tag that should be applied to the given package.
Source should be URI contain tarball with exact version or Repository that contains
tag with version same as mentioned in version tag. It can be also be URI with hash
that is exact release point of the source.
(optional; literal; pkgconf extension)
.It Requires
Required dependencies that must be met for the package to be usable.
All dependencies must be satisfied or the pkg-config implementation must not use
the package.
(optional; dependency list)
.It Requires.internal
Required dependencies that must be met for the package to be usable for
static linking.
The main differences verses Requires.private are that CFLAGS will not be
included and the solver will not consider the dependency when solving for
CFLAGS only.
(optional; dependency list; pkgconf extension)
.It Requires.private
Required dependencies that must be met for the package to be usable for header
inclusion and static linking.
Required dependencies that must be met for the package to be usable for static linking.
All dependencies must be satisfied or the pkg-config implementation must not use
the package for header inclusion and static linking.
the package for static linking.
(optional; dependency list)
.It Conflicts
Dependencies that must not be met for the package to be usable.

View File

@ -16,745 +16,212 @@
.Sh SYNOPSIS
.Nm
.Op Ar options
.Ar module ...
.Op Ar list of modules
.Sh DESCRIPTION
The
.Nm
program retrieves configuration information related to the
.Ar module
arguments from
.Xr pc 5
files installed on the system and prints parts of the retrieved
information depending on the specified
.Ar options .
The most common use is printing the compiler and linker flags needed
to build software that uses the libraries given by the
.Ar module
arguments.
.Pp
The
.Xr pc 5
files are searched for along a path constructed from the
.Fl -with-path
option, the
.Ev PKG_CONFIG_PATH
and
.Ev PKG_CONFIG_LIBDIR
environment variables, and some compiled-in default directories.
The
.Ar module
arguments correspond to the file names, but without the
.Pa .pc
filename extension.
.Pp
Several of the
.Ar options
cause immediate exit.
If multiple of these options are given, only the option with the
highest priority takes effect and those with lower priority are
silently ignored.
These options are, ordered by descending priority:
.Bl -enum
.It
No-module options:
.Fl -relocate ,
.Fl -dump-personality ,
.Fl -about ,
.Fl -version ,
.Fl -help ,
.Fl -atleast-pkgconfig-version ,
.Fl -list-all ,
and
.Fl -list-package-names :
These options cause all arguments to be ignored.
.It
Argument-only options:
.Fl -atleast-version ,
.Fl -exact-version ,
and
.Fl -max-version :
These options only inspect modules explicitly specified on the
command line and do not look at dependencies.
.It
Limited-output options:
.Fl -validate ,
.Fl -license ,
.Fl -license-file ,
.Fl -source ,
.Fl -uninstalled ,
and
.Fl -env :
These options perform dependency resolution, but exit after printing
the information requested by the highest-priority option,
ignoring other output options that may have been specified.
.El
.Pp
Several other options require at least one
.Ar module
argument, produce output, do not cause early exit, can be combined
with each other, but override and disable all
.Fl -cflags
and
.Fl -libs
options:
.Bl -enum
.It
Single-module output options:
.Fl -path ,
.Fl -print-variables ,
.Fl -variable :
If any of these options is specified, only the first
.Ar module
argument is used, all other arguments are silently ignored,
and no dependency resolution is attempted.
.It
Depth-one output options:
.Fl -print-provides ,
.Fl -modversion ,
.Fl -print-requires ,
and
.Fl -print-requires-private :
If any of these options is specified, only modules
explicitly specified on the command line are inspected
and no dependency resolution is attempted.
.It
General output options:
.Fl -simulate ,
.Fl -digraph ,
.Fl -solution ,
.Fl -fragment-tree ,
.Fl -newlines :
These options do not limit dependency resolution.
.El
.Pp
The most important output options
.Fl -cflags
and
.Fl -libs
can be combined with each other, but are overridden and ignored if
any of the options listed above are specified.
.Pp
The complete list of
.Ar options
is as follows:
is a program which helps to configure compiler and linker flags for
development libraries.
This allows build systems to detect other dependencies and use them with the
system toolchain.
.Sh GENERAL OPTIONS
.Bl -tag -width indent
.It Fl -about
Print the version number, the Copyright notice, and the license of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -atleast-pkgconfig-version Ns = Ns Ar version
Exit with error if the requested
.Ar version
number is greater than the version number of the
.Nm
program, or with success otherwise.
Most other options and all command line arguments are ignored.
.It Fl -atleast-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is greater than or equal to the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
is less than the requested
.Ar version
number.
.It Fl -cflags , Fl -cflags-only-I , Fl -cflags-only-other
Print all compiler flags required to compile against the
.Ar module ,
or only the include path
.Pq Fl I
flags, or only the compiler flags that are not include path flags,
respectively.
These options imply
.Fl -print-errors .
.It Fl -debug
Print some non-fatal warning messages to standard error output
that would otherwise silently be ignored.
This option also implies
.Fl -print-errors .
If
.Nm
was compiled without defining the preprocessor macro
.Dv PKGCONF_LITE ,
this option also prints many debugging messages to standard error output.
.It Fl -define-prefix
Attempts to determine the prefix variable to use for CFLAGS and LIBS entry relocations.
This is mainly useful for platforms where framework SDKs are relocatable, such as Windows.
.It Fl -define-variable Ns = Ns Ar varname Ns = Ns Ar value
Define
.Ar varname
as
.Ar value .
Variables are used in query output, and some modules' results may change based
on the presence of a variable definition.
.It Fl -digraph
Dump the dependency resolver's solution as a graphviz
.Sq dot
file.
This can be used with graphviz to visualize module interdependencies.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -dont-define-prefix
Disables the
.Sq define-prefix
feature.
.It Fl -dont-relocate-paths
Disables the path relocation feature.
.It Fl -dump-personality
Print some default settings to standard output, in particular
the default module search path that is used when
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list of include paths that are filtered out when
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH
is not defined,
and the default list of library paths that are filtered out when
.Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH
is not defined, and exit.
Most other options and all command line arguments are ignored.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -env Ns = Ns Ar varname
Print the requested values as variable declarations in a similar format as the
.Xr env 1
command.
.It Fl -env-only
Initialize the module search path from
.Fl -with-path
and
.Ev PKG_CONFIG_PATH
only, ignoring
.Ev PKG_CONFIG_LIBDIR
and the compiled-in default directories.
.It Fl -version
Display the supported pkg-config version and exit.
.It Fl -atleast-pkgconfig-version Ns = Ns Ar VERSION
Exit with error if we do not support the requested pkg-config version.
.It Fl -errors-to-stdout
Print all error, warning, and debugging messages to standard output
instead of to standard error output.
.It Fl -exact-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is exactly the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
differs from the requested
.Ar version
number.
.It Fl -exists
Exit with a non-zero exit status
if the dependency resolver is unable to find all of the requested
.Ar module Ns s .
This option is active by default and cannot be disabled.
However, various other options cause
.Nm
to exit and report success or failure before all arguments have been inspected.
.It Fl -fragment-filter Ns = Ns Ar types
Filter the fragment lists for the specified
.Ar types .
.It Fl -help
Print a usage summary on standard output and exit.
Most other options and all command line arguments are ignored.
Print all errors on the main output stream instead of the error output stream.
.It Fl -silence-errors
Do not display any errors at all.
.It Fl -list-all
Walk all directories listed in the
.Va PKG_CONFIG_PATH
environmental variable and display information on packages which have registered
information there.
.It Fl -simulate
Simulates resolving a dependency graph based on the requested modules on the
command line.
Dumps a series of trees denoting pkgconf's resolver state.
.It Fl -no-cache
Skip caching packages when they are loaded into the internal resolver.
This may result in an alternate dependency graph being computed.
.It Fl -ignore-conflicts
Ignore
.Sq Conflicts
rules in modules.
.It Fl -keep-system-cflags , Fl -keep-system-libs
Keep CFLAGS or linker flag fragments that would be filtered due to being
included by default in the compiler.
.It Fl -libs , Fl -libs-only-L , Fl -libs-only-l , Fl -libs-only-other
Print all linker flags required to link against the
.Ar module ,
or only the library path
.Pq Fl L
flags, or only the library
.Pq Fl l
flags, or only the linker flags that are neither library path
nor library flags, respectively.
These options imply
.Fl -print-errors .
.It Fl -list-all
Walk the module search path in the order of descending priority.
For each
.Xr pc 5
file found, print one line to standard output,
containing the basename of the file without the extension, the
.Ic Name
property, a dash
.Pq Sq \- ,
and the
.Ic Description
property.
This option implies
.Fl -print-errors .
All command line arguments are ignored.
.It Fl -list-package-names
Perform the same search as
.Fl -list-all ,
but only print the basename of each
.Xr pc 5
file without the extension, not the module name and the description.
This option implies
.Fl -print-errors .
All command line arguments are ignored.
.It Fl -log-file Ns = Ns Ar file
Set the name of the output
.Ar file
where information about selected modules is logged,
both about those selected by arguments and as dependencies.
For each selected module, one line is printed,
containing the basename of the
.Xr pc 5
file without the extension, optionally an operator and version number
describing the desired range of versions, and either the actual version
number in square brackets or the string
.Qq NOT-FOUND .
If this option is not provided, the name of the output file
is instead taken from the
.Ev PKG_CONFIG_LOG
environment variable, and if that is not provided either,
this kind of logging is disabled.
.It Fl -max-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is less than or equal to the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
is greater than the requested
.Ar version
number.
.It Fl -maximum-traverse-depth Ns = Ns Ar depth
.It Fl -env-only
Learn about pkgconf's configuration strictly from environmental variables.
.It Fl -validate Ar package ...
Validate specific
.Sq .pc
files for correctness.
.It Fl -maximum-traverse-depth Ns = Ns Ar DEPTH
Impose a limit on the allowed depth in the dependency graph.
For example, a
.Ar depth
of 2 restricts the resolver from acting on child
For example, a depth of 2 will restrict the resolver from acting on child
dependencies of modules added to the resolver's solution.
This option is overridden by the
.Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
environment variable and by the options
.Fl -modversion ,
.Fl -path ,
.Fl -print-provides ,
.Fl -print-requires ,
.Fl -print-requires-private ,
.Fl -print-variables ,
and
.Fl -variable .
.It Fl -modversion
For each specified
.Ar module ,
print the version number to standard output.
If the
.Fl -verbose
option is also specified, the name of the respective
.Ar module
and a colon is printed before each version number.
This option implies
.Fl -print-errors
and
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -msvc-syntax
Use MSVC syntax for
.Fl -cflags ,
.Fl -env ,
and
.Fl -libs
output.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -newlines
Use newlines to separate individual CFLAGS or linker flag fragments
instead of spaces.
.It Fl -no-cache
Skip caching packages when they are loaded into the internal resolver.
This may result in an alternate dependency graph being computed.
.It Fl -static
Compute a deeper dependency graph and use compiler/linker flags intended for
static linking.
.It Fl -shared
Compute a simple dependency graph that is only suitable for shared linking.
.It Fl -pure
Treats the computed dependency graph as if it were pure.
This is mainly intended for use with the
.Fl -static
flag.
.It Fl -no-provides
Ignore
.Sq Provides
rules in modules when resolving dependencies.
.It Fl -no-uninstalled
Forbids the dependency resolver from considering 'uninstalled' modules as part
of a solution.
.It Fl -path
For the first
.Ar module
given on the command line, let the dependency resolver find the
.Xr pc 5
file describing that module, print the absolute pathname of that file
to standard output, and exit immediately,
ignoring most other options and all other arguments.
.It Fl -prefix-variable Ns = Ns Ar variable
.It Fl -with-path Ns = Ns Ar PATH
Adds a new module search path to pkgconf's dependency resolver.
Paths added in this way are given preference before other paths.
.It Fl -define-prefix
Attempts to determine the prefix variable to use for CFLAGS and LIBS entry relocations.
This is mainly useful for platforms where framework SDKs are relocatable, such as Windows.
.It Fl -dont-define-prefix
Disables the
.Sq define-prefix
feature.
.It Fl -prefix-variable Ns = Ns Ar VARIABLE
Sets the
.Sq prefix
variable used by the
.Sq define-prefix
feature.
.It Fl -print-errors
Print some messages about fatal errors to standard error output
that would otherwise be omitted.
This option is implied by many other options, but not by all.
It can be overridden with
.Fl -silence-errors .
.It Fl -print-provides
For each specified
.Ar module ,
print one line to standard output containing the
.Ic Name
property, an equal sign
.Pq Sq = ,
and the
.Ic Version
property.
If the
.Ar module
contains one or more
.Ic Provides
properties, print additional lines in dependency list format, one name
per line, each name optionally followed by an operator and a version.
This option implies
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -print-requires , Fl -print-requires-private
For each specified
.Ar module ,
print the
.Ic Requires
or
.Ic Requires.private
properties, respectively, in dependency list format to standard output.
Both of these options imply
.Fl -maximum-traverse-depth Ns =1
and override and disable all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -print-variables
For the first
.Ar module
given on the command line, print the names of all seen variables
to standard output, one per line.
Any subsequent arguments are silently ignored.
This option implies
.Fl -print-errors
and
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -pure
Treats the computed dependency graph as if it were pure.
This is mainly intended for use with the
.Fl -static
flag and has no effect if
.Fl -shared
is also specified.
.It Fl -relocate Ns = Ns Ar path
.It Fl -relocate Ns = Ns Ar PATH
Relocates a path using the pkgconf_path_relocate API.
This is mainly used by the testsuite to provide a guaranteed interface
to the system's path relocation backend.
.It Fl -shared
Compute a simple dependency graph that is only suitable for shared linking.
This option overrides
.Fl -static .
.It Fl -short-errors
When printing error messages about modules that are not found
or conflict with each other, avoid printing additional, verbose
instructions explaining potential methods for solving the problem.
.It Fl -silence-errors
Do not print any error, warning, or debugging messages at all.
Overrides all of
.Fl -debug ,
.Fl -errors-to-stdout ,
and
.Fl -print-errors .
This option is overridden and disabled if the
.Ev PKG_CONFIG_DEBUG_SPEW
environment variable is set.
.It Fl -simulate
Simulates resolving a dependency graph based on the requested modules on the
command line.
Dumps a series of trees denoting pkgconf's resolver state.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -solution
Print the names of the modules requested with
.Ar module
arguments and their dependencies to standard output.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -static
Compute a deeper dependency graph and use compiler/linker flags intended for
static linking.
This option is overridden by
.Fl -shared .
.It Fl -dont-relocate-paths
Disables the path relocation feature.
.El
.Sh MODULE-SPECIFIC OPTIONS
.Bl -tag -width indent
.It Fl -atleast-version Ns = Ns Ar VERSION
Exit with error if a module's version is less than the specified version.
.It Fl -exact-version Ns = Ns Ar VERSION
Exit with error if a module's version is not exactly the specified version.
.It Fl -max-version Ns = Ns Ar VERSION
Exit with error if a module's version is greater than the specified version.
.It Fl -exists
Exit with a non-zero result if the dependency resolver was unable to find all of
the requested modules.
.It Fl -uninstalled
Exit with a non-zero result if the dependency resolver uses an
.Sq uninstalled
module as part of its solution.
.It Fl -validate Ar package ...
Validate specific
.It Fl -no-uninstalled
Forbids the dependency resolver from considering 'uninstalled' modules as part
of a solution.
.El
.Sh QUERY-SPECIFIC OPTIONS
.Bl -tag -width indent
.It Fl -cflags , Fl -cflags-only-I , Fl -cflags-only-other
Display either all CFLAGS, only
.Fl I
CFLAGS or only CFLAGS that are not
.Fl I .
.It Fl -libs , Fl -libs-only-L , Fl -libs-only-l , Fl -libs-only-other
Display either all linker flags, only
.Fl L
linker flags, only
.Fl l
linker flags or only linker flags that are not
.Fl L
or
.Fl l .
.It Fl -keep-system-cflags , Fl -keep-system-libs
Keep CFLAGS or linker flag fragments that would be filtered due to being
included by default in the compiler.
.It Fl -define-variable Ns = Ns Ar VARNAME Ns = Ns Ar VALUE
Define
.Va VARNAME
as
.Va VALUE .
Variables are used in query output, and some modules' results may change based
on the presence of a variable definition.
.It Fl -print-variables
Print all seen variables for a module to the output channel.
.It Fl -print-provides
Print all relevant
.Sq Provides
entries for a module to the output channel.
.It Fl -variable Ns = Ns Ar VARNAME
Print the value of
.Va VARNAME .
.It Fl -print-requires , Fl -print-requires-private
Print the modules included in either the
.Va Requires
field or the
.Va Requires.private
field.
.It Fl -digraph
Dump the dependency resolver's solution as a graphviz
.Sq dot
file.
This can be used with graphviz to visualize module interdependencies.
.It Fl -path
Display the filenames of the
.Sq .pc
files for correctness.
This option implies
.Fl -print-errors
and
.Fl -errors-to-stdout .
.It Fl -variable Ns = Ns Ar varname
For the first
.Ar module
given on the command line, print the value of the variable with the name
.Ar varname
to standard output.
Any subsequent arguments are silently ignored.
This option implies
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -verbose
This option only has an effect if
.Fl -modversion
is also specified.
It prints the name of the respective
.Ar module
and a colon before each version number.
.It Fl -version
Print the version number of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -with-path Ns = Ns Ar path
Prepend the directory
.Ar path
to the module search path,
giving it priority over all other directories including those from
.Ev PKG_CONFIG_PATH
and
.Ev PKG_CONFIG_LIBDIR .
files used by the dependency resolver for a given dependency set.
.It Fl -env Ns = Ns Ar VARNAME
Print the requested values as variable declarations in a similar format as the
.Xr env 1
command.
.It Fl -fragment-filter Ns = Ns Ar TYPES
Filter the fragment lists for the specified types.
.It Fl -modversion
Print the version of the queried module.
.El
.Sh ENVIRONMENT
.Bl -tag -width indent
.It Ev CPATH
First supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev CPLUS_INCLUDE_PATH
Third supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev C_INCLUDE_PATH
Second supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev DESTDIR
If set to the same value as
.Ev PKG_CONFIG_SYSROOT_DIR ,
behave in the same way as if
.Ev PKG_CONFIG_FDO_SYSROOT_RULES
is set.
If
.Ev PKG_CONFIG_SYSROOT_DIR
is not set or set to a different value,
.Ev DESTDIR
is ignored.
.It Ev LIBRARY_PATH
Supplementary colon-separated list of library paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH .
.It Ev OBJC_INCLUDE_PATH
Fourth supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
If set, this variable has the same effect as the
.Fl -keep-system-cflags
option.
.It Ev PKG_CONFIG_ALLOW_SYSTEM_LIBS
If set, this variable has the same effect as the
.Fl -keep-system-libs
option.
.It Ev PKG_CONFIG_DEBUG_SPEW
If set, override and disable the
.Fl -silence-errors
option.
.It Ev PKG_CONFIG_DISABLE_UNINSTALLED
If set, enables the same behaviour as the
.Fl -no-uninstalled
flag.
.It Ev PKG_CONFIG_DONT_DEFINE_PREFIX
If set, this variable has the same effect as the
.Fl -dont-define-prefix
option.
.It Ev PKG_CONFIG_DONT_RELOCATE_PATHS
If set, disables the path relocation feature.
.It Ev PKG_CONFIG_FDO_SYSROOT_RULES
If set, follow the sysroot prefixing rules that freedesktop.org pkg-config uses.
.It Ev PKG_CONFIG_IGNORE_CONFLICTS
If set, ignore
.Ic Conflicts
rules in modules.
Has the same effect as the
.Fl -ignore-conflicts
option.
.It Ev PKG_CONFIG_LIBDIR
A colon-separated list of low-priority directories where
.Xr pc 5
.It Va PKG_CONFIG_PATH
List of secondary directories where
.Sq .pc
files are looked up.
The module search path is constructed by appending this list to
.Ev PKG_CONFIG_PATH ,
which enjoys higher priority.
If
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list compiled into the
.Nm
program from the
.Dv PKG_DEFAULT_PATH
preprocessor macro is appended instead.
If
.Ev PKG_CONFIG_LIBDIR
is defined but empty, nothing is appended.
.It Ev PKG_CONFIG_LOG
If set, log information about selected modules
to the file with the name stored in this variable.
For more details, see the
.Fl -log-file
command line option, which overrides this variable.
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
Impose a limit on the allowed depth in the dependency graph.
This variable overrides the
.Fl -maximum-traverse-depth
option, but is overridden by the other options mentioned there.
.It Ev PKG_CONFIG_MSVC_SYNTAX
If set, use MSVC syntax for
.Fl -cflags ,
.Fl -env ,
and
.Fl -libs
output.
This variable has the same effect as the
.Fl -msvc-syntax
option.
If the preprocessor macro
.Dv PKGCONF_LITE
was defined during compilation, this variable is ignored.
.It Ev PKG_CONFIG_PATH
A colon-separated list of high-priority directories where
.Xr pc 5
.It Va PKG_CONFIG_LIBDIR
List of primary directories where
.Sq .pc
files are looked up.
The module search path is constructed
by prepending the directory specified with
.Fl -with-path ,
if any, and unless
.Fl -env-only
is specified, by appending either
.Ev PKG_CONFIG_LIBDIR
or the compiled-in default directories with lower priority.
.It Ev PKG_CONFIG_PRELOADED_FILES
Colon-separated list of
.Xr pc 5
files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
.It Ev PKG_CONFIG_PURE_DEPGRAPH
.It Va PKG_CONFIG_SYSROOT_DIR
.Sq sysroot
directory, will be prepended to every path defined in
.Va PKG_CONFIG_PATH .
Useful for cross compilation.
.It Va PKG_CONFIG_TOP_BUILD_DIR
Provides an alternative setting for the
.Sq pc_top_builddir
global variable.
.It Va PKG_CONFIG_PURE_DEPGRAPH
If set, enables the same behaviour as the
.Fl -pure
flag.
.It Ev PKG_CONFIG_RELOCATE_PATHS
If set, this variable has the same effect as the
.Fl -define-prefix
option.
.It Ev PKG_CONFIG_SYSROOT_DIR
If set, this variable defines a
.Sq sysroot
directory, which will be prepended to every path variable
beginning with the prefix variable in a given
.Xr pc 5
file.
Useful for cross compilation.
The value of this environment variable is also copied into the global variable
.Va pc_sysrootdir .
.It Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH
Colon-separated list of include paths that are filtered out
and not printed by the
.Fl -cflags
and
.Fl -cflags-only-I
options because they are considered system include paths.
If not defined, the default list compiled into the
.Nm
program from the
.Dv SYSTEM_INCLUDEDIR
preprocessor macro is used instead.
This variable is a pkgconf-specific extension.
Any directories listed in the environment variables
.Ev CPATH ,
.Ev C_INCLUDE_PATH ,
.Ev CPLUS_INCLUDE_PATH ,
and
.Ev OBJC_INCLUDE_PATH
are also filtered out.
.It Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH
Colon-separated list of library paths that are filtered out
and not printed by the
.Fl -libs
and
.Fl -libs-only-L
options because they are considered system library paths.
If not defined, the default list compiled into the
.Nm
program from the
.Dv SYSTEM_LIBDIR
preprocessor macro is used instead.
This variable is a pkgconf-specific extension.
.It Ev PKG_CONFIG_TOP_BUILD_DIR
The value of the
.Va pc_top_builddir
global variable.
If this environment variable is not defined, the string
.Qq $(top_builddir)
is used as the value of
.Va pc_top_builddir .
.It Va PKG_CONFIG_SYSTEM_INCLUDE_PATH
List of paths that are considered system include paths by the toolchain.
This is a pkgconf-specific extension.
.It Va PKG_CONFIG_SYSTEM_LIBRARY_PATH
List of paths that are considered system library paths by the toolchain.
This is a pkgconf-specific extension.
.It Va PKG_CONFIG_DISABLE_UNINSTALLED
If set, enables the same behaviour as the
.Fl -no-uninstalled
flag.
.It Va PKG_CONFIG_LOG
.Sq logfile
which is used for dumping audit information concerning installed module versions.
.It Va PKG_CONFIG_DEBUG_SPEW
If set, enables additional debug logging.
The format of the debug log messages is implementation-specific.
.It Va PKG_CONFIG_DONT_RELOCATE_PATHS
If set, disables the path relocation feature.
.It Va PKG_CONFIG_MSVC_SYNTAX
If set, uses MSVC syntax for fragments.
.It Va PKG_CONFIG_FDO_SYSROOT_RULES
If set, follow the sysroot prefixing rules that freedesktop.org pkg-config uses.
.It Va DESTDIR
If set to PKG_CONFIG_SYSROOT_DIR, assume that PKG_CONFIG_FDO_SYSROOT_RULES is set.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Displaying the CFLAGS of a package:
.Dl $ pkgconf --cflags foo

View File

@ -1,17 +1,15 @@
project('pkgconf', 'c',
version : '2.5.1',
version : '2.1.0',
license : 'ISC',
meson_version : '>=0.49',
default_options : ['c_std=c99'],
meson_version: '>=0.52',
)
cc = meson.get_compiler('c')
add_project_arguments(
'-D_BSD_SOURCE',
'-D_DARWIN_C_SOURCE',
'-D_DEFAULT_SOURCE',
'-D_POSIX_C_SOURCE=200809L',
cc.get_supported_arguments(
'-Wimplicit-function-declaration',
'-Wmisleading-indentation',
@ -29,14 +27,11 @@ check_functions = [
['strncasecmp', 'strings.h'],
['strcasecmp', 'strings.h'],
['reallocarray', 'stdlib.h'],
['pledge', 'unistd.h'],
['unveil', 'unistd.h'],
['readlinkat', 'unistd.h'],
]
foreach f : check_functions
name = f[0].to_upper().underscorify()
if cc.has_function(f[0], prefix : '#define _BSD_SOURCE\n#define _DARWIN_C_SOURCE\n#define _DEFAULT_SOURCE\n#define _POSIX_C_SOURCE 200809L\n#include <@0@>'.format(f[1])) and cc.has_header_symbol(f[1], f[0], prefix : '#define _BSD_SOURCE\n#define _DARWIN_C_SOURCE\n#define _DEFAULT_SOURCE\n#define _POSIX_C_SOURCE 200809L')
if cc.has_function(f[0], prefix : '#define _BSD_SOURCE\n#include <@0@>'.format(f[1])) and cc.has_header_symbol(f[1], f[0], prefix : '#define _BSD_SOURCE')
cdata.set('HAVE_@0@'.format(name), 1)
cdata.set('HAVE_DECL_@0@'.format(name), 1)
else
@ -87,14 +82,12 @@ endif
libpkgconf = library('pkgconf',
'libpkgconf/argvsplit.c',
'libpkgconf/audit.c',
'libpkgconf/buffer.c',
'libpkgconf/bsdstubs.c',
'libpkgconf/cache.c',
'libpkgconf/client.c',
'libpkgconf/dependency.c',
'libpkgconf/fileio.c',
'libpkgconf/fragment.c',
'libpkgconf/output.c',
'libpkgconf/parser.c',
'libpkgconf/path.c',
'libpkgconf/personality.c',
@ -103,8 +96,8 @@ libpkgconf = library('pkgconf',
'libpkgconf/tuple.c',
c_args: ['-DLIBPKGCONF_EXPORT', build_static],
install : true,
version : '7.0.0',
soversion : '7',
version : '4.0.0',
soversion : '4',
)
# For other projects using libpkgconfig as a subproject
@ -129,72 +122,22 @@ pkg.generate(libpkgconf,
extra_cflags : build_static
)
cli_include = include_directories('cli')
pkgconf_exe = executable('pkgconf',
'cli/main.c',
'cli/core.c',
'cli/getopt_long.c',
'cli/renderer-msvc.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : cli_include,
c_args: build_static,
install : true)
bomtool_exe = executable('bomtool',
'cli/bomtool/main.c',
'cli/getopt_long.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : cli_include,
install : true)
spdxtool_exe = executable('spdxtool',
'cli/spdxtool/main.c',
'cli/spdxtool/core.c',
'cli/spdxtool/software.c',
'cli/spdxtool/serialize.c',
'cli/spdxtool/simplelicensing.c',
'cli/spdxtool/util.c',
'cli/getopt_long.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : include_directories('cli', 'cli/spdxtool'),
install : true)
test_runner_exe = executable('test-runner',
'cli/core.c',
'cli/getopt_long.c',
'cli/renderer-msvc.c',
'tests/test-runner.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : cli_include,
install : true)
fixtures_dir = '@0@/tests'.format(meson.current_source_dir())
test_suites = [
'basic',
'ordering',
'parser',
'solver',
'sbom',
'sysroot',
'tuple',
]
foreach t : test_suites
test(t, test_runner_exe, args : ['--test-fixtures', fixtures_dir, '@0@/t/@1@'.format(meson.current_source_dir(), t)])
endforeach
with_tests = get_option('tests')
kyua_exe = find_program('kyua', required : with_tests, disabler : true, native : true)
atf_sh_exe = find_program('atf-sh', required : with_tests, disabler : true, native : true)
kyua_exe = find_program('kyua', required : with_tests, disabler : true)
atf_sh_exe = find_program('atf-sh', required : with_tests, disabler : true)
kyuafile = configure_file(input : 'Kyuafile.in', output : 'Kyuafile', configuration : cdata)
test('kyua', kyua_exe, args : ['--config=none', 'test', '--kyuafile', kyuafile, '--build-root', meson.current_build_dir()])
subdir('tests')
install_man('man/bomtool.1')
install_man('man/pkgconf.1')
install_man('man/pkg.m4.7')
install_man('man/pc.5')
@ -202,40 +145,3 @@ install_man('man/pkgconf-personality.5')
install_data('pkg.m4', install_dir: 'share/aclocal')
install_data('AUTHORS', install_dir: 'share/doc/pkgconf')
install_data('README.md', install_dir: 'share/doc/pkgconf')
if host_machine.system() == 'windows'
conf_data = configuration_data()
conf_data.set('VERSION', meson.project_version())
conf_data.set('EXE', pkgconf_exe.full_path())
conf_data.set('DLL', libpkgconf.full_path())
if host_machine.cpu() != 'x86_64'
wixl_arch = 'x86'
else
wixl_arch = 'x64'
endif
conf_data.set('WIXL_ARCH', wixl_arch)
python = find_program('python3')
wixl = find_program('wixl', required: false, version: '>= 0.105')
msi_filename = 'pkgconf-@0@-@1@.msi'.format(wixl_arch, meson.project_version())
wxsfile = configure_file(input: 'pkgconf.wxs.in', output: 'pkgconf.wxs', configuration: conf_data)
if wixl.found()
licensefile = custom_target(
'License.rtf',
input: 'COPYING',
output: 'License.rtf',
command: [python, files('txt2rtf.py'), '@INPUT@', '@OUTPUT@'],
)
msi = custom_target(
msi_filename,
input: [wxsfile, licensefile, pkgconf_exe],
output: msi_filename,
command: [wixl, '--arch', wixl_arch, '--ext', 'ui', '-o', msi_filename, wxsfile],
)
alias_target('msi', msi)
endif
endif

12
pkg.m4
View File

@ -1,5 +1,5 @@
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
# serial 16 (pkgconf)
# serial 12 (pkg-config-0.29.2)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -15,7 +15,9 @@ dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, see <https://www.gnu.org/licenses/>.
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
dnl 02111-1307, USA.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
@ -173,13 +175,13 @@ _PKG_TEXT])[]dnl
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[A pkg-config implementation could not be found or is too old. Make sure it
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get a pkg-config implementation, see <http://github.com/pkgconf/pkgconf>.])[]dnl
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
@ -300,7 +302,7 @@ AC_ARG_WITH(with_arg,
[AS_TR_SH([with_]with_arg)=def_arg])
AS_CASE([$AS_TR_SH([with_]with_arg)],
[yes],[PKG_CHECK_MODULES([$1],[$2],[$3],[$4])],
[yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
[auto],[PKG_CHECK_MODULES([$1],[$2],
[m4_n([def_action_if_found]) $3],
[m4_n([def_action_if_not_found]) $4])])

View File

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define Arch = "@WIXL_ARCH@"?>
<?if $(var.Arch) = "x64"?>
<?define GLIB_ARCH = "win64"?>
<?define ArchString = "64-bit"?>
<?define ArchProgramFilesFolder = "ProgramFiles64Folder"?>
<?define Win64 = "yes"?>
<?else?>
<?define GLIB_ARCH = "win32"?>
<?define ArchString = "32-bit"?>
<?define ArchProgramFilesFolder = "ProgramFilesFolder"?>
<?define Win64 = "no"?>
<?endif?>
<Product Id="*"
Name="pkgconf @VERSION@ ($(var.ArchString))"
Language="1033"
Version="@VERSION@"
Manufacturer="pkgconf"
UpgradeCode="4faedad2-3f9d-45cc-89a7-3732ad2db0f7">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="pkgconf" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.ArchProgramFilesFolder)">
<Directory Id="INSTALLFOLDER" Name="pkgconf @VERSION@" />
</Directory>
</Directory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="PkgconfExe" Guid="*" Win64="$(var.Win64)">
<File Id="PkgconfExeFile"
Source="@EXE@"
KeyPath="yes" />
<File Id="PkgconfigExeFile"
Name="pkg-config.exe"
Source="@EXE@"/>
<File Id="PkgconfDllFile"
Source="@DLL@"/>
<Environment Id="PATH"
Name="PATH"
Value="[INSTALLFOLDER]"
Permanent="no"
Part="last"
Action="set"
System="yes" />
</Component>
</ComponentGroup>
<UIRef Id="WixUI_Minimal" />
</Product>
</Wix>

View File

@ -1,3 +0,0 @@
Query: %TEST_FIXTURES_DIR%/lib1/foo.pc
WantedFlags: libs
ExpectedStdout: -L/test/lib -lfoo

View File

@ -1,3 +0,0 @@
Query: pkgconf
WantedFlags: exists
ExpectedExitCode: 0

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: pkg-config
WantVariable: pc_path
ExpectedExitCode: 0
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1

View File

@ -1,3 +0,0 @@
Query: pkgconf
WantedFlags: exists
ExpectedExitCode: 0

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: pkgconf
WantVariable: pc_path
ExpectedExitCode: 0
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1

View File

@ -1,5 +0,0 @@
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1/child-prefix/pkgconfig
Environment: PKG_CONFIG_RELOCATE_PATHS=1
WantedFlags: cflags libs
Query: child-prefix-1
ExpectedStdout: -I%TEST_FIXTURES_DIR%/lib1/include/child-prefix-1 -L%TEST_FIXTURES_DIR%/lib1/lib64 -lchild-prefix-1

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1/child-prefix/pkgconfig
WantedFlags: define-prefix cflags libs
Query: child-prefix-1
ExpectedStdout: -I%TEST_FIXTURES_DIR%/lib1/include/child-prefix-1 -L%TEST_FIXTURES_DIR%/lib1/lib64 -lchild-prefix-1

View File

@ -1,4 +0,0 @@
WantVariable: prefix
WantedFlags: define-prefix
Query: %TEST_FIXTURES_DIR%/lib-relocatable/lib/pkgconfig/foo.pc
ExpectedStdout: %TEST_FIXTURES_DIR%/lib-relocatable

View File

@ -1,4 +0,0 @@
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib2
Query: %TEST_FIXTURES_DIR%/lib3/bar.pc
WantedFlags: cflags
ExpectedStdout: -fPIC -I/test/include/foo

View File

@ -1,5 +0,0 @@
Environment: PKG_CONFIG_DUPLICATE_TUPLE_PREFIX=/bar
PackageSearchPath: lib1
WantVariable: prefix
Query: duplicate-tuple
ExpectedStdout: /bar

View File

@ -1,8 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: cflags exists-cflags
ExpectedExitCode: 0
ExpectedStdout: FOO_CFLAGS='-DHAVE_FOO'
MatchStdout: partial
WantEnvPrefix: FOO
FragmentFilter: D

View File

@ -1,6 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: cflags exists-cflags
ExpectedExitCode: 0
ExpectedStdout: -DHAVE_FOO
MatchStdout: partial

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: nonexistent
WantedFlags: exists
ExpectedExitCode: 1

View File

@ -1,3 +0,0 @@
PackageSearchPath: lib1
Query: tilde >= 1.0.0
ExpectedExitCode: 1

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: foo > 1.2.3
WantedFlags: exists
ExpectedExitCode: 1

View File

@ -1,3 +0,0 @@
PackageSearchPath: lib1
Query: tilde <= 1.0.0
ExpectedExitCode: 0

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: foo >=
WantedFlags: exists
ExpectedExitCode: 1

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: foo > 1.2
WantedFlags: exists
ExpectedExitCode: 0

View File

@ -1,3 +0,0 @@
PackageSearchPath: lib1
Query: tilde = 1.0.0~rc1
ExpectedExitCode: 0

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: incomplete
WantedFlags: cflags
ExpectedStdout:

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: incomplete
WantedFlags: libs
ExpectedStdout:

View File

@ -1,4 +0,0 @@
Environment: PKG_CONFIG_SYSTEM_LIBRARY_PATH=/test/local/lib
PackageSearchPath: lib1
WantedFlags: libs-only-ldpath keep-system-libs
Query: cflags-libs-only

View File

@ -1,6 +0,0 @@
Environment: PKG_CONFIG_SYSTEM_LIBRARY_PATH=/test/local/lib
PackageSearchPath: lib1
WantedFlags: libs-only-ldpath
ExpectedStdout:
MatchStdout: empty
Query: cflags-libs-only

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo > 1.2,bar >= 1.3
WantedFlags: libs cflags
ExpectedExitCode: 0
ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lbar -lfoo

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo > 1.2 bar >= 1.3
WantedFlags: libs cflags
ExpectedExitCode: 0
ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lbar -lfoo

View File

@ -1,6 +0,0 @@
PackageSearchPath: lib1
Query: foo != 1.2.3
WantedFlags: libs cflags
ExpectedExitCode: 1
MatchStderr: partial
ExpectedStderr: Package 'foo' has version '1.2.3', required version is '!= 1.2.3'

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo != 1.3.0
WantedFlags: libs cflags
ExpectedExitCode: 0
ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lfoo

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo > 1.2
WantedFlags: libs cflags
ExpectedExitCode: 0
ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lfoo

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: libs cflags
ExpectedExitCode: 0
ExpectedStdout: -fPIC -I/test/include/foo -L/test/lib -lfoo

View File

@ -1,6 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: libs
ExpectedExitCode: 0
ExpectedStdout: FOO_LIBS='-L/test/lib -lfoo'
WantEnvPrefix: FOO

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: cflags-libs-only
WantedFlags: libs-only-ldpath libs-only-libname
ExpectedStdout: -L/test/local/lib -lfoo

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: libs
ExpectedExitCode: 0
ExpectedStdout: -L/test/lib -lfoo

View File

@ -1,3 +0,0 @@
PackageSearchPath: lib1
Query: , foo
ExpectedExitCode: 0

View File

@ -1,3 +0,0 @@
WantedFlags: modversion
Query: %TEST_FIXTURES_DIR%/lib1/bar.pc
ExpectedStdout: 1.3

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
WantedFlags: modversion
Query: bar
ExpectedStdout: 1.3

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
WantedFlags: modversion
Query: omg
ExpectedStdout: 1.2.3

View File

@ -1,7 +0,0 @@
PackageSearchPath: lib1
Query: foo, foobar
WantedFlags: modversion
VerbosityLevel: 1
ExpectedStdout: foo: 1.2.3
ExpectedStdout: foobar: 3.2.1
MatchStdout: partial

View File

@ -1,3 +0,0 @@
Query:
ExpectedExitCode: 1
ExpectedStderr: Please specify at least one package name on the command line.

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: nocflag
WantedFlags: cflags
ExpectedStdout:
ExpectedExitCode: 0

View File

@ -1,5 +0,0 @@
PackageSearchPath: lib1
Query: nolib
WantedFlags: libs
ExpectedStdout:
ExpectedExitCode: 0

View File

@ -1,4 +0,0 @@
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1%DIR_SEP%%TEST_FIXTURES_DIR%/lib2
WantedFlags: libs
Query: bar
ExpectedStdout: -L/test/lib -lbar -lfoo

View File

@ -1,12 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: print-variables cflags libs
WantEnvPrefix: FOO
ExpectedStdout: FOO_CFLAGS='-fPIC -I/test/include/foo'
ExpectedStdout: FOO_LIBS='-L/test/lib -lfoo'
ExpectedStdout: FOO_INCLUDEDIR='/test/include'
ExpectedStdout: FOO_LIBDIR='/test/lib'
ExpectedStdout: FOO_EXEC_PREFIX='/test'
ExpectedStdout: FOO_PREFIX='/test'
ExpectedStdout: FOO_PCFILEDIR='%TEST_FIXTURES_DIR%/lib1'
MatchStdout: partial

View File

@ -1,5 +0,0 @@
Environment: PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=1
PackageSearchPath: lib3
WantedFlags: print-requires
Query: bar
ExpectedStdout: foo

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
WantedFlags: libs
Query: static-archive-libs
ExpectedStdout: /libfoo.a -pthread

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: foo
WantedFlags: uninstalled
ExpectedExitCode: 1

View File

@ -1,4 +0,0 @@
PackageSearchPath: lib1
Query: omg
WantedFlags: uninstalled
ExpectedExitCode: 0

Some files were not shown because too many files have changed in this diff Show More