xml2-config stops you guessing which libxml2 installation your compiler is actually using. You will pull the compiler and linker flags, check which installation your shell picks by default, and compile a small C program to prove headers, library and binary all match. Allow about fifteen minutes.
You need a shell, libxml2-dev or another libxml2 development install, and a C compiler for the final smoke test. Everything that inspects paths and prints flags is an ordinary user command; installing packages is outside this guide and needs your normal administrator process.
More than one installation can supply a command with this name, so start by inspecting the search path rather than assuming:
$ command -v xml2-config
/home/linuxbrew/.linuxbrew/bin/xml2-config
$ type -a xml2-config
xml2-config is /home/linuxbrew/.linuxbrew/bin/xml2-config
xml2-config is /usr/bin/xml2-config
Your output will differ, but the first entry is the one a bare xml2-config --cflags actually uses. On this machine that is libxml2 2.15.4 from Homebrew for Linux, while the package-owned Debian command sits at /usr/bin/xml2-config, supplied by libxml2-dev:amd64 version 2.9.14+dfsg-1.3ubuntu3.9. Two commands, same name, different libraries: exactly the trap this step exists to catch.
Checkpoint: pick your installation on purpose. Building against the Debian package means using the absolute path below; deliberately using something else means checking that installation's version first, not assuming it matches.
$ XML2_CONFIG=/usr/bin/xml2-config
$ "$XML2_CONFIG" --version
2.9.14
The package-owned command reports the include directory with --cflags and the link-time libraries with --libs:
$ "$XML2_CONFIG" --cflags
-I/usr/include/libxml2
$ "$XML2_CONFIG" --libs
-lxml2
These are shell-ready fragments: -I tells the compiler where to find headers, -lxml2 tells the linker to use libxml2. Let the command produce the flags rather than hardcoding paths into a build script, because those paths move between a system package, a Homebrew prefix and a source install.
The same command also reports the installation prefix:
$ "$XML2_CONFIG" --prefix
/usr
$ "$XML2_CONFIG" --exec-prefix
/usr
$ "$XML2_CONFIG" --modules
1
The --modules result is just a capability indicator from this installed script: not a list of modules, and not a request to enable anything.
Feed both outputs into the compiler command. Keeping the source before the libraries, as shown, is what common Unix linkers expect and avoids surprises under static or strict link settings:
$ cat > /tmp/xml2-config-smoke.c <<'EOF'
#include <libxml/parser.h>
int main(void)
{
xmlInitParser();
xmlCleanupParser();
return 0;
}
EOF
$ gcc -o /tmp/xml2-config-smoke /tmp/xml2-config-smoke.c \
$("$XML2_CONFIG" --cflags) $("$XML2_CONFIG" --libs)
$ /tmp/xml2-config-smoke
$ printf 'exit status: %s\n' "$?"
exit status: 0
A zero exit status confirms the selected headers were found, the program linked against the selected libxml2 library, and the binary ran. That is a smoke test, not an application test. Clean up when you are done:
$ rm -f /tmp/xml2-config-smoke.c /tmp/xml2-config-smoke
That removal is irreversible for these temporary files, so check the names before you run it. No elevated privileges needed.
--prefix=DIR changes the paths printed for later flag requests. It does not install libxml2, copy headers, or move a library:
$ "$XML2_CONFIG" --prefix=/opt/libxml2 --cflags
-I/opt/libxml2/include/libxml2
$ "$XML2_CONFIG" --prefix=/opt/libxml2 --libs
-lxml2
The option must come before --cflags or --libs: the manual page documents that ordering, and the installed script follows it. If the prefix does not contain the expected files, compilation or linking fails. Do not point a successful-looking build at an arbitrary directory just to silence a missing-header error.
There is a second trap here: a prefix override can make the compiler use headers from one installation while the linker finds a library through the system search path. Keep include and library paths under one known prefix, and inspect the full command in your build log.
The installed manual page is dated 3 July 1999 and still describes the old GNOME-XML-era tool as xml-config. It documents --version, --libs, --cflags and --prefix=PREFIX, but it does not describe the modern help output accurately: the package-owned executable here reports libxml2 2.9.14 and also accepts --exec-prefix, --modules and --help.
Trust the executable you are actually invoking, not the ageing manpage. Keep the version check, command -v output and flag output together as one picture. If PATH finds 2.15.4 while your build is meant to use the Debian package at 2.9.14, call /usr/bin/xml2-config explicitly or fix the build environment. Do not mix the Homebrew include directory with Debian's library just because both commands share a name.
Command not found: the development package or its bin directory is missing from PATH. Check with command -v and use your distribution's package manager. Installing a package changes system state, so confirm the package name and repository before reaching for elevated privileges.
Header not found: print --cflags and check that the directory contains libxml/parser.h. A prefix override pointing at an empty or differently laid-out directory is a common cause.
Cannot find -lxml2: print --libs and check that the corresponding library installation is present. Do not fix this by deleting libraries or changing global linker configuration. Restore the previous build environment and select one complete installation instead.
Unexpected version or paths: run type -a xml2-config, then use an absolute command path in the build. Shell aliases, virtual environments and Homebrew prefixes can change which executable wins.
Linking works but runtime loading fails: inspect the executable with your platform's normal loader tools and check its runtime library configuration. xml2-config supplies build flags; it does not configure the dynamic loader or guarantee that a deployed host has the same libxml2 version.
command -v or an absolute path names the intended xml2-config.--version, --cflags and --libs all come from that same install.