diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cd96cb..32b57c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,71 +1,62 @@ name: CI on: + pull_request: push: - branches: ["*"] + branches: + - main + paths: + - "lib/**/*" + - "test/**/*" + - "native/**/*" env: MIX_ENV: test + BLAKE3_BUILD: true jobs: test: - name: OTP ${{ matrix.otp }} / Elixir ${{ matrix.elixir }} / Rust ${{ matrix.rust }} + name: Elixir ${{ matrix.pair.elixir }} / OTP ${{ matrix.pair.otp }} runs-on: ubuntu-20.04 + strategy: + fail-fast: false matrix: - elixir: ["1.13", "1.14", "1.15"] - otp: ["23", "24", "25", "26"] - rust: ["stable"] - exclude: - - elixir: "1.14" - otp: "24" - - elixir: "1.13" - otp: "25" - - elixir: "1.13" - otp: "26" - - elixir: "1.15" - otp: "23" - + include: + - pair: + elixir: 1.14.3 + otp: 25.2.1 + - pair: + elixir: 1.15.6 + otp: 26.1 + lint: lint steps: - - name: Checkout code - uses: actions/checkout@v3 - - uses: erlef/setup-beam@v1 - with: - otp-version: ${{ matrix.otp }} - elixir-version: ${{ matrix.elixir }} - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - - name: Cache Elixir deps - uses: actions/cache@v3 - with: - path: | - deps - _build - key: deps-cache-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles('**/mix.lock') }} - restore-keys: | - deps-cache-${{ matrix.elixir }}-${{ matrix.otp }}- - - name: Cache Rust deps - uses: actions/cache@v3 + - uses: actions/checkout@v3 + + - uses: erlef/setup-beam@v1.15 with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - key: ${{ matrix.rust }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ matrix.rust }}-cargo- - - name: Install elixir dependencies - run: mix do local.hex --force, local.rebar --force, deps.get - - name: Check code formatting + otp-version: ${{ matrix.pair.otp }} + elixir-version: ${{ matrix.pair.elixir }} + + - name: Install minimal stable Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install Dependencies + run: mix deps.get + + - name: Check formatting run: mix format --check-formatted - - name: Compile dependencies + if: ${{ matrix.lint }} + + - name: Check unused deps + run: mix deps.unlock --check-unused + if: ${{ matrix.lint }} + + - name: Compile deps run: mix deps.compile - - name: Compile code (warnings as errors) + + - name: Compile run: mix compile --warnings-as-errors - - name: Run tests + + - name: Test run: mix test - - name: Create docs - run: mix docs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f7b700..6e2451c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,31 +1,68 @@ -name: Release +name: Build precompiled NIFs + on: - release: - types: [released] + push: + tags: + - 'v*.*.*' jobs: - release: - name: Publish release - runs-on: ubuntu-latest + build_release: + name: NIF ${{ matrix.nif }} - ${{ matrix.job.target }} (${{ matrix.job.os }}) + permissions: + contents: write + runs-on: ${{ matrix.job.os }} + strategy: + fail-fast: false + matrix: + nif: ["2.15"] + job: + - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04 , use-cross: true } + - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04 , use-cross: true } + - { target: aarch64-unknown-linux-musl , os: ubuntu-20.04 , use-cross: true } + - { target: aarch64-apple-darwin , os: macos-12 } + - { target: x86_64-apple-darwin , os: macos-12 } + - { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 } + - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04 , use-cross: true } + - { target: x86_64-pc-windows-gnu , os: windows-2019 } + - { target: x86_64-pc-windows-msvc , os: windows-2019 } + - { target: x86_64-unknown-freebsd, os: ubuntu-22.04, use-cross: true, cross-version: v0.2.5 } steps: - - name: Display build environment - run: printenv - - name: Checkout code - uses: actions/checkout@v3 + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Extract project version + shell: bash + run: | + # Get the project version from mix.exs + echo "PROJECT_VERSION=$(sed -n 's/^ @version "\(.*\)"/\1/p' mix.exs | head -n1)" >> $GITHUB_ENV + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + target: ${{ matrix.job.target }} + + - name: Build the project + id: build-crate + uses: philss/rustler-precompiled-action@v1.1.0 + with: + project-name: blake3 + project-version: ${{ env.PROJECT_VERSION }} + target: ${{ matrix.job.target }} + nif-version: ${{ matrix.nif }} + use-cross: ${{ matrix.job.use-cross }} + cross-version: ${{ matrix.job.cross-version || 'v0.2.4' }} + project-dir: "native/blake3" - - uses: erlef/setup-beam@v1 - with: - otp-version: "25" - elixir-version: "1.14" - - name: Install dependencies - run: mix do local.hex --force, local.rebar --force, deps.get + - name: Artifact upload + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.build-crate.outputs.file-name }} + path: ${{ steps.build-crate.outputs.file-path }} - - name: Compile code - run: mix compile - - name: Create docs - run: mix docs - - name: Publish release - run: mix hex.publish --yes - env: - HEX_API_KEY: ${{ secrets.HEX_API_KEY }} + - name: Publish archives and packages + uses: softprops/action-gh-release@v1 + with: + files: | + ${{ steps.build-crate.outputs.file-path }} + if: startsWith(github.ref, 'refs/tags/') diff --git a/checksum-Elixir.Blake3.Native.exs b/checksum-Elixir.Blake3.Native.exs new file mode 100644 index 0000000..279e3f0 --- /dev/null +++ b/checksum-Elixir.Blake3.Native.exs @@ -0,0 +1,11 @@ +%{ + "blake3-v1.0.3-nif-2.15-x86_64-pc-windows-gnu.dll.tar.gz" => "sha256:fa25a68693a0824c299ab0717bc46849272c0681b863fb3494c31e2871b29169", + "blake3-v1.0.3-nif-2.15-x86_64-pc-windows-msvc.dll.tar.gz" => "sha256:e8c595c68d021e66ef07bc5468a205764bf84c45a14c02762fa503bd87055fc4", + "libblake3-v1.0.3-nif-2.15-aarch64-apple-darwin.so.tar.gz" => "sha256:cc48c5d41911a6e947b36b12f5345e4c07ee273ca1389eaa0d67970095684276", + "libblake3-v1.0.3-nif-2.15-aarch64-unknown-linux-gnu.so.tar.gz" => "sha256:0907ed122301b1acfe0c6a2de68445a7df60adf27d3444638b87026795935a1a", + "libblake3-v1.0.3-nif-2.15-aarch64-unknown-linux-musl.so.tar.gz" => "sha256:459998cb86bf18207f2ac5fce17db528cec1d842cd8f73aaeac7a62e9ca86dc3", + "libblake3-v1.0.3-nif-2.15-arm-unknown-linux-gnueabihf.so.tar.gz" => "sha256:69e2aca5a84f779938065420a9196bbebf2fb5c7567cc31c999ec9c9694fe587", + "libblake3-v1.0.3-nif-2.15-x86_64-apple-darwin.so.tar.gz" => "sha256:1e4278e95d1b418ac0deb892fae4c4bbc938fd6b41e658c67e4c53fae0dc422c", + "libblake3-v1.0.3-nif-2.15-x86_64-unknown-linux-gnu.so.tar.gz" => "sha256:ded52eadc26c3f46d456419c1f1186da051483f26f3bb9ae734b7ec75a7dbb8f", + "libblake3-v1.0.3-nif-2.15-x86_64-unknown-linux-musl.so.tar.gz" => "sha256:3506cd9aefee8b28b1f33e8c3464343974c63aa8542ccc1853924f315f1726df", +} diff --git a/config/config.exs b/config/config.exs index 080e2b8..b272e0d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,5 +1,7 @@ import Config +config :blake3, source_url: "https://github.com/royal-markets/blake3" + config :blake3, Blake3.Native, mode: :release, features: MixBlake3.Project.config_features() diff --git a/lib/blake3/native.ex b/lib/blake3/native.ex index d1137d1..799c5f7 100644 --- a/lib/blake3/native.ex +++ b/lib/blake3/native.ex @@ -3,9 +3,30 @@ defmodule Blake3.Native do Blake3.Native is the rustler module that will be replaced with the nif rust functions. This module doesn't need to be called direcly. """ + config = Mix.Project.config() + version = config[:version] - use Rustler, - otp_app: :blake3 + force_build = Application.compile_env(:rustler_precompiled, :force_build, []) + source_url = Application.compile_env(:blake3, :source_url, config[:source_url]) + + use RustlerPrecompiled, + otp_app: :blake3, + crate: "blake3", + base_url: "#{source_url}/releases/download/v#{version}", + force_build: System.get_env("BLAKE3_BUILD") in ["1", "true"] or force_build[:blake3], + nif_versions: ["2.15"], + targets: [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "arm-unknown-linux-gnueabihf", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl" + ], + version: version def hash(_str), do: error() def new(), do: error() diff --git a/mix.exs b/mix.exs index d972aa3..7899334 100644 --- a/mix.exs +++ b/mix.exs @@ -1,16 +1,23 @@ defmodule MixBlake3.Project do use Mix.Project + @source_url "https://github.com/Thomas-Jean/blake3" + @version "1.0.3" + + @rayon Application.compile_env(:blake3, :rayon, System.get_env("BLAKE3_RAYON")) + @simd_mode Application.compile_env(:blake3, :simd_mode, System.get_env("BLAKE3_SIMD_MODE")) + def project do [ app: :blake3, - version: "1.0.2", + version: @version, elixir: "~> 1.13", build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, deps: deps(), docs: docs(), - package: package() + package: package(), + source_url: @source_url ] end @@ -21,15 +28,24 @@ defmodule MixBlake3.Project do defp package() do [ description: "Elixir binding for the Rust Blake3 implementation", - files: ["lib", "native", ".formatter.exs", "README*", "LICENSE*", "mix.exs"], + files: [ + "lib", + "native", + ".formatter.exs", + "README*", + "LICENSE*", + "mix.exs", + "checksum-*.exs" + ], licenses: ["Apache-2.0"], - links: %{"GitHub" => "https://github.com/Thomas-Jean/blake3"} + links: %{"GitHub" => @source_url} ] end defp deps do [ - {:rustler, "~> 0.30"}, + {:rustler, "~> 0.30", optional: true}, + {:rustler_precompiled, "~> 0.7"}, {:ex_doc, "~> 0.21", only: [:dev, :test], runtime: false} ] end @@ -38,13 +54,13 @@ defmodule MixBlake3.Project do [ extras: ["README.md"], main: "readme", - source_url: "https://github.com/Thomas-Jean/blake3" + source_url: @source_url ] end def config_features() do simd = - case Application.get_env(:blake3, :simd_mode) || System.get_env("BLAKE3_SIMD_MODE") do + case @simd_mode do "c_neon" -> "neon" :c_neon -> "neon" "neon" -> "neon" @@ -52,12 +68,7 @@ defmodule MixBlake3.Project do _ -> nil end - rayon = - if !is_nil(Application.get_env(:blake3, :rayon) || System.get_env("BLAKE3_RAYON")) do - "rayon" - else - nil - end + rayon = if @rayon, do: "rayon", else: nil Enum.reject([simd, rayon], &is_nil/1) end diff --git a/mix.lock b/mix.lock index bc05981..d21d3a8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, + "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, "earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"}, "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, @@ -8,5 +8,6 @@ "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.0", "9e18a119d9efc3370a3ef2a937bf0b24c088d9c4bf0ba9d7c3751d49d347d035", [:mix], [], "hexpm", "7977f183127a7cbe9346981e2f480dc04c55ffddaef746bd58debd566070eef8"}, "rustler": {:hex, :rustler, "0.30.0", "cefc49922132b072853fa9b0ca4dc2ffcb452f68fb73b779042b02d545e097fb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "9ef1abb6a7dda35c47cfc649e6a5a61663af6cf842a55814a554a84607dee389"}, + "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.1", "ecadf02cc59a0eccbaed6c1937303a5827fbcf60010c541595e6d3747d3d0f9f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "b9e4657b99a1483ea31502e1d58c464bedebe9028808eda45c3a429af4550c66"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, } diff --git a/native/blake3/.cargo/config b/native/blake3/.cargo/config index e27a6c4..2c83f15 100644 --- a/native/blake3/.cargo/config +++ b/native/blake3/.cargo/config @@ -1,10 +1,20 @@ -[target.x86_64-apple-darwin] +[target.'cfg(target_os = "macos")'] rustflags = [ - "-C", "link-arg=-undefined", - "-C", "link-arg=dynamic_lookup", + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", ] -[target.aarch64-apple-darwin] + +# See https://github.com/rust-lang/rust/issues/59302 +[target.x86_64-unknown-linux-musl] rustflags = [ - "-C", "link-arg=-undefined", - "-C", "link-arg=dynamic_lookup", + "-C", "target-feature=-crt-static" ] + +[target.aarch64-unknown-linux-musl] +rustflags = [ + "-C", "target-feature=-crt-static" +] + +# Provides a small build size, but takes more time to build. +[profile.release] +lto = true diff --git a/native/blake3/Cross.toml b/native/blake3/Cross.toml new file mode 100644 index 0000000..8ba543c --- /dev/null +++ b/native/blake3/Cross.toml @@ -0,0 +1,4 @@ +[build.env] +passthrough = [ + "RUSTLER_NIF_VERSION" +]