Skip to content

Commit ad18a73

Browse files
Add example project (#3)
Co-authored-by: Jonatan Kłosko <[email protected]>
1 parent 6699668 commit ad18a73

File tree

13 files changed

+157
-1
lines changed

13 files changed

+157
-1
lines changed

.github/workflows/ci.yml

+8-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
with:
1818
otp-version: "27.2"
1919
elixir-version: "1.18.2"
20-
- run: mix deps.get
20+
- run: mix deps.get --check-locked
2121
- run: mix deps.compile
2222
- run: mix format --check-formatted
2323
- run: mix deps.unlock --check-unused
@@ -59,3 +59,10 @@ jobs:
5959
working-directory: test
6060
- run: mix test
6161
working-directory: test
62+
- name: Test example/
63+
run: |
64+
mix deps.get --check-locked
65+
mix format --check-formatted
66+
mix deps.unlock --check-unused
67+
mix test --warnings-as-errors
68+
working-directory: example

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ FINE_NIF(add, 0);
110110
FINE_INIT("Elixir.MyLib.NIF");
111111
```
112112
113+
See [`example/`](https://github.com/elixir-nx/fine/tree/main/example) project.
114+
113115
## Encoding/Decoding
114116

115117
Terms are automatically encoded and decoded at the NIF boundary based

example/.formatter.exs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

example/.gitignore

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# If the VM crashes, it generates a dump, let's ignore it too.
14+
erl_crash.dump
15+
16+
# Also ignore archive artifacts (built via "mix archive.build").
17+
*.ez
18+
19+
# Ignore package tarball (built via "mix hex.build").
20+
example-*.tar
21+
22+
# Temporary files, for example, from tests.
23+
/tmp/

example/Makefile

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
PRIV_DIR := $(MIX_APP_PATH)/priv
2+
NIF_PATH := $(PRIV_DIR)/libexample.so
3+
C_SRC := $(shell pwd)/c_src
4+
5+
CPPFLAGS := -shared -fPIC -std=c++17 -Wall -Wextra
6+
CPPFLAGS += -I$(ERTS_INCLUDE_DIR) -I$(FINE_INCLUDE_DIR)
7+
8+
ifdef DEBUG
9+
CPPFLAGS += -g
10+
else
11+
CPPFLAGS += -O3
12+
endif
13+
14+
ifndef TARGET_ABI
15+
TARGET_ABI := $(shell uname -s | tr '[:upper:]' '[:lower:]')
16+
endif
17+
18+
ifeq ($(TARGET_ABI),darwin)
19+
CPPFLAGS += -undefined dynamic_lookup -flat_namespace
20+
endif
21+
22+
SOURCES := $(wildcard $(C_SRC)/*.cpp)
23+
24+
all: $(NIF_PATH)
25+
@ echo > /dev/null # Dummy command to avoid the default output "Nothing to be done"
26+
27+
$(NIF_PATH): $(SOURCES)
28+
@ mkdir -p $(PRIV_DIR)
29+
$(CXX) $(CPPFLAGS) $(SOURCES) -o $(NIF_PATH)

example/Makefile.win

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
PRIV_DIR=$(MIX_APP_PATH)\priv
2+
NIF_PATH=$(PRIV_DIR)\libexample.dll
3+
4+
C_SRC=$(MAKEDIR)\c_src
5+
CPPFLAGS=/LD /std:c++17 /W4 /O2 /EHsc
6+
CPPFLAGS=$(CPPFLAGS) /I"$(ERTS_INCLUDE_DIR)" /I"$(FINE_INCLUDE_DIR)"
7+
8+
SOURCES=$(C_SRC)\*.cpp
9+
10+
all: $(NIF_PATH)
11+
12+
$(NIF_PATH): $(SOURCES)
13+
@ if not exist "$(PRIV_DIR)" mkdir "$(PRIV_DIR)"
14+
cl $(CPPFLAGS) $(SOURCES) /Fe"$(NIF_PATH)"

example/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Example
2+
3+
Example project using Fine to implement NIFs.
4+
5+
To run tests, execute:
6+
7+
```shell
8+
$ mix deps.get
9+
$ mix test
10+
```

example/c_src/example.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <fine.hpp>
2+
3+
int64_t add(ErlNifEnv *env, int64_t x, int64_t y) {
4+
return x + y;
5+
}
6+
7+
FINE_NIF(add, 0);
8+
FINE_INIT("Elixir.Example");

example/lib/example.ex

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
defmodule Example do
2+
@on_load :__on_load__
3+
4+
def __on_load__ do
5+
path = :filename.join(:code.priv_dir(:example), ~c"libexample")
6+
7+
case :erlang.load_nif(path, 0) do
8+
:ok -> :ok
9+
{:error, reason} -> raise "failed to load NIF library, reason: #{inspect(reason)}"
10+
end
11+
end
12+
13+
@doc """
14+
Adds two numbers using NIF.
15+
16+
## Examples
17+
18+
iex> Example.add(1, 2)
19+
3
20+
"""
21+
def add(_x, _y) do
22+
:erlang.nif_error("nif not loaded")
23+
end
24+
end

example/mix.exs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
defmodule Example.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :example,
7+
version: "0.1.0",
8+
elixir: "~> 1.15",
9+
compilers: [:elixir_make] ++ Mix.compilers(),
10+
make_env: fn -> %{"FINE_INCLUDE_DIR" => Fine.include_dir()} end,
11+
deps: deps()
12+
]
13+
end
14+
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
defp deps do
22+
[
23+
{:elixir_make, "~> 0.9.0"},
24+
{:fine, path: ".."}
25+
]
26+
end
27+
end

example/mix.lock

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
%{
2+
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
3+
}

example/test/example_test.exs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
defmodule ExampleTest do
2+
use ExUnit.Case, async: true
3+
doctest Example
4+
end

example/test/test_helper.exs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExUnit.start()

0 commit comments

Comments
 (0)