Skip to contentSkip to Content
DocsGetting StartedBuilding from Source

Building from Source

This page covers the SPIRES build system in detail: Makefile targets, compiler flags, platform-specific setup, library output formats, the test suite, and cross-compilation.

Makefile Targets

Run these from the repository root.

TargetWhat It Builds
make or make allBoth libspires.a (static) and libspires.so (shared) in build/
make staticOnly the static library build/libspires.a
make sharedOnly the shared library build/libspires.so (or .dylib on macOS)
make testBuild and run the test suite
make cleanRemove all build artifacts
make installInstall headers to /usr/local/include and libraries to /usr/local/lib (may require sudo)

Compiler Flags

The default Makefile applies these flags:

CFLAGS = -O2 -Wall -Wextra -std=c11 -fopenmp -march=native
FlagPurpose
-O2Optimization level 2. Good balance of speed and compile time. Use -O3 if you want more aggressive loop/vectorization optimizations at the cost of longer builds.
-Wall -WextraEnable most compiler warnings. SPIRES builds warning-free under both GCC and Clang.
-std=c11Use the C11 standard. Required for designated initializers and _Atomic support.
-fopenmpEnable OpenMP threading for parallel reservoir operations (matrix-vector products, state updates).
-march=nativeGenerate code tuned to the host CPU’s instruction set (AVX2, NEON, etc.). Remove this flag when cross-compiling.

Warning: -march=native produces binaries that may not run on a different CPU microarchitecture. For portable builds, replace it with a specific target like -march=x86-64-v2 or remove it entirely.

Platform-Specific Notes

macOS (Homebrew)

Apple Clang does not ship OpenMP or OpenBLAS. Install them with Homebrew and tell the compiler where to find them.

brew install openblas lapack libomp

Then build with the Homebrew paths:

make \ CFLAGS="-O2 -std=c11 -march=native \ -Xpreprocessor -fopenmp \ -I$(brew --prefix libomp)/include \ -I$(brew --prefix openblas)/include" \ LDFLAGS="-L$(brew --prefix libomp)/lib -lomp \ -L$(brew --prefix openblas)/lib -lopenblas \ -llapacke -lm"

Tip: If you see ld: library 'omp' not found, verify that libomp is installed and the LDFLAGS path is correct. Run brew --prefix libomp to confirm the installation directory.

Apple Silicon (M1/M2/M3/M4) Macs will automatically benefit from -march=native generating NEON-optimized code.

Ubuntu / Debian

sudo apt install build-essential libopenblas-dev liblapacke-dev libomp-dev

Then build normally:

make

GCC on Ubuntu includes OpenMP support by default. No extra flags are needed beyond the Makefile defaults.

Fedora / RHEL

sudo dnf install gcc openblas-devel lapack-devel libomp-devel

Then build normally:

make

Static vs Shared Library

SPIRES builds both a static (.a) and a shared (.so / .dylib) library.

Static Linking

gcc -o my_program my_program.c \ -I/path/to/spires/include \ /path/to/spires/build/libspires.a \ -lopenblas -llapacke -lm -fopenmp

The entire SPIRES library is embedded in your binary. No runtime dependency on libspires, though you still depend on OpenBLAS and LAPACKE at runtime.

Shared Linking

gcc -o my_program my_program.c \ -I/path/to/spires/include \ -L/path/to/spires/build \ -lspires -lopenblas -llapacke -lm -fopenmp

At runtime the dynamic linker must find libspires.so. Set the appropriate environment variable:

# Linux export LD_LIBRARY_PATH=/path/to/spires/build:$LD_LIBRARY_PATH # macOS export DYLD_LIBRARY_PATH=/path/to/spires/build:$DYLD_LIBRARY_PATH

Alternatively, install the library to a system path with make install.

Tip: For deployment, static linking avoids library-path issues. For development, shared linking gives faster incremental rebuilds since you only relink your program, not the library.


Running the Test Suite

make test

This compiles and runs all tests. The output reports the number of tests passed and failed. A successful run looks like:

Running SPIRES test suite... [PASS] test_create_destroy [PASS] test_step_single [PASS] test_ridge_sine [PASS] test_online_convergence [PASS] test_state_copy [PASS] test_reset ... All tests passed.

To run tests under Valgrind for memory-leak checking:

valgrind --leak-check=full ./build/test_spires

Tip: If you have modified neuron models or weight initialization, run the full test suite before committing to catch regressions early.


Troubleshooting Common Build Issues

Missing OpenBLAS Headers

Symptom:

fatal error: cblas.h: No such file or directory

Fix: Install the OpenBLAS development package (see Platform-Specific Notes above). If the headers are in a non-standard location, add the path:

make CFLAGS="-O2 -std=c11 -fopenmp -I/usr/include/openblas"

On some distributions the header is at /usr/include/x86_64-linux-gnu/cblas.h. Adjust the include path accordingly.

Missing LAPACKE

Symptom:

fatal error: lapacke.h: No such file or directory

Fix: Install liblapacke-dev (Debian/Ubuntu) or lapack-devel (Fedora/RHEL). On macOS with Homebrew:

brew install lapack make CFLAGS="-O2 -std=c11 -I$(brew --prefix lapack)/include" \ LDFLAGS="-L$(brew --prefix lapack)/lib -llapacke"

OpenMP Not Found on macOS

Symptom:

clang: error: unsupported option '-fopenmp'

Fix: Apple Clang does not support -fopenmp directly. Install libomp via Homebrew and use the -Xpreprocessor -fopenmp flag instead:

brew install libomp make CFLAGS="-O2 -std=c11 -Xpreprocessor -fopenmp -I$(brew --prefix libomp)/include" \ LDFLAGS="-L$(brew --prefix libomp)/lib -lomp"

Alternatively, install GCC from Homebrew (brew install gcc) and build with CC=gcc-14 make.

Linker Errors for BLAS Symbols

Symptom:

undefined reference to `cblas_dgemv'

Fix: The linker is not finding OpenBLAS. Ensure -lopenblas (or -lblas) appears in LDFLAGS and the library path is correct:

make LDFLAGS="-L/usr/lib/x86_64-linux-gnu -lopenblas -llapacke -lm"

Build Succeeds but Tests Segfault

This usually means the BLAS library is incompatible with the rest of the toolchain (e.g., mixing 32-bit and 64-bit integer interfaces). Ensure all libraries agree on sizeof(int):

# Check OpenBLAS integer width nm /usr/lib/libopenblas.so | grep ilp64

If your OpenBLAS uses 64-bit integers (ILP64), you may need to define OPENBLAS_USE64BITINT at compile time or switch to a 32-bit-integer build of OpenBLAS.


Cross-Compilation

To build SPIRES for a target architecture different from your host, override CC, CFLAGS, and LDFLAGS.

Example: x86_64 Host to aarch64 Target

sudo apt install gcc-aarch64-linux-gnu libopenblas-dev:arm64 make CC=aarch64-linux-gnu-gcc \ CFLAGS="-O2 -std=c11 -fopenmp -march=armv8-a" \ LDFLAGS="-lopenblas -llapacke -lm -lgomp"

Key points for cross-compilation:

  • Remove -march=native — it generates code for your host CPU, not the target.
  • Specify the target architecture explicitly — e.g., -march=armv8-a for 64-bit ARM.
  • Use cross-compiled versions of OpenBLAS and LAPACKE — the host libraries will not work on the target.
  • Test on the target or in an emulator (qemu-aarch64) before deploying.

Example: Building for Embedded Linux (No OpenMP)

If the target does not have OpenMP support:

make CC=arm-linux-gnueabihf-gcc \ CFLAGS="-O2 -std=c11 -march=armv7-a -mfpu=neon" \ LDFLAGS="-lopenblas -llapacke -lm" \ DISABLE_OPENMP=1

Tip: Disabling OpenMP means all reservoir operations run single-threaded. This is fine for small reservoirs (under ~1000 neurons) and avoids threading overhead on single-core embedded targets.


← First Reservoir | User Guide →

Last updated on