[Ur] Clarifying public API

Benjamin Barenblat benjamin at barenblat.name
Fri Dec 21 11:01:36 EST 2018


I’d like to change the way the liburweb API appears to consumers.
Currently, all functions inside liburweb fall into two categories:
public and static. Public functions are declared in urweb.h, and static
functions are local to the .c file they’re declared in.

I suspect there are functions in the runtime that aren’t intended to be
accessible to FFI authors and are simply exported for convenience. For
instance, I can think of no reason why anything other than the runtime
itself would need to call uw_global_init. As I see it, there ought to be
four categories of functions:

  1. functions that are public for FFI purposes,
  2. functions that are used in compiled code but should never be called
     by FFI libraries,
  3. functions that are internal to the runtime but need to be called
     across translation units, and
  4. static functions.

I think only public functions (category 1) should be listed in urweb.h.
Functions needed by compiled code but not available for the FFI
(category 2) should go in their own header file, and to emphasize their
internal nature, we shouldn’t install that header in /usr/include but
rather in /usr/share/urweb. Internal functions needed across translation
units (category 3) should be declared in headers that are only used
while compiling the runtime and not installed at all.

Making this change would allow more flexibility inside the runtime.
Currently, category 3 functions are exported and part of liburweb’s ABI.
If we make them internal, we can edit or rename them without worrying
about breaking existing programs or FFI libraries. As an added bonus,
making them internal lets the compiler emit better relocations for them,
speeding both the dynamic linking process and runtime performance in
general for Ur/Web programs. (An exported function requires an indirect
jump through the PLT and a trip through the dynamic linker the first
time around; an internal function can be called directly.)

This would break ABI (and therefore all currently compiled binaries and
FFI libraries), but we’re already doing that in the next release.
Provided we pick a reasonable public API, it won’t break any FFI library
source code.

The major challenge here is figuring out exactly what the public API
should be. What functions and types should we expose to FFI consumers?
Obviously, we need the ones listed in the manual, and we need the Basis
types for FFI interop. But do FFI libraries really need to call, say,
uw_Basis_strlen, when there’s a perfectly reasonable strlen in libc that
does the same thing?

I’d love to hear your thoughts about whether or not this is a reasonable
idea, as well as what patterns you’ve seen and used in FFI libraries
that we shouldn’t break.



More information about the Ur mailing list