From 4778a17822033619e1562e8b13cd70662be5500d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20D=C4=85browski?= Date: Wed, 20 May 2026 14:35:34 +0200 Subject: [PATCH] project init --- .envrc | 1 + .formatter.exs | 4 + .gitignore | 26 ++++ .gitmodules | 3 + Makefile | 36 +++++ README.md | 21 +++ c_src/CMakeLists.txt | 65 +++++++++ c_src/chromaprint_nif.cpp | 282 ++++++++++++++++++++++++++++++++++++++ flake.lock | 26 ++++ flake.nix | 30 ++++ mix.exs | 70 ++++++++++ mix.lock | 3 + 12 files changed, 567 insertions(+) create mode 100644 .envrc create mode 100644 .formatter.exs create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 README.md create mode 100644 c_src/CMakeLists.txt create mode 100644 c_src/chromaprint_nif.cpp create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 mix.exs create mode 100644 mix.lock diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c34192b --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Temporary files, for example, from tests. +/tmp/ + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +chromaprint-*.tar + +/.direnv/ +/.state/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4c3488f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "c_src/chromaprint"] + path = c_src/chromaprint + url = https://github.com/acoustid/chromaprint.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e95ca92 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +PRIV_DIR := $(MIX_APP_PATH)/priv +BUILD_DIR := $(MIX_APP_PATH)/cmake_build +NIF_SO := $(PRIV_DIR)/chromaprint_nif.so +JOBS ?= $(shell nproc 2>/dev/null || echo 4) +CMAKE_BUILD_TYPE ?= Release +CHROMAPRINT_USE_SYSTEM ?= OFF + +CMAKE_EXTRA_ARGS ?= + +ifneq ($(strip $(CHROMAPRINT_INCLUDE_DIR)),) +CMAKE_EXTRA_ARGS += -DCHROMAPRINT_INCLUDE_DIR=$(CHROMAPRINT_INCLUDE_DIR) +endif +ifneq ($(strip $(CHROMAPRINT_LIB_DIR)),) +CMAKE_EXTRA_ARGS += -DCMAKE_LIBRARY_PATH=$(CHROMAPRINT_LIB_DIR) +endif + +.PHONY: all clean + +all: $(NIF_SO) + +$(NIF_SO): $(BUILD_DIR)/CMakeCache.txt + @mkdir -p $(PRIV_DIR) + cmake --build $(BUILD_DIR) --config $(CMAKE_BUILD_TYPE) -j $(JOBS) + cmake --install $(BUILD_DIR) + +$(BUILD_DIR)/CMakeCache.txt: + @mkdir -p $(BUILD_DIR) + cmake -S c_src -B $(BUILD_DIR) \ + -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ + -DERTS_INCLUDE_DIR=$(ERTS_INCLUDE_DIR) \ + -DPRIV_DIR=$(PRIV_DIR) \ + -DCHROMAPRINT_USE_SYSTEM=$(CHROMAPRINT_USE_SYSTEM) \ + $(CMAKE_EXTRA_ARGS) + +clean: + rm -rf $(BUILD_DIR) $(NIF_SO) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9077a1 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Chromaprint + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `chromaprint` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:chromaprint, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at . + diff --git a/c_src/CMakeLists.txt b/c_src/CMakeLists.txt new file mode 100644 index 0000000..98b3cb9 --- /dev/null +++ b/c_src/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 3.10) +project(chromaprint_nif LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if(NOT ERTS_INCLUDE_DIR) + message(FATAL_ERROR "ERTS_INCLUDE_DIR is required (path to erts-x.y.z/include)") +endif() +if(NOT PRIV_DIR) + message(FATAL_ERROR "PRIV_DIR is required (mix app priv/ directory)") +endif() + +option(CHROMAPRINT_USE_SYSTEM "Link against a system-provided libchromaprint" OFF) + +if(CHROMAPRINT_USE_SYSTEM) + find_path(CHROMAPRINT_INCLUDE_DIR chromaprint.h) + find_library(CHROMAPRINT_LIBRARY NAMES chromaprint) + if(NOT CHROMAPRINT_INCLUDE_DIR OR NOT CHROMAPRINT_LIBRARY) + message(FATAL_ERROR + "CHROMAPRINT_USE_SYSTEM=ON but chromaprint.h or libchromaprint not found. " + "Set CHROMAPRINT_INCLUDE_DIR and CMAKE_LIBRARY_PATH (or CMAKE_PREFIX_PATH).") + endif() + message(STATUS "Using system chromaprint: ${CHROMAPRINT_LIBRARY}") + add_library(chromaprint_dep INTERFACE) + target_include_directories(chromaprint_dep INTERFACE "${CHROMAPRINT_INCLUDE_DIR}") + target_link_libraries(chromaprint_dep INTERFACE "${CHROMAPRINT_LIBRARY}") +else() + message(STATUS "Building vendored chromaprint (c_src/chromaprint)") + set(BUILD_TOOLS OFF CACHE BOOL "" FORCE) + set(BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + set(BUILD_FRAMEWORK OFF CACHE BOOL "" FORCE) + set(FFT_LIB "kissfft" CACHE STRING "" FORCE) + # FindKissFFT.cmake searches CMAKE_SOURCE_DIR/src/3rdparty/kissfft, which would + # resolve to c_src/src/... when chromaprint is added as a subdirectory. Point + # it at the vendored copy inside the submodule. + set(KISSFFT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/chromaprint/src/3rdparty/kissfft" + CACHE PATH "" FORCE) + add_subdirectory(chromaprint EXCLUDE_FROM_ALL) + add_library(chromaprint_dep INTERFACE) + target_link_libraries(chromaprint_dep INTERFACE chromaprint) + target_include_directories(chromaprint_dep INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/chromaprint/src") +endif() + +add_library(chromaprint_nif SHARED chromaprint_nif.cpp) + +set_target_properties(chromaprint_nif PROPERTIES + PREFIX "" + SUFFIX ".so" +) + +target_include_directories(chromaprint_nif PRIVATE "${ERTS_INCLUDE_DIR}") +target_link_libraries(chromaprint_nif PRIVATE chromaprint_dep) + +if(APPLE) + set_target_properties(chromaprint_nif PROPERTIES + LINK_FLAGS "-flat_namespace -undefined suppress") +endif() + +install(TARGETS chromaprint_nif + LIBRARY DESTINATION "${PRIV_DIR}" + RUNTIME DESTINATION "${PRIV_DIR}") diff --git a/c_src/chromaprint_nif.cpp b/c_src/chromaprint_nif.cpp new file mode 100644 index 0000000..4613f2a --- /dev/null +++ b/c_src/chromaprint_nif.cpp @@ -0,0 +1,282 @@ +#include +#include + +#include +#include +#include + +namespace { + +ErlNifResourceType *CHROMAPRINT_CTX_RES = nullptr; + +struct ChromaprintCtxRes { + ChromaprintContext *ctx; +}; + +ERL_NIF_TERM ATOM_OK; +ERL_NIF_TERM ATOM_ERROR; +ERL_NIF_TERM ATOM_TRUE; +ERL_NIF_TERM ATOM_FALSE; +ERL_NIF_TERM ATOM_BADARG; +ERL_NIF_TERM ATOM_ALLOC_FAILED; +ERL_NIF_TERM ATOM_CHROMAPRINT_FAILED; +ERL_NIF_TERM ATOM_NIL; + +inline ERL_NIF_TERM mk_atom(ErlNifEnv *env, const char *name) { + ERL_NIF_TERM atom; + if (enif_make_existing_atom(env, name, &atom, ERL_NIF_LATIN1)) return atom; + return enif_make_atom(env, name); +} + +inline ERL_NIF_TERM ok_tuple(ErlNifEnv *env, ERL_NIF_TERM value) { + return enif_make_tuple2(env, ATOM_OK, value); +} + +inline ERL_NIF_TERM error_tuple(ErlNifEnv *env, ERL_NIF_TERM reason) { + return enif_make_tuple2(env, ATOM_ERROR, reason); +} + +void destruct_ctx(ErlNifEnv * /*env*/, void *obj) { + auto *res = static_cast(obj); + if (res->ctx != nullptr) { + chromaprint_free(res->ctx); + res->ctx = nullptr; + } +} + +bool get_bool(ErlNifEnv *env, ERL_NIF_TERM term, int *out) { + if (enif_compare(term, ATOM_TRUE) == 0) { + *out = 1; + return true; + } + if (enif_compare(term, ATOM_FALSE) == 0) { + *out = 0; + return true; + } + return false; +} + +ERL_NIF_TERM new_context(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + int algorithm; + if (!enif_get_int(env, argv[0], &algorithm)) { + return enif_make_badarg(env); + } + ChromaprintContext *ctx = chromaprint_new(algorithm); + if (ctx == nullptr) { + return error_tuple(env, ATOM_ALLOC_FAILED); + } + auto *res = static_cast( + enif_alloc_resource(CHROMAPRINT_CTX_RES, sizeof(ChromaprintCtxRes))); + res->ctx = ctx; + ERL_NIF_TERM term = enif_make_resource(env, res); + enif_release_resource(res); + return ok_tuple(env, term); +} + +ERL_NIF_TERM nif_start(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + int sample_rate; + int channels; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res) || + !enif_get_int(env, argv[1], &sample_rate) || + !enif_get_int(env, argv[2], &channels)) { + return enif_make_badarg(env); + } + if (chromaprint_start(res->ctx, sample_rate, channels) != 1) { + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + return ATOM_OK; +} + +ERL_NIF_TERM nif_feed(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + ErlNifBinary bin; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res) || + !enif_inspect_binary(env, argv[1], &bin)) { + return enif_make_badarg(env); + } + if (bin.size % 2 != 0) { + return error_tuple(env, ATOM_BADARG); + } + const auto *samples = reinterpret_cast(bin.data); + const int sample_count = static_cast(bin.size / 2); + if (chromaprint_feed(res->ctx, samples, sample_count) != 1) { + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + return ATOM_OK; +} + +ERL_NIF_TERM nif_finish(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) { + return enif_make_badarg(env); + } + if (chromaprint_finish(res->ctx) != 1) { + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + return ATOM_OK; +} + +ERL_NIF_TERM nif_get_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) { + return enif_make_badarg(env); + } + char *fp = nullptr; + if (chromaprint_get_fingerprint(res->ctx, &fp) != 1 || fp == nullptr) { + if (fp != nullptr) chromaprint_dealloc(fp); + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + const std::size_t len = std::strlen(fp); + ERL_NIF_TERM bin_term; + unsigned char *buf = enif_make_new_binary(env, len, &bin_term); + std::memcpy(buf, fp, len); + chromaprint_dealloc(fp); + return ok_tuple(env, bin_term); +} + +ERL_NIF_TERM nif_get_raw_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) { + return enif_make_badarg(env); + } + uint32_t *fp = nullptr; + int size = 0; + if (chromaprint_get_raw_fingerprint(res->ctx, &fp, &size) != 1 || fp == nullptr) { + if (fp != nullptr) chromaprint_dealloc(fp); + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + std::vector items; + items.reserve(size); + for (int i = 0; i < size; ++i) { + items.push_back(enif_make_uint(env, fp[i])); + } + chromaprint_dealloc(fp); + ERL_NIF_TERM list = + items.empty() ? enif_make_list(env, 0) + : enif_make_list_from_array(env, items.data(), + static_cast(items.size())); + return ok_tuple(env, list); +} + +ERL_NIF_TERM nif_get_fingerprint_hash(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ChromaprintCtxRes *res; + if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) { + return enif_make_badarg(env); + } + uint32_t hash = 0; + if (chromaprint_get_fingerprint_hash(res->ctx, &hash) != 1) { + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + return ok_tuple(env, enif_make_uint(env, hash)); +} + +ERL_NIF_TERM nif_encode_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + unsigned int list_len = 0; + if (!enif_get_list_length(env, argv[0], &list_len)) { + return enif_make_badarg(env); + } + int algorithm; + int base64; + if (!enif_get_int(env, argv[1], &algorithm) || !get_bool(env, argv[2], &base64)) { + return enif_make_badarg(env); + } + std::vector raw; + raw.reserve(list_len); + ERL_NIF_TERM head; + ERL_NIF_TERM tail = argv[0]; + while (enif_get_list_cell(env, tail, &head, &tail)) { + unsigned int val; + if (!enif_get_uint(env, head, &val)) { + return enif_make_badarg(env); + } + raw.push_back(val); + } + char *encoded = nullptr; + int encoded_size = 0; + if (chromaprint_encode_fingerprint(raw.data(), static_cast(raw.size()), algorithm, + &encoded, &encoded_size, base64) != 1 || + encoded == nullptr) { + if (encoded != nullptr) chromaprint_dealloc(encoded); + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + ERL_NIF_TERM bin_term; + unsigned char *buf = + enif_make_new_binary(env, static_cast(encoded_size), &bin_term); + std::memcpy(buf, encoded, static_cast(encoded_size)); + chromaprint_dealloc(encoded); + return ok_tuple(env, bin_term); +} + +ERL_NIF_TERM nif_decode_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) { + ErlNifBinary bin; + int base64; + if (!enif_inspect_binary(env, argv[0], &bin) || !get_bool(env, argv[1], &base64)) { + return enif_make_badarg(env); + } + uint32_t *raw = nullptr; + int size = 0; + int algorithm = 0; + if (chromaprint_decode_fingerprint(reinterpret_cast(bin.data), + static_cast(bin.size), &raw, &size, &algorithm, + base64) != 1 || + raw == nullptr) { + if (raw != nullptr) chromaprint_dealloc(raw); + return error_tuple(env, ATOM_CHROMAPRINT_FAILED); + } + std::vector items; + items.reserve(size); + for (int i = 0; i < size; ++i) { + items.push_back(enif_make_uint(env, raw[i])); + } + chromaprint_dealloc(raw); + ERL_NIF_TERM list = + items.empty() ? enif_make_list(env, 0) + : enif_make_list_from_array(env, items.data(), + static_cast(items.size())); + ERL_NIF_TERM pair = enif_make_tuple2(env, enif_make_int(env, algorithm), list); + return ok_tuple(env, pair); +} + +ERL_NIF_TERM nif_version(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM * /*argv*/) { + const char *v = chromaprint_get_version(); + if (v == nullptr) return ATOM_NIL; + const std::size_t len = std::strlen(v); + ERL_NIF_TERM bin_term; + unsigned char *buf = enif_make_new_binary(env, len, &bin_term); + std::memcpy(buf, v, len); + return bin_term; +} + +int load(ErlNifEnv *env, void ** /*priv_data*/, ERL_NIF_TERM /*load_info*/) { + CHROMAPRINT_CTX_RES = enif_open_resource_type(env, nullptr, "ChromaprintContext", + destruct_ctx, ERL_NIF_RT_CREATE, nullptr); + if (CHROMAPRINT_CTX_RES == nullptr) return -1; + + ATOM_OK = mk_atom(env, "ok"); + ATOM_ERROR = mk_atom(env, "error"); + ATOM_TRUE = mk_atom(env, "true"); + ATOM_FALSE = mk_atom(env, "false"); + ATOM_BADARG = mk_atom(env, "badarg"); + ATOM_ALLOC_FAILED = mk_atom(env, "alloc_failed"); + ATOM_CHROMAPRINT_FAILED = mk_atom(env, "chromaprint_failed"); + ATOM_NIL = mk_atom(env, "nil"); + return 0; +} + +ErlNifFunc funcs[] = { + {"new_context", 1, new_context, 0}, + {"start", 3, nif_start, 0}, + {"feed", 2, nif_feed, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"finish", 1, nif_finish, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"get_fingerprint", 1, nif_get_fingerprint, 0}, + {"get_raw_fingerprint", 1, nif_get_raw_fingerprint, 0}, + {"get_fingerprint_hash", 1, nif_get_fingerprint_hash, 0}, + {"encode_fingerprint", 3, nif_encode_fingerprint, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"decode_fingerprint", 2, nif_decode_fingerprint, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"version", 0, nif_version, 0}, +}; + +} // namespace + +ERL_NIF_INIT(Elixir.Chromaprint.NIF, funcs, load, nullptr, nullptr, nullptr) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..e3ec46e --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1774386573, + "narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f66f731 --- /dev/null +++ b/flake.nix @@ -0,0 +1,30 @@ +{ + inputs = { nixpkgs.url = "nixpkgs/nixos-unstable"; }; + + outputs = { self, nixpkgs }: { + devShell.x86_64-linux = let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + beam = pkgs.beam.packages.erlang_28; + elixir = beam.elixir_1_20; + elixir-ls = (beam.elixir-ls.override { inherit elixir; }); + in pkgs.mkShell { + buildInputs = [ + elixir + elixir-ls + pkgs.cmake + pkgs.gnumake + pkgs.git + ]; + shellHook = '' + mkdir -p .state/mix .state/hex + export MIX_HOME=$PWD/.state/mix + export HEX_HOME=$PWD/.state/hex + export PATH=$MIX_HOME/bin:$MIX_HOME/escripts:$HEX_HOME/bin:$PATH + mix local.hex --if-missing --force + export LANG=en_US.UTF-8 + export ERL_AFLAGS="-kernel shell_history enabled -kernel shell_history_path '\"$PWD/.state\"' -kernel shell_history_file_bytes 1024000" + ''; + }; + }; +} diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..ff9ebf0 --- /dev/null +++ b/mix.exs @@ -0,0 +1,70 @@ +defmodule Chromaprint.MixProject do + use Mix.Project + + def project do + [ + app: :chromaprint, + version: "0.1.0", + elixir: "~> 1.20-rc", + start_permanent: Mix.env() == :prod, + deps: deps(), + compilers: [:elixir_make] ++ Mix.compilers(), + make_targets: ["all"], + make_clean: ["clean"], + make_env: &make_env/0 + ] + end + + def application do + [ + extra_applications: [:logger] + ] + end + + defp deps do + [ + {:elixir_make, "~> 0.9", runtime: false}, + ] + end + + defp make_env do + verify_chromaprint_source!() + + %{ + "ERTS_INCLUDE_DIR" => erts_include_dir(), + "CHROMAPRINT_USE_SYSTEM" => + if(System.get_env("CHROMAPRINT_USE_SYSTEM") in ~w(1 true on ON YES yes), + do: "ON", + else: "OFF" + ) + } + end + + defp erts_include_dir do + Path.join([ + :code.root_dir() |> to_string(), + "erts-#{:erlang.system_info(:version)}", + "include" + ]) + end + + defp verify_chromaprint_source! do + use_system = System.get_env("CHROMAPRINT_USE_SYSTEM") in ~w(1 true on ON YES yes) + submodule_cmake = Path.join([__DIR__, "c_src", "chromaprint", "CMakeLists.txt"]) + + if not use_system and not File.exists?(submodule_cmake) do + Mix.raise(""" + The chromaprint source submodule is missing at c_src/chromaprint/. + + Either initialise it: + + git submodule update --init c_src/chromaprint + + Or, to link against a system-provided libchromaprint (recommended for + Nix and other sandboxed builds), set CHROMAPRINT_USE_SYSTEM=1 and ensure + chromaprint.h and libchromaprint can be found via the compiler's default + paths (or CHROMAPRINT_INCLUDE_DIR / CHROMAPRINT_LIB_DIR if not). + """) + end + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..0e11663 --- /dev/null +++ b/mix.lock @@ -0,0 +1,3 @@ +%{ + "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, +}