Install and use MakeMKV (without GUI) on FreeBSD

zirias@

Developer
0. Errata/Updates:

  • 2019/05/05 -- turned out it worked for me out of pure luck when building with SSL headers of my system, but linking to OpenSSL from linux-c7 packages. This is super easy to break and I updated the HOWTO to include downloading the same OpenSSL version that's used in linux-c7 and use the headers from this package when building MakeMKV. I also created a port automating the whole build, please see the followup post :)
1. Disclaimers:
  • This Howto is for amd64 only. MakeMKV exists for i386 as well, you might be able to adapt the instructions.
  • Builds done here are very dirty, they often use headers installed on your FreeBSD system together with Linux libraries installed in /compat/linux. It might not work for you, it might break any time when anything is upgraded.
  • All commands shown here assume you're using a bourne-compatible shell (like bash, zsh, etc). If you use a C shell, translate yourself please.
  • The result of this Howto will be a closed source (and therefore potentially untrustworthy) Linux program accessing devices directly on your FreeBSD system using Linux emulation layers. If anything bad happens, don't blame me.
  • This Howto uses some fixed paths for everything. If you know exactly what you do, you can use different paths of course.
  • I'm pretty sure I have missed some dependencies. If you're running into a problem and have to install some package to solve it, please leave a note here :)
2. Prerequisites:
  • First of all, you will need a kernel providing Linux-compatible /dev/sg* devices. For instructions how to build and install a custom kernel, see the Handbook, Building and Installing a Custom Kernel. The minimal configuration file (e.g. /usr/src/sys/amd64/conf/MYKERNEL) you'll need looks something like
    Code:
    include GENERIC
    ident MYKERNEL
    
    device          sg
  • Then, you'll need to install some ports or packages:
    devel/nasm
    devel/gmake
    emulators/linux_base-c7
    textproc/linux-c7-expat
    security/linux-c7-openssl
    devel/linux-c7-devtools
    lang/perl5.28
    sysutils/patchelf
    (did I miss something here?)
  • create directories for the source and for libraries built statically, we will use /usr/local/src/makemkv and /usr/local/src/staticbuild. Change ownership of these directories to your ordinary user and group (we don't want to build as root).
  • We will use the "Linux devtools" like they were a cross-compiling toolchain. Create the symlinks needed for this in /usr/local/bin:
    Code:
    cd /usr/local/bin
    for t in gcc link ld objdump ar nm strip ranlib g++; do
        ln -s /compat/linux/bin/$t x86_64-redhat-linux-$t
    done
  • At least on my system, some symbolic links were missing for Linux libraries, so the Linux linker finds them at build time. Create them:
    Code:
    cd /compat/linux/usr/lib64
    ln -s libz.so.1 libz.so
    ln -s libcrypto.so.10 libcrypto.so
    ln -s libexpat.so.1 libexpat.so
3. Building and installing the software:

From here, do everything as a normal (non-root) user unless explicitly stated otherwise!

In /usr/local/src/makemkv, download the latest distribution files for:
The following instructions will use filenames with the versions I used myself, so you might have to adapt them to newer versions if needed:

3.1 fdk-aac:
Code:
tar xf fdk-aac-2.0.0.tar.gz
cd fdk-aac-2.0.0
./configure --prefix=/usr/local/src/staticbuild --disable-shared --enable-static --with-pic --host=x86_64-redhat-linux
make install
make install built everything twice here before installing, so don't worry if this happens to you.

3.2 ffmpeg:
Code:
tar xf ffmpeg-4.1.3.tar.bz2
cd ffmpeg-4.1.3
PKG_CONFIG_PATH=/usr/local/src/staticbuild/lib/pkgconfig CPPFLAGS="-Dcaddr_t=void\* -D__daddr_t_defined" ./configure --prefix=/usr/local/src/staticbuild --disable-shared --enable-static --enable-pic --enable-libfdk-aac --pkg-config=pkg-config --cross-prefix=x86_64-redhat-linux- --arch=x86_64 --target-os=linux --host-cc=cc
gmake
gmake install

The CPPFLAGS are very hacky here, they work around code using some obscure type caddr_t that's in fact just a generic pointer.

At this stage, we have static libraries needed to build libmakemkv.so in /usr/local/src/staticbuild. You can completely delete this directory once you have MakeMKV running.

3.3 openssl (only headers needed):
Code:
tar xf openssl-1.0.2k.tar.gz2
cd openssl-1.0.2k
./Configure --openssldir= --prefix=/usr linux-x86_64

3.4 makemkv-oss:
Code:
tar xf makemkv-oss-1.14.3.tar.gz
cd makemkv-oss-1.14.3
PKG_CONFIG_PATH=/usr/local/src/staticbuild/lib/pkgconfig CFLAGS="-DFORCE_OPENSSL_NO_EC -I/usr/local/src/makemkv/openssl-1.0.2k/include" ./configure --prefix=/opt/makemkv --disable-gui --host=x86_64-redhat-linux
gmake
sed -ie 's:INSTALL) -D:INSTALL):' Makefile
Then, as root:
Code:
install -d -m755 /opt/makemkv/lib
gmake install

3.5 makemkv-bin:
Code:
tar xf makemkv-bin-1.14.3.tar.gz
cd makemkv-bin-1.14.3
sed -ie 's:/bin/bash:/bin/sh:' Makefile
sed -ie 's:x86_64:amd64:' Makefile
sed -ie 's:-t \([^ ]*\) \([^ ]*\):\2 \1:' Makefile
Then, as root:
Code:
gmake PREFIX=/opt/makemkv install
patchelf --set-rpath /opt/makemkv/lib /opt/makemkv/bin/makemkvcon
sed -ie 's:/sys/bus/scsi:/opt/makemkv/:' /opt/makemkv/bin/makemkvcon

Be careful here when changing any paths! makemkvcon searches /sys/bus/scsi for usable optical drives, and unfortunately, linsysfs(5) doesn't provide this. So here we patch the binary to look for this sysfs-path in a different location. Because we are patching a binary, the replacement string must be exactly the same length, otherwise the program is broken.

Now, we have to present makemkvcon some faked sysfs entries to find our drive on FreeBSD. Use camcontrol devlist to get some info about your optical drive. An example output could look like that:
Code:
<HL-DT-ST BD-RE  GGW-H20L YL04>    at scbus1 target 0 lun 0 (sg0,cd0,pass1)
The line you're looking for will contain a cd* device. It must also contain a sg* device, that's the reason we compiled a custom kernel at the beginning.

The info we need from this line is the SCSI bus number (here 1), the target and lun (here 0 and 0) and the sg device (here sg0)

With this info issue the following commands as root, replacing <bus>, <target>, <lun> and <sgdev> appropriately:
Code:
mkdir -p /opt/makemkv/devices/<bus>:0:<target>:<lun>/scsi_generic/<sgdev>
mkdir -p /opt/makemkv/drivers/sr
ln -s ../../devices/<bus>:0:<target>:<lun> /opt/makemkv/drivers/sr/<bus>:0:<target>:<lun>
echo 5 >/opt/makemkv/devices/<bus>:0:<target>:<lun>/type

E.g. on my system, I typed these commands:
Code:
mkdir -p /opt/makemkv/devices/1:0:0:0/scsi_generic/sg0
mkdir -p /opt/makemkv/drivers/sr
ln -s ../../devices/1:0:0:0 /opt/makemkv/drivers/sr/1:0:0:0
echo 5 >/opt/makemkv/devices/1:0:0:0/type

4. Testing:

Put a video disc (e.g. DVD-Video or Bluray) in your optical drive and try
Code:
/opt/makemkv/bin/makemkvcon info disc:0
This should now print out information about the titles found on the disc. You can rip one of them to an mkv file with
Code:
/opt/makemkv/bin/makemkvcon mkv disc:0 0 .
The single 0 here is the title number to rip, the . is the output directory.
Refer to https://www.makemkv.com/developers/usage.txt for more info on the commandline.

Be careful: On my system, makemkvcon always crashes after finishing its work, so watch out for dumped cores :)

Optional: you might want to create a symlink /usr/local/bin/makemkvcon -> /opt/makemkv/bin/makemkvcon so you don't have to type the whole path all the time.

5. What's next:
  • It should be possible to use the MakeMKV GUI as well, but I didn't get that to work so far. Maybe we could even build the GUI as a native FreeBSD executable? :)
  • One could go wild and try to create a port automating all this crap ... or maybe not ;)
 
Last edited:
Meanwhile, I created a port that automates all this trickery:
https://github.com/Zirias/zfbsd-ports/tree/master/new/multimedia/makemkv

So, if you trust me, just try this -- it's probably a bit fragile as well, but works for me with linux-c7 on amd64. Can be built in poudriere as well. The MakeMKV EULA can't be accepted automatically, so if you want batch building (e.g. in poudriere), add the following to your make.conf:
Code:
LICENSES_ACCEPTED+=     MAKEMKV

I actually recommend you try the port before attempting to build it all manually :)
 
I got this when trying to clone,
Code:
anders@aasennas:~ % git clone https://github.com/Zirias/zfbsd-ports/tree/master/new/multimedia/makemkv
Cloning into 'makemkv'...
fatal: repository 'https://github.com/Zirias/zfbsd-ports/tree/master/new/multimedia/makemkv/' not found

i dont use git much but thot that was the way to clone the repo?
 
Thanks to anyone giving a "thumbs up" here. But I really think the build process got too complicated to follow it manually. The HOWTO here might still be valuable as a reference/documentation, but on the other hand, I meanwhile changed my port (automating all this mess) not to use /opt at all, so it is more in line with FreeBSD. Therefore, please have a look at this thread about creating the new port. And, of course, I will keep the port in my own git repo up to date...
 
I just cloned your repo and I had to add a few f to the ln -s so it wouldn't fail if I had errors the first time around, and I'm still getting the following error:

Code:
 lebel@sulaco   ³ VEnv  ~/S/zfbsd-ports   master    new/multimedia/makemkv 
↳ doas make                                                                                                   jeu. 2019-10-03 14h31
===>   makemkv-1.14.5 depends on package: nasm>0 - found
===>   makemkv-1.14.5 depends on file: /usr/local/include/expat.h - found
===>   makemkv-1.14.5 depends on package: patchelf>0 - found
===>   makemkv-1.14.5 depends on executable: gmake - found
===>   makemkv-1.14.5 depends on package: linux-c7-expat>0 - found
===>   makemkv-1.14.5 depends on package: linux_base-c7>=7.6.1810_7 - found
===>   makemkv-1.14.5 depends on package: linux-c7-devtools>0 - found
===>   makemkv-1.14.5 depends on package: pkgconf>=1.3.0_1 - found
===>   makemkv-1.14.5 depends on package: perl5>=5.30.r1<5.31 - found
===>  Configuring for makemkv-1.14.5
/bin/mkdir -p /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/bin
cd /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/bin;  for t in gcc link ld objdump ar nm strip ranlib g++; do  /bin/ln -sf /compat/linux/bin/$t x86_64-redhat-linux-$t;  done
/bin/mkdir -p /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/lib
cd /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/lib;  /bin/ln -sf /compat/linux/lib64/libz.so.1 libz.so;  /bin/ln -sf /compat/linux/lib64/libcrypto.so.10 libcrypto.so;  /bin/ln -sf /compat/linux/lib64/libexpat.so.1 libexpat.so
cd /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/fdk-aac-2.0.0;  export PATH=/usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/bin:$PATH  LDFLAGS=-L/usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs/lib  CXXFLAGS="-O2 -pipe -DFORCE_OPENSSL_NO_EC -I/usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/openssl-1.0.2k/include -fstack-protector-strong -fno-strict-aliasing "  LD=x86_64-redhat-linux-ld; ./configure --prefix=/usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/staticlibs  --disable-shared --enable-static --with-pic  --host=x86_64-redhat-linux --disable-silent-rules;
checking for a BSD-compatible install... /usr/local/bin/ginstall -c
checking whether build environment is sane... yes
checking for x86_64-redhat-linux-strip... x86_64-redhat-linux-strip
checking for a thread-safe mkdir -p... /usr/local/bin/gmkdir -p
checking for gawk... no
checking for mawk... no
checking for nawk... nawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether UID '0' is supported by ustar format... yes
checking whether GID '0' is supported by ustar format... yes
checking how to create a ustar tar archive... gnutar
checking whether make supports nested variables... (cached) yes
checking for x86_64-redhat-linux-gcc... x86_64-redhat-linux-gcc
checking whether the C compiler works... no
configure: error: in `/usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv/work/fdk-aac-2.0.0':
configure: error: C compiler cannot create executables
See `config.log' for more details
*** Error code 77

Stop.
make: stopped in /usr/home/lebel/Sources/zfbsd-ports/new/multimedia/makemkv
1  lebel@sulaco   ³ VEnv  ~/S/zfbsd-ports   master    new/multimedia/makemkv 
↳

My guess is that configure picks up the $LINUXTRIPLETS-gcc as compiler, but will link using BSD's ld.

You might see that I modified a bit your Makefile, so just so we're on the same line, here's the diff of the Makefile:

Code:
diff --git a/new/multimedia/makemkv/Makefile b/new/multimedia/makemkv/Makefile
index 10d4d9d..f5700fa 100644
--- a/new/multimedia/makemkv/Makefile
+++ b/new/multimedia/makemkv/Makefile
@@ -72,7 +72,7 @@ LDFLAGS+=    -L${WRKDIR}/staticlibs/lib
HAS_CONFIGURE=    yes
CONFIGURE_ARGS=    --prefix=${PREFIX} --disable-gui --host=${LINUXTRIPLET} \
         --libdir=${PREFIX}/lib/makemkv
-CONFIGURE_ENV=    CC=${LINUXTRIPLET}-gcc CXX=${LINUXTRIPLET}-g++ \
+CONFIGURE_ENV=    CC=${LINUXTRIPLET}-gcc CXX=${LINUXTRIPLET}-g++ LD=${LINUXTRIPLET}-ld \
         PATH=${WRKDIR}/staticlibs/bin:${PATH} \
         PKG_CONFIG_PATH=${WRKDIR}/staticlibs/lib/pkgconfig
MAKE_ENV=    PATH=${WRKDIR}/staticlibs/bin:${PATH}
@@ -89,20 +89,20 @@ pre-configure:
         ${MKDIR} ${WRKDIR}/staticlibs/bin
         cd ${WRKDIR}/staticlibs/bin; \
         for t in gcc link ld objdump ar nm strip ranlib g++; do \
-            ${LN} -s ${LINUXBASE}/bin/$$t ${LINUXTRIPLET}-$$t; \
+            ${LN} -sf ${LINUXBASE}/bin/$$t ${LINUXTRIPLET}-$$t; \
         done
         ${MKDIR} ${WRKDIR}/staticlibs/lib
         cd ${WRKDIR}/staticlibs/lib; \
-            ${LN} -s ${LINUXLIBDIR}/libz.so.1 libz.so; \
-            ${LN} -s ${LINUXLIBDIR}/libcrypto.so.10 libcrypto.so; \
-            ${LN} -s ${LINUXLIBDIR}/libexpat.so.1 libexpat.so
+            ${LN} -sf ${LINUXLIBDIR}/libz.so.1 libz.so; \
+            ${LN} -sf ${LINUXLIBDIR}/libcrypto.so.10 libcrypto.so; \
+            ${LN} -sf ${LINUXLIBDIR}/libexpat.so.1 libexpat.so
         cd ${WRKDIR}/fdk-aac-${FDKAACVERSION}; \
-        PATH=${WRKDIR}/staticlibs/bin:$$PATH \
+        export PATH=${WRKDIR}/staticlibs/bin:$$PATH \
         LDFLAGS=-L${WRKDIR}/staticlibs/lib \
         CXXFLAGS="${CFLAGS}" \
-        ./configure --prefix=${WRKDIR}/staticlibs \
+        LD=${LINUXTRIPLET}-ld; ./configure --prefix=${WRKDIR}/staticlibs \
             --disable-shared --enable-static --with-pic \
-            --host=${LINUXTRIPLET} --disable-silent-rules; \
+            --host=${LINUXTRIPLET} --disable-silent-rules; 
         PATH=${WRKDIR}/staticlibs/bin:$$PATH \
         CXXFLAGS="${CFLAGS}" \
         ${MAKE_CMD} install

All that under FreeBSD 12.0-p10.
 
I see that the use of /opt is discouraged. Is there a particular directory where the files should be cloned to? Thanks
 
Back
Top