Library / SDK
JuliaMath/openlibm avatar
JuliaMath/openlibm

openlibm: a portable libm that gives a runtime the same maths everywhere

High quality system independent, portable, open source libm implementation

637 stars164 forksCNOASSERTION

At a glance

What is it?
OpenLibm is a standalone C implementation of the C mathematical library, built so that a language runtime or an application gets identical floating point results across compilers, operating systems and word sizes. It supports a long list of architectures and ships with its own test suite and cross-build recipe.
Who is it for?
OpenLibm fits a project that needs bit-identical floating point behaviour across platforms and is willing to vendor and maintain a C library, which is exactly why Julia needed one. It is the wrong choice for an application that already runs on a platform libm and does not care about cross-platform consistency, since vendoring means owning the build, the security updates and the licence review.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 51 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why a language runtime would want its own libm

OpenLibm describes itself as an effort to have a high quality, portable, standalone C mathematical library. The README is explicit about the audience: it can be used standalone in applications and in programming language implementations.

The origin story explains the design. The project was born out of a need for a good libm for the Julia programming language that worked consistently across compilers and operating systems, and in 32-bit and 64-bit environments. That word consistently is the whole point. A system libm is allowed to differ between platforms and vendors, and a runtime that wants reproducible numerical results cannot simply call whatever the host provides.

That constraint shapes everything else about the library. It is written in C, it is standalone, and it is tested in-house rather than inherited from the operating system. For an application developer the appeal is the same as for a language runtime: if your results differ between your Linux CI machine and a customer's Windows laptop, a controlled libm removes one variable.

The cost is equally clear. You are taking on a C library that you compile, ship and eventually patch yourself. The repository topics are c, cross-platform, math-library and openlibm, and the project homepage is openlibm.org.

One directory per architecture, including wasm32 and loongarch64

The repository layout is the clearest description of the scope. The top-level entries include src/ for the shared sources, include/ for the public headers, test/ for the test suite, docs/, CMakeLists.txt, Makefile, Make.inc, openlibm.pc.in and bsdsrc/, plus a directory for every supported architecture: amd64/, i387/, arm/, aarch64/, powerpc/, riscv64/, s390/, mips/, loongarch64/ and wasm32/.

Two directories that do not look like architectures are worth understanding. ld80/ and ld128/ hold the long double implementations, and the Makefile shows exactly when they are compiled in. The top-level SUBDIRS variable starts as src, the architecture directory and bsdsrc, and then, only when LONG_DOUBLE_NOT_DOUBLE is set, the build adds ld80 for i387 and amd64, and ld128 for aarch64. On every other target the long double path is whatever the compiler provides. That is a per-architecture correctness decision baked into the build system, not a runtime option.

The Makefile also handles the platform naming differences for the shared library. On Windows it skips versioned shared libraries entirely and generates an import library for the DLL with an --out-implib linker flag. On macOS it puts the version number before the .dylib extension, and elsewhere it puts it after. Anyone embedding the library and hard-coding a file name has to read that section of the Makefile.

The README lists the architectures as largely tested and widely used on x86 and x86-64, with arm, aarch64, ppc64le, mips, wasm32, riscv, s390(x) and loongarch64 also supported.

Building with GNU Make and forcing the toolchain

The build instructions are short, and the important part is that you can override the compiler and the target architecture explicitly.

On most systems the build command is make, with gmake on BSDs. To select the compiler, use USECLANG=1 for clang, which is the default on OS X, FreeBSD and OpenBSD, and USEGCC=1 for GCC, which is the default on Linux and Windows.

bash
make USEGCC=1
bash
make USECLANG=1

The target architecture is auto-detected, but you can force it. For the WebAssembly build the README gives the exact invocation, which pairs the clang build with the wasm32 architecture:

bash
make ARCH=wasm32

And for 32-bit x86 the instruction is to use make ARCH=i386, with i486, i586 and i686 as the other supported variants. The README adds one hard requirement: GCC 4.8 is the minimum for correct codegen on the older 32-bit architectures. That is a real constraint for anyone building on a modern distribution that has moved to a newer GCC and wants to support i386.

The build produces the library, and the Makefile also defines install, install-static, install-shared, install-pkgconfig and install-headers targets, so a system-wide install into your own prefix is a supported path rather than something you assemble by hand.

Cross building for riscv64 and running the tests under qemu

The cross build recipe in the README is the most useful part of the documentation, because it covers the case that is normally skipped: not only building for another architecture, but actually running the test binaries there.

The example takes riscv64. First you install the emulator and the cross compiler, qemu-riscv64-static and gcc-riscv64-linux-gnu. Then the build itself sets the architecture and the toolchain prefix:

sh
ARCH=riscv64
TRIPLE=$ARCH-linux-gnu
make ARCH=$ARCH TOOLPREFIX=$TRIPLE-  -j
make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE-  -j

Note that the test directory is built as a separate make invocation with make -C test, which is why the test sources carry their own Make.files entries.

Running the result then goes through qemu, with the library search paths pointing at the local build and at the cross sysroot:

sh
qemu-$ARCH-static -L . -L /usr/$TRIPLE/  test/test-float
qemu-$ARCH-static -L . -L /usr/$TRIPLE/  test/test-double

test-float and test-double are the two main correctness binaries. The Makefile also lists a check and test target alongside test-regression, and its comment explains that per-issue regression programs live in test/regression/*.c and are run from the repository root so that the freshly built shared library is found the same way on every platform. That detail is the reason this library can claim consistent results across platforms: the tests are run against the build you just made, not against a system library.

The CMake path and the shared or static decision

CMake is the alternative build system, and its documentation is even shorter. You create a build directory with mkdir build, change into it with cd build, configure with cmake /path/to/openlibm/, and build with cmake --build . If you want a specific generator, the README gives an example using the MinGW Makefiles generator.

bash
mkdir build
cd build
cmake /path/to/openlibm/
cmake --build .

One configuration decision matters for packagers. The default CMake configuration builds a shared library, and the README says this can be changed with the BUILD_SHARED_LIBS configuration option. Since the same CMakeLists.txt is what a distribution would use to package OpenLibm, that option is where the shared versus static decision is made, and getting it wrong changes the way your consumers link.

The openlibm.pc.in file at the root is a pkg-config template, and the Makefile has an install-pkgconfig target, so the library can advertise its flags through pkg-config once installed. The presence of a pkg-config template alongside a Make-based build says the project is aiming to be consumable as an ordinary system library rather than only as vendored source.

For CMake consumers, the picture is complete: an out-of-tree build directory, a configure step that accepts the standard CMake variables, and a single build command.

Versions, the licence question, and when the system libm is enough

The release record shows a steady, unhurried cadence. Tagged versions include v0.8.6 on 2025-03-07, v0.8.7 on 2025-06-03 and v0.8.8 on 2026-09-02. The repository is not archived, and the last push was on 2026-09-02, the same day as the newest tag, so the tag reflects the current state of the tree rather than lagging behind it.

The licensing detail needs attention. GitHub reports the licence as a custom one that it cannot classify, and the repository has a LICENSE.md file rather than a standard identifier. For a library you plan to vendor into a product, that file is the one you need to read, because an unclassifiable licence is not a standard permissive grant by default.

The alternative is the one most applications should take: use the platform libm. Your operating system already ships one, it is maintained by the distribution vendor alongside security patches, and every toolchain expects it. The reason to prefer OpenLibm is a specific requirement, not a general preference for portability: identical numerical results across platforms, a controlled build you can reproduce, or a target such as wasm32 or loongarch64 where the platform libm is not what you want.

If your requirement is only that the maths library exists on every platform, use the system one. If your requirement is that it behaves the same everywhere, and you can own a C library, vendor this.

Editorial conclusion

OpenLibm fits a project that needs bit-identical floating point behaviour across platforms and is willing to vendor and maintain a C library, which is exactly why Julia needed one. It is the wrong choice for an application that already runs on a platform libm and does not care about cross-platform consistency, since vendoring means owning the build, the security updates and the licence review. Before adopting, read LICENSE.md in the repository, because the licence is a custom one that GitHub cannot classify, build it with the toolchain your distribution pins, and run the test suite under test/ rather than trusting a cross-compiled binary you have never executed on the target.

Frequently asked questions

How do I build openlibm with GCC instead of clang?

Use make USEGCC=1, which is the default on Linux and Windows. The clang build is make USECLANG=1 and is the default on OS X, FreeBSD and OpenBSD, and the architecture is auto-detected unless you set ARCH.

How do I cross build openlibm for another architecture and test it?

The README uses riscv64 as its example: install qemu-riscv64-static and gcc-riscv64-linux-gnu, then run make ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j and make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j. The resulting binaries are run with qemu-$ARCH-static -L . -L /usr/$TRIPLE/ test/test-float and test/test-double.

Can I build openlibm with CMake instead of GNU Make?

Yes. Create a build directory with mkdir build, enter it with cd build, configure with cmake /path/to/openlibm/ and build with cmake --build .. The default CMake configuration builds a shared library, and BUILD_SHARED_LIBS changes that.

Which architectures does openlibm support?

The README says it builds on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD and DragonFly BSD, and supports x86 and x86-64 along with arm, aarch64, ppc64le, mips, wasm32, riscv, s390(x) and loongarch64. Separate ld80 and ld128 directories hold long double implementations for x86 and aarch64.

Official sources

  1. Issues
  2. JuliaMath/openlibm on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/juliamath-openlibm.svg)](https://hysenlabs.com/projects/juliamath-openlibm)

Was this useful?