thirtythreeforty / neolink

An RTSP bridge to Reolink IP cameras
https://www.thirtythreeforty.net/posts/2020/05/hacking-reolink-cameras-for-fun-and-profit/
GNU Affero General Public License v3.0
882 stars 144 forks source link

Issue with prefix when Gstreamer (v1.20) linking on MacOSX #311

Open vfdev-5 opened 1 year ago

vfdev-5 commented 1 year ago

I'm trying to build neolink on MacOSX and cargo build fails with the following error:

   Compiling neolink v0.4.0 (.../neolink)
error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "-arch" "x86_64" ...

  = note: ld: warning: directory not found for option '-L/non_existent_on_purpose/please_use_framework_pkg-config/or_pass_--define-prefix_to_your_pkg-config/lib'
          ld: warning: directory not found for option '-L/non_existent_on_purpose/please_use_framework_pkg-config/or_pass_--define-prefix_to_your_pkg-config/lib
...

Seems like we have to override somehow prefix variable from gstreamer-1.0.pc which is

prefix=/non_existent_on_purpose/please_use_framework_pkg-config/or_pass_--define-prefix_to_your_pkg-config
libdir=${prefix}/lib
includedir=${prefix}/include

exec_prefix=${prefix}
toolsdir=${exec_prefix}/bin
pluginsdir=${libdir}/gstreamer-1.0
datarootdir=${prefix}/share
datadir=${datarootdir}
girdir=${datadir}/gir-1.0
typelibdir=${libdir}/girepository-1.0
libexecdir=${prefix}/libexec
pluginscannerdir=${libexecdir}/gstreamer-1.0

Name: gstreamer-1.0
Description: Streaming media framework
Version: 1.20.3
Requires: glib-2.0 >= 2.56.0, gobject-2.0
Requires.private: gmodule-2.0
Libs: -L${libdir} -lgstreamer-1.0 -Wl,-rpath,${libdir}
Libs.private: -lm -ldl
Cflags: -I${includedir}/gstreamer-1.0

I could solve the problem in build.rs :

#[cfg(not(windows))]
fn platform_cfg() {
    let gstreamer_dir = env::var_os("GSTREAMER_1_0_ROOT_MACOSX")
        .and_then(|x| x.into_string().ok())
        .unwrap_or_else(|| r#"/Library/Frameworks/GStreamer.framework/Versions/1.0"#.to_string());

    println!(r"cargo:rustc-link-search=native={}/lib", gstreamer_dir);
    println!(r"cargo:rustc-link-arg=-Wl,-rpath,{}/lib", gstreamer_dir);
}

but I'm not sure which is a right way to fix the wrong lib path.

Thanks !

QuantumEntangledAndy commented 1 year ago

So I do all my dev work on macOS so should work unless something has changed upstream.

We have a build on macOS using GitHub runners and that built just a few days ago. Here's the code we use for getting it to build on that:

curl -L 'https://gstreamer.freedesktop.org/data/pkg/osx/1.16.2/gstreamer-1.0-devel-1.16.2-x86_64.pkg' -o "$(pwd)/gstreamer-devel.pkg"

sudo installer -verbose -pkg "$(pwd)/gstreamer-devel.pkg" -target /

PKG_CONFIG_PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"

export "PKG_CONFIG_PATH=${PKG_CONFIG_PATH}"

cargo build --release --all-features
QuantumEntangledAndy commented 1 year ago

I believe what you are missing is the PKG_CONFIG_PATH env var that points to the frameworks pc file. As indicated by your error message non_existent_on_purpose/please_use_framework_pkg-config/or_pass_--define-prefix_to_your_pkg-config/lib

vfdev-5 commented 1 year ago

Thanks for the answer @QuantumEntangledAndy ! Yes, I saw this CI job and the issue is actually with gstreamer v1.20 and its gstreamer-1.0.pc. For v1.20 the content is

prefix=/non_existent_on_purpose/please_use_framework_pkg-config/or_pass_--define-prefix_to_your_pkg-config
libdir=${prefix}/lib
includedir=${prefix}/include

exec_prefix=${prefix}
toolsdir=${exec_prefix}/bin
pluginsdir=${libdir}/gstreamer-1.0
datarootdir=${prefix}/share
datadir=${datarootdir}
girdir=${datadir}/gir-1.0
typelibdir=${libdir}/girepository-1.0
libexecdir=${prefix}/libexec
pluginscannerdir=${libexecdir}/gstreamer-1.0

Name: gstreamer-1.0
Description: Streaming media framework
Version: 1.20.3
Requires: glib-2.0 >= 2.56.0, gobject-2.0
Requires.private: gmodule-2.0
Libs: -L${libdir} -lgstreamer-1.0 -Wl,-rpath,${libdir}
Libs.private: -lm -ldl
Cflags: -I${includedir}/gstreamer-1.0

I checked manually the content of this file for v1.16 :

prefix=/Library/Frameworks/GStreamer.framework/Versions/1.0
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include/gstreamer-1.0
toolsdir=${exec_prefix}/bin
pluginsdir=${prefix}/lib/gstreamer-1.0
datarootdir=${prefix}/share
datadir=${datarootdir}
girdir=${datadir}/gir-1.0
typelibdir=${libdir}/girepository-1.0

Name: GStreamer
Description: Streaming media framework
Version: 1.16.2
Requires: glib-2.0, gobject-2.0
Requires.private: gmodule-no-export-2.0  
Libs: -L${libdir} -lgstreamer-1.0
Cflags: -I${includedir}

As you can see for v1.16 they explicitly defined prefix as /Library/Frameworks/GStreamer.framework/Versions/1.0 but for 1.20 it is undefined and requires to be overwritten.

I believe what you are missing is the PKG_CONFIG_PATH env var that points to the frameworks pc file.

No, I set this env var, otherwise compilation fails (not linking).

Another question I had is how rpath is set up for 1.16 such that on execution it could find dynamic lib libgstreamer-1.0.dylib ? In my case for v1.20 I had to pass println!(r"cargo:rustc-link-arg=-Wl,-rpath,{}/lib", gstreamer_dir); in build.rs.

vfdev-5 commented 1 year ago

Here is the log of CI job with v1.20 : https://github.com/vfdev-5/neolink/actions/runs/3096119485/jobs/5011289090 We can see that it is failing with the above error

QuantumEntangledAndy commented 1 year ago

With leave the rpath as the defaults. Which tends to be absolute path at build time I believe. It's one of the reasons why we build with the official pkg installer rather than brew because most people install via pkg and the paths are different.

p.s. not sure if you know but you can read the paths with otool -L <excecutable>

If this is a 1.20 change is there anything in the change log about the official way to deal with this.

vfdev-5 commented 1 year ago

If this is a 1.20 change is there anything in the change log about the official way to deal with this.

It only says:

macOS: In order to support a relocatable GStreamer.framework on macOS, an application may now need to add an rpath entry to the location of the GStreamer.framework (which could be bundled with the application itself). Some build systems will do this for you by default.

(https://gstreamer.freedesktop.org/releases/1.20/#1.20.3)

As for linked libs when neolink is built with gstreamer 1.20:

otool -L neolink 
> 
target/debug/neolink:
        @rpath/libgstrtspserver-1.0.0.dylib (compatibility version 2004.0.0, current version 2004.0.0)
        @rpath/libgstreamer-1.0.0.dylib (compatibility version 2004.0.0, current version 2004.0.0)
        ...

While neolink binary that this project distributes has:

otool -L neolink 
> 
neolink:
        /Library/Frameworks/GStreamer.framework/Versions/1.0/lib/libgstrtspserver-1.0.0.dylib (compatibility version 1603.0.0, current version 1603.0.0)
        /Library/Frameworks/GStreamer.framework/Versions/1.0/lib/libgstreamer-1.0.0.dylib (compatibility version 1603.0.0, current version 1603.0.0)
       ...
Vizzyy commented 1 year ago

after building with the above commands I had to

cp /Library/Frameworks/GStreamer.framework/Versions/1.0/lib/libgstrtspserver-1.0.dylib /Library/Frameworks/GStreamer.framework/Versions/1.0/lib/libgstrtspserver-1.0.0.dylib

as neolink expects 1.0.0.dylib instead of the 1.0.dylib that was installed for me.