evision icon indicating copy to clipboard operation
evision copied to clipboard

Getting evision up and running on FreeBSD

Open marschro opened this issue 7 months ago • 9 comments

Setup

  • Running an Elixir Phoenix App that uses Image
  • Image makes use of Image.Video and thus needs evision as dependency
  • The setup works perfect on local development machine (macOS), but I totally forgot to test if its seamlessly deployable to my infrastructure, running on FreeBSD... well, it isn't... ;-)

Goals

  • A precompiled version for FreeBSD 14.2

Current State and Progress

  • I created a small mix project with little dependency
    def deps do
        [
            {:evision, "~> 0.2"}
        ]
    end
    
  • I compiled evision on a FreeBSD 14.2 remote machine
    • pkg install cmake gmake python bash opencv
    • mix deps.get && env MAKE=gmake env MIX_ENV=prod mix deps.compile
  • I guess the crucial part is:
    _build/prod/lib/evision/ebin/
    _build/prod/lib/evision/priv/
    _build/prod/lib/evision/cmake_evision/
    _build/prod/lib/evision/cmake_opencv_4.11.0/
    _build/prod/lib/evision/.mix
    
  • Next question: how to make this available for my or other projects

Info

  • I update this during my findings
  • Looping in @dch as this is again a FreeBSD thingy...

marschro avatar Apr 09 '25 09:04 marschro

what sort of errors did you get? setup in 14.2-RELEASE amd64 jail:

setup

  • ports has v5 ffmpeg, opencv 4.9
# pkg install -yr FreeBSD ninja  multimedia/ffmpeg lang/erlang-runtime27 lang/elixir-devel gmake python bash opencv cmake
# export PATH=$PATH:/usr/local/lib/erlang27/bin
# export LANG=en_US.UTF-8
# export LC_ALL=$LANG
# git clone https://github.com/cocoa-xu/evision
# cd evision

build

  • note it insists on fetching opencv again itself
# env MAKE=gmake \
      EVISION_ENABLE_CONTRIB=false \
      EVISION_ENABLE_CUDA=false \
      OPENCV_VER=4.9.0 \
  mix do deps.get, compile

I'd suggest diving through mix.exs and seeing if you can skip download, and use prebuilt opencv from ports.

Here's what opencv4.pc has:

 /usr/local/libdata/pkgconfig/opencv4.pc
# Package Information for pkg-config

prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/opencv4

Name: OpenCV
Description: Open Source Computer Vision Library
Version: 4.9.0
Libs: -L${exec_prefix}/lib -lopencv_stitching -lopencv_alphamat -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core
Libs.private: -lm -lpthread
Cflags: -I${includedir}

BTW definitely the longest mix.exs I've ever seen ;-)

dch avatar Apr 09 '25 17:04 dch

Hi @marschro @dch, just let you know that I saw this issue this morning. I'm on vacation this week but please feel free to drop a PR that brings the pre-compile support for AMD64 FreeBSD. I'll review/help on this when I'm back. :)

Besides that, this library does not use existing OpenCV on the host because when there's no pre-built support, it needs some build-time metadata to generate corresponding binding files, which doesn't exist in these packages (from the pkg repo).

cocoa-xu avatar Apr 09 '25 18:04 cocoa-xu

@dch - I actually did not have any errors. It compiled successfully.

But when re-doing that, I recognized, that I had some errors in the first post. cmake was also needed.

I updated the pkg's, that where needed (of course elixir also, I had that in the jail already...) and also updated the command, that I successfully used to compile the little project, that contains evision

marschro avatar Apr 09 '25 20:04 marschro

Hey @marschro, v0.2.12 is shipped, which has precompiled binaries for x86_64 FreeBSD systems!

iex> Mix.install([{:evision, "~> 0.2.12"}])
...

10:13:36.261 [info] EVISION_PREFER_PRECOMPILED: true; try to download and use the precompiled library.

10:13:36.261 [info] Current target `x86_64-unknown-freebsd` has precompiled binaries.

10:13:36.261 [info] Current host NIF version is `2.17`, will use precompiled binaries with NIF version 2.16.
==> evision
Downloading precompiled tarball from: https://github.com/cocoa-xu/evision/releases/download/v0.2.12/evision-nif_2.16-x86_64-unknown-freebsd-contrib-0.2.12.tar.gz

10:13:39.092 [info] Precompiled binary tarball downloaded and saved to /root/.cache/evision-nif_2.16-x86_64-unknown-freebsd-contrib-0.2.12.tar.gz, sha256=d6f3afa242c3911a485a38720fd550e8970dadb71805c126512f2dc582369211

10:13:39.692 [info] Copying priv directory: /root/.cache/evision-nif_2.16-x86_64-unknown-freebsd-contrib-0.2.12/priv => /root/.cache/mix/installs/elixir-1.18.3-erts-15.1.1/01c0587d0b475ad2cc86d574549cedad/_build/dev/lib/evision/priv

10:13:39.768 [info] Copying generated Elixir binding files: /root/.cache/evision-nif_2.16-x86_64-unknown-freebsd-contrib-0.2.12/elixir_generated => /root/.cache/mix/installs/elixir-1.18.3-erts-15.1.1/01c0587d0b475ad2cc86d574549cedad/deps/evision/lib/generated
Compiling 676 files (.ex)
Generated evision app

cocoa-xu avatar Apr 15 '25 08:04 cocoa-xu

What ? crazy in no time? Would like to know more - but will test it first :)

marschro avatar Apr 15 '25 22:04 marschro

Hi @cocoa-xu

I just tested this in a FreeBSD jail with 14.2-RELEASE.

That's what I got - somehow it wants to compile it... Maybe I forgot something obvious. iex should be started with EVISION_PREFER_PRECOMPILED=true iex I guess?

UPDATE: Ah just saw default for EVISION_PREFER_PRECOMPILED is true So should not be the cause.

Setting it explicit like: Mix.install([{:evision, "0.2.12"}], system_env: [{"EVISION_PREFER_PRECOMPILED", "true"}]) ends up in same issue below.

Erlang/OTP 26 [erts-14.2.5.5] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns] [dtrace] [sharing-preserving]

Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.install([{:evision, "~> 0.2.12"}])
* creating /root/.mix/archives/hex-2.1.1
Resolving Hex dependencies...
Resolution completed in 0.058s
New:
  castore 1.0.12
  complex 0.6.0
  elixir_make 0.9.0
  evision 0.2.12
  nx 0.9.2
  telemetry 1.3.0
* Getting evision (Hex package)
* Getting castore (Hex package)
* Getting elixir_make (Hex package)
* Getting nx (Hex package)
* Getting complex (Hex package)
* Getting telemetry (Hex package)
* creating /root/.mix/elixir/1-17/rebar3
===> Analyzing applications...
===> Compiling telemetry
==> complex
Compiling 2 files (.ex)
Generated complex app
==> nx
Compiling 36 files (.ex)
Generated nx app
==> castore
Compiling 1 file (.ex)
Generated castore app
==> elixir_make
Compiling 8 files (.ex)
Generated elixir_make app
==> evision
could not compile dependency :evision, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile evision --force", update it with "mix deps.update evision" or clean it with "mix deps.clean evision"
** (Mix.Error) "gmake" not found in the path. If you have set the MAKE environment variable, please make sure it is correct.

    (mix 1.17.3) lib/mix.ex:588: Mix.raise/2
    (elixir_make 0.9.0) lib/elixir_make/compiler.ex:117: ElixirMake.Compiler.cmd/5
    (elixir_make 0.9.0) lib/elixir_make/compiler.ex:92: ElixirMake.Compiler.make/2
    (elixir_make 0.9.0) lib/elixir_make/compiler.ex:53: ElixirMake.Compiler.compile/1
    (mix 1.17.3) lib/mix/task.ex:495: anonymous fn/3 in Mix.Task.run_task/5
    (mix 1.17.3) lib/mix/tasks/compile.all.ex:108: Mix.Tasks.Compile.All.run_compiler/2
    (mix 1.17.3) lib/mix/tasks/compile.all.ex:88: Mix.Tasks.Compile.All.compile/4

marschro avatar Apr 15 '25 23:04 marschro

In the .mix file in 859 you have the run function:

@impl true
  def run(_args) do
    {target, [_arch, os, _abi]} = get_target()

    evision_so_file =
      if os == "windows" do
        "evision.dll"
      else
        "evision.so"
      end

    windows_fix_so_file =
      if os == "windows" do
        "windows_fix.dll"
      else
        "windows_fix.so"
      end

    evision_so_file = Path.join([app_priv(), evision_so_file])
    windows_fix_so_file = Path.join([app_priv(), windows_fix_so_file])

    if !File.exists?(evision_so_file) or !File.exists?(windows_fix_so_file) do
      with {:precompiled, _} <- deploy_type(true) do
        version = Metadata.version()
        nif_version = get_compile_nif_version()
        enable_contrib = System.get_env("EVISION_ENABLE_CONTRIB", "true") == "true"
        enable_cuda = System.get_env("EVISION_ENABLE_CUDA", "false") == "true"
        {default_cuda_version, default_cudnn_version} = Metadata.default_cuda_version()
        cuda_version = System.get_env("EVISION_CUDA_VERSION", default_cuda_version)
        cudnn_version = System.get_env("EVISION_CUDNN_VERSION", default_cudnn_version)

        prepare(
          target,
          os,
          version,
          nif_version,
          enable_contrib,
          enable_cuda,
          cuda_version,
          cudnn_version
        )
      else
        _ ->
          raise RuntimeError, "Cannot use precompiled binaries."
      end
    else
      :ok
    end
  end
end
  • there I see its checking if evision_so_file exists. if so it checks for deploy_type etc...
  • I wonder why I do not run into this. Because I also do not get any logging from use_precompiled?/1 in 224 which itself is called by reply_type/1.
  • And you are searching for the evision_so_file in Path.join([app_priv(), evision_so_file]) ... wich resolves to the local build path.
  • It's all fine if I mix install local on macOS for example. Then all is created and evision.so is created.

So from log above, it raises in lib/mix.ex:588

=> Might there be an issue with getting/creating the cache directory for FreeBSD?

marschro avatar Apr 17 '25 11:04 marschro

That sounds weird, might be because it's in the jail?

cocoa-xu avatar Apr 17 '25 12:04 cocoa-xu

@cocoa-xu I checked again and did on the FreeBSD host - not in a jail:

  • ran the Mix.install([{:evision, "~> 0.2.12"}]) in the host system.
  • I also created a little mix project with evision as dependency on the latest 14.2-RELEASE-p3 FreeBSD and tried to compile it.

Outcome:

  • Same error, it tries to compile and misses gmake but should download. It does not reach the point in the mix file to start the precompiled ...

marschro avatar Apr 22 '25 16:04 marschro