Skip to content

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

About

C++20 library: iostream wrappers, ABNF/RFC parsers, coroutine networking with TLS, quantized transformer runtime, and hyperspace rendering

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages