This is a sample project demonstrating how to build NIFs for multiple languages using elixir_make, including C, Rust, and Zig NIF implementations.
c_add/2- Add two numbersc_concat/2- String concatenation
rust_multiply/2- Multiply two numbersrust_reverse/1- String reversal
zig_subtract/2- Subtract two numberszig_strlen/1- Calculate string length
- Elixir 1.14+
- Erlang/OTP 24+
- CMake 3.10+
- Rust (latest stable version)
- Zig 0.11+
- Visual Studio Build Tools
- scoop install make
- scoop install coreutils
- scoop install cmake
- scoop install zig
- rustup
-
Get dependencies
mix deps.get
-
Compile project
# Default release mode compilation mix compile # Or explicitly specify mode make release # Build release version make debug # Build debug version # Using environment variable BUILD_MODE=debug mix compile
-
Run tests
mix test -
Interactive testing
# Using release version iex -S mix # Using debug version BUILD_MODE=debug iex -S mix
Then test in IEx:
# C NIF tests MakeNif.c_add(5, 3) # => 8 MakeNif.c_concat("Hello, ", "World!") # => "Hello, World!" # Rust NIF tests MakeNif.rust_multiply(4, 5) # => 20 MakeNif.rust_reverse("hello") # => "olleh" # Zig NIF tests MakeNif.zig_subtract(10, 3) # => 7 MakeNif.zig_strlen("Elixir") # => 6
-
Run demo script
# Release mode demo elixir demo.exs # Debug mode demo BUILD_MODE=debug elixir demo.exs
make_nif/
├── lib/
│ └── make_nif.ex # Elixir module definition
├── native/
│ ├── c_src/ # C NIF source code
│ │ ├── CMakeLists.txt # CMake build configuration
│ │ └── c_nif.c # C NIF implementation
│ ├── rust_src/ # Rust NIF source code
│ │ ├── Cargo.toml # Cargo configuration
│ │ └── src/lib.rs # Rust NIF implementation
│ └── zig_src/ # Zig NIF source code
│ ├── build.zig # Zig build configuration
│ └── src/main.zig # Zig NIF implementation
├── test/
│ ├── make_nif_test.exs # Test file
│ └── test_helper.exs # Test helper
├── Makefile # Main build file
└── mix.exs # Mix project configuration
This project uses elixir_make to coordinate builds across different languages:
- Makefile is the main build entry point
- CMake is used to build C NIFs
- Cargo is used to build Rust NIFs
- Zig built-in build system is used to build Zig NIFs
elixir_make will automatically call the Makefile's all target during mix compile.
The project supports two build modes:
-
Release mode (default): Optimized production build
make release # or BUILD_MODE=release make all -
Debug mode: Development build with debug symbols
make debug # or BUILD_MODE=debug make all
make all- Build all NIFs (default release mode)make release- Build release version of all NIFsmake debug- Build debug version of all NIFsmake clean- Clean current build mode artifactsmake clean-all- Clean all build artifacts (debug and release)make help- Show help information
Built NIF files will have suffixes based on the mode:
- Release mode:
c_nif.dll,rust_nif.dll,zig_nif.dll - Debug mode:
c_nif_debug.dll,rust_nif_debug.dll,zig_nif_debug.dll
Ensure Erlang development packages are installed and erl_nif.h is accessible.
Ensure Rust toolchain is properly installed:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shEnsure Zig is properly installed and in PATH:
zig version- Ensure you're using the correct shell (PowerShell or Git Bash)
- May need to set environment variables pointing to compiler paths
- When using MinGW, ensure the toolchain is in PATH