Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
README for jlib-2.0.x
------------------------
jlib is a personal C++ library, begun in 1999 and worked on sporadically ever
since. It started as a set of STL-compatible utility classes and grew into
something wider: a mail client that speaks OAuth2 to Gmail, a transformer that
runs quantized models on the GPU, renderers that draw four-dimensional objects
as solid geometry, and the RFC parsers underneath the first of those.
Three habits hold it together.
The older one is that most of it either models an STL container or iterator
concept, or plugs into std::streambuf and std::iostream. A socket, a TLS
connection, a subprocess, a serial port and a temporary file are all streams
here, so they compose with each other and with everything else that takes an
istream.
The newer one is that where a format has a published grammar, that grammar is
pasted into a header and read as it stands -- RFC 5322 addresses, MIME
headers, URLs, IMAP responses, HTTP messages -- rather than approximated with
find() and substr(). Every departure from the published text is marked at the
point of use, because the whole value of pasting it in is that a reader can
check one against the other.
The newest is that where something can wait, it should be able to wait on
more than one thing at once. For most of its life jlib had four unrelated
ways to block and no way to combine them; it has one reactor now, and C++20
coroutines over it, so a read and a request and a timer are all things one
thread can be waiting for. The blocking interfaces are all still there and
still the right answer for a program that wants them -- nothing was migrated,
and run_until_complete is what lets a synchronous caller drive an
asynchronous one without becoming one.
What came of it was a server. The HTTP server answers more than one request
per connection now, where the blocking one would have to hold a thread for
every client that might ask again -- and once connections were reusable, the
things a reusable connection makes worth having followed: chunked output so a
streamed body has an end, route patterns, HEAD, conditional requests, byte
ranges, and a handler for serving a directory. It is still not hardened for a
public port and the header still says so, at rather more length than before.
Errors are thrown rather than returned, and each class nests its own
exception type. Everything lives in namespace jlib::<module>.
What is in it:
sys iostream wrappers over OS facilities -- sockets, TLS, subprocesses,
serial ports, a listener and a server, a job queue, a lock-free
ring buffer. And an async half: an I/O reactor over kqueue,
epoll or poll, C++20 coroutine tasks and awaitables on top of it,
cancellation with deadlines, and a server whose connections are
coroutines rather than threads
util an ABNF parser-combinator core with an RFC 5234 front end, and the
RFC grammars read through it: 5322, 2045/2047, 3986, 9110/9112.
Plus JSON, MIME headers, a Jinja2 subset, and an XML parser
crypt OpenPGP through GPGME, and ristretto255 curve/Schnorr/Groth proofs
net an email client stack -- Email, MBox, POP3, IMAP4 -- with OAuth2,
and an HTTP client and server: the client deliberately narrow, the
server less so than it was -- keep-alive, chunked output, route
patterns, HEAD, conditional requests, byte ranges and static
files, in a blocking flavour and a suspending one that runs the
same handlers
ai a quantized transformer that runs GGUF files: llama, qwen2 and
gemma2, with Metal compute where there is one
media audio through PortAudio, driven from its callback
math matrices, tensors, polynomials, and N-dimensional objects
x/gl Xlib, OpenGL, GLX and GLFW rendering, including 4-D solids
Some programs it builds:
jlib-mail a command-line mail client
jchat talk to a GGUF model
jserve an OpenAI-compatible endpoint, which aider can drive
jhardhyper 4-D hypercubes and tori as solid 3-D geometry
jcrypt a GPGME encrypt/decrypt filter
DOCUMENTATION
-------------
Per-symbol documentation is in the headers, next to what it describes, which
is where it stays correct.
What a header cannot hold is the shape that spans several of them, and that is
in docs/:
docs/abnf.md grammars pasted from the RFCs, and the PEG that runs
them
docs/net.md mail and HTTP clients, OAuth2, and the three habits
layered by age
docs/async.md the reactor, the coroutine layer, and the two ways
sys::server serves a connection
docs/jhttpd.md the HTTP server, and the daemon built on it
docs/ai.md the transformer, the backend, and the network that
trains from scratch
docs/jserve.md an OpenAI-compatible endpoint over a local model
docs/jchat.md talking to one from a terminal
docs/jalpaca.md the same, with a transcript, and why that is a second
program
docs/jcode.md the coding harness, its two edit formats, and the
write that is deliberately not a tool
docs/audio.md synthesis, sampling and mixing, and the streambuf you
write notes into
Each is a map rather than a reference: it says how the pieces fit and why they
are shaped that way, and points at the header for the detail. Where a
document and a header disagree, the header is right and the document is a bug.
REQUIREMENTS
------------
A C++20 compiler. Apple clang 15+ and gcc 11+ are what it is built with;
configure probes for the standard explicitly and stops if it is not there.
Required:
json-c >= 0.9
gpgme >= 1.0
gpg-error
openssl >= 1.1
Optional, each gating its own module:
libsodium (with ristretto headers) crypt/curve, schnorr, groth
portaudio media
glfw the GLFW window and its 4-D apps
ncurses jalpaca
ImageMagick++ jneural-alpha
X11, OpenGL, GLU, GLX the X11 and GLX rendering
CUDA --with-cuda
Metal the GPU compute backend, on macOS
configure prints a summary of what it found and what it skipped.
The names above are the upstream ones. Two scripts translate them:
./install-ubuntu-deps.sh [full] Debian and Ubuntu, via apt-get
./install-mac-deps.sh [full] macOS, via Homebrew
Without an argument each installs the toolchain and the four required
dependencies; with "full" it adds the optional ones too. Pass -n to print
the command and install nothing -- that works anywhere, including where the
package manager does not exist, so it doubles as the name mapping for
anyone translating to another system.
macOS needs a different set rather than different names for the same set.
OpenGL and GLU come from -framework OpenGL, so nothing installs them and no
pkg-config module finds them; Apple ships an ncurses with a .pc file, so
Homebrew's keg-only one is not wanted; and X11 is XQuartz, a cask, which
neither script installs because only jlib/x and jlib/glx want it and the
GLFW backend does not.
INSTALLATION
------------
Out-of-tree builds are expected:
./autogen.sh
mkdir build && cd build
../configure
make -j8
make check
make install
autogen.sh is a one-line autoreconf and is only needed from a git checkout.
It wants autoconf, automake, libtool, pkg-config and autoconf-archive -- the
last for AX_CXX_COMPILE_STDCXX and AX_PTHREAD.
Missing either of the last two used to be hard to read. Without pkg-config,
PKG_CHECK_MODULES goes unexpanded and autoconf complains about an AC_ macro
nested inside one, 180 lines further down -- "possibly undefined macro:
AC_CHECK_LIB", which names a macro that is obviously defined. Without
autoconf-archive it is worse: autoconf's pattern check does not cover AX_, so
nothing is reported, autoreconf succeeds, and configure fails much later with
"AX_PTHREAD: command not found". configure.ac now checks for both and names
the package.
For a list of options,
../configure --help
Two worth knowing:
--enable-perf build tools/perf, the measurement programs. They need a
model file and take minutes, so they are never run by
make check. Read tools/perf/README.md first
--with-cuda build jlib/cuda
Tests are plain main() programs registered in TESTS -- no framework. Exit 77
means SKIP, which is how a test needing a display, an audio device, or a GGUF
model file reports a machine without one. See DOCKER for building and testing
on Linux.
LICENSE
-------
Apache License, Version 2.0. See the file LICENSE for the full text,
and NOTICE for the attribution notice it requires.
jlib was distributed under the GNU General Public License, version 2 or
later, from 1999 until 2026. Everything up to and including the commit
that added this paragraph remains available under those terms; the
relicense applies from that point forward. It became possible only when
the last file jlib did not hold the copyright to -- a third-party XML
parser -- was replaced.
CONTACT
-------
Copyright (c) 1999-2026 Joey Yandle <xoloki@gmail.com>
https://github.com/xoloki/jlib