Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- add gst-plugins-base 1.19.1 #7142

Merged
merged 13 commits into from
Sep 27, 2021
Merged
4 changes: 4 additions & 0 deletions recipes/gst-plugins-base/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sources:
"1.19.1":
url: "https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/archive/1.19.1/gst-plugins-base-1.19.1.tar.bz2"
sha256 : "b39338e306502570b49043a9b9df5704043e02c8a2ccba3a5a4f1f6ea410d4b1"
217 changes: 217 additions & 0 deletions recipes/gst-plugins-base/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
from conans import ConanFile, tools, Meson, VisualStudioBuildEnvironment
from conans.errors import ConanInvalidConfiguration
import glob
import os
import shutil


class GStPluginsBaseConan(ConanFile):
name = "gst-plugins-base"
description = "GStreamer is a development framework for creating applications like media players, video editors, " \
"streaming media broadcasters and so on"
topics = ("gstreamer", "multimedia", "video", "audio", "broadcasting", "framework", "media")
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://gstreamer.freedesktop.org/"
license = "GPL-2.0-only"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_libalsa": [True, False],
"with_gl": [True, False],
"with_introspection": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"with_libalsa": True,
"with_gl": False,
"with_introspection": False,
}
_source_subfolder = "source_subfolder"
_build_subfolder = "build_subfolder"
exports_sources = ["patches/*.patch"]

generators = "pkg_config"

@property
def _is_msvc(self):
return self.settings.compiler == "Visual Studio"

def validate(self):
if self.options.shared != self.options["gstreamer"].shared or \
self.options.shared != self.options["glib"].shared:
# https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/133
raise ConanInvalidConfiguration("GLib, GStreamer and GstPlugins must be either all shared, or all static")
SSE4 marked this conversation as resolved.
Show resolved Hide resolved
if tools.Version(self.version) >= "1.18.2" and\
self.settings.compiler == "gcc" and\
tools.Version(self.settings.compiler.version) < "5":
raise ConanInvalidConfiguration(
"gst-plugins-base %s does not support gcc older than 5" % self.version
)

def configure(self):
if self.options.shared:
del self.options.fPIC
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd
self.options['gstreamer'].shared = self.options.shared
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed to a check in validate?

if self.options.shared and not self.options["gstreamer"].shared:
    raise ConanInvalidConfiguration("The options gstreamer:shared and {}:shared must be the same".format(self.name))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Thanks.
But this line overrides user arguments.
What happens if I build with the following arguments?

conan create . gst-plugins-base/1.19.1@ -o gstreamer:shared=True -o gst-plugins-base:shared=False
conan create . gst-plugins-base/1.19.1@ -o gstreamer:shared=False -o gst-plugins-base:shared=True

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the bad things happen for sure.
GLib is designed to be present only once within an entire address space.
mixing shared/static leads to undefined behavior (e.g. CI hands).
literally, we run into the issue https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/133
e.g. locally I get these errors:

objc[21642]: Class GNotificationCenterDelegate is implemented in both /Users/sse4/.conan/data/gstreamer/1.19.1/_/_/package/456f111003e278e1a2f9a487e4964b0dec0b5ce3/lib/libgstnet-1.0.0.dylib (0x100a663b8) and /Users/sse4/.conan/data/gst-plugins-base/1.19.1/_/_/package/15f899debcee0aa9e4e9a72e52b66594fa545dbe/lib/libgstrtsp-1.0.0.dylib (0x1004c2378). One of the two will be used. Which one is undefined.

and many errors of that type:

(process:3125): GLib-GObject-CRITICAL **: 15:57:26.899: g_param_spec_pool_lookup: assertion 'pool != NULL' failed

these errors indicate two instances of glib exist in the address place.

the bad things also happen with conan side here...
I gonna submit new bug, but I doubt it will be ever fixed (at least in 1.x).
if I request the following build:

conan create . gst-plugins-base/1.19.1@ \
 -o gst-plugins-base:shared=True \
 -o gstreamer:shared=True \
 -o glib:shared=True \

what do you think happens?
I am requesting all glib, gstreamer and gst-plugins-base to be shared libraries.
does conan guarantee that all of them will be shared?
nope, it surprisingly consumes gstreamer:shared=True linked to glib:shared=False.
and there seems to be no way to override it from command line?

why does it happen?
both packages gstreamer:shared=True with glib:shared=True and gstreamer:shared=True with glib:shared=False have the same package id!
for me, running on Mac:

conan info gstreamer/1.19.1 -o gstreamer:shared=True -o glib:shared=False
conan info gstreamer/1.19.1-o gstreamer:shared=True -o glib:shared=True

I get the exactly same result:

gstreamer/1.19.1
    ID: 5a1e3781444d60ee53a8d7e762ece8f559cf15ca

so the options glib:shared is erased from the package id of the gstreamer package.

are these two packages supposed to have the same package id? I don't think so.
the first one embeds glib objects into the gstreamer DLL.
the second one links gstreamer DLL into glib DLL.
I think that's entirely different package with a different behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the problem you're describing the need for full transitive package ids? default_package_id_mode and full_transitive_package_id?
But you're right, all shared libraries built by c3i have all static libraries built-in. This is really awkward.

My comment was about the recipe overriding user options, which is a no no imho.

Perhaps conan needs apost_validate method.
A method in which a recipe can check the complete dependency tree.
Then , the following can be added to the glib recipe:

def post_validate(self):
    if not self.options.shared:
        consumers = self.tree.get_consumers(self.name)
        shared_consumers = [consumer for consumer in consumers if getattr(consumer.options, "shared", False) == True]
        if len(shared_consumers) > 1:
            raise ConanInvalidConfiguration("glib is used by more then 1 library that is built as a shared library. This will lead to undefined behavior.")

Copy link
Contributor Author

@SSE4 SSE4 Sep 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need post_validate.
validate already runs for the final dependency tree, after all overrides computed.

Another important difference with the configure() method, is that validate() is evaluated after 
the graph has been computed and the information has been propagated downstream. 
So the values used in validate() are guaranteed to be final real values, while values at configure() time are not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I thought about it too late.


def config_options(self):
if self.settings.os == 'Windows':
del self.options.fPIC
if self.settings.os != "Linux":
del self.options.with_libalsa

def requirements(self):
self.requires("gstreamer/1.19.1")
if self.settings.os == "Linux":
if self.options.with_libalsa:
self.requires("libalsa/1.1.9")

def build_requirements(self):
self.build_requires("meson/0.54.2")
if not tools.which("pkg-config"):
self.build_requires("pkgconf/1.7.3")
SSE4 marked this conversation as resolved.
Show resolved Hide resolved
if self.settings.os == 'Windows':
self.build_requires("winflexbison/2.5.22")
SSE4 marked this conversation as resolved.
Show resolved Hide resolved
else:
self.build_requires("bison/3.5.3")
SSE4 marked this conversation as resolved.
Show resolved Hide resolved
self.build_requires("flex/2.6.4")
if self.options.with_introspection:
self.build_requires("gobject-introspection/1.68.0")

def source(self):
tools.get(**self.conan_data["sources"][self.version],
destination=self._source_subfolder, strip_root=True)

def _configure_meson(self):
defs = dict()

def add_flag(name, value):
if name in defs:
defs[name] += " " + value
else:
defs[name] = value

def add_compiler_flag(value):
add_flag("c_args", value)
add_flag("cpp_args", value)

def add_linker_flag(value):
add_flag("c_link_args", value)
add_flag("cpp_link_args", value)

meson = Meson(self)
if self.settings.compiler == "Visual Studio":
add_linker_flag("-lws2_32")
add_compiler_flag("-%s" % self.settings.compiler.runtime)
if int(str(self.settings.compiler.version)) < 14:
add_compiler_flag("-Dsnprintf=_snprintf")
if self.settings.get_safe("compiler.runtime"):
defs["b_vscrt"] = str(self.settings.compiler.runtime).lower()
defs["tools"] = "disabled"
defs["examples"] = "disabled"
defs["benchmarks"] = "disabled"
defs["tests"] = "disabled"
defs["wrap_mode"] = "nofallback"
defs["introspection"] = "enabled" if self.options.with_introspection else "disabled"
defs["gl"] = "enabled" if self.options.with_gl else "disabled"
meson.configure(build_folder=self._build_subfolder,
source_folder=self._source_subfolder,
defs=defs)
return meson

def _copy_pkg_config(self, name):
root = self.deps_cpp_info[name].rootpath
pc_dir = os.path.join(root, 'lib', 'pkgconfig')
pc_files = glob.glob('%s/*.pc' % pc_dir)
if not pc_files: # zlib store .pc in root
pc_files = glob.glob('%s/*.pc' % root)
for pc_name in pc_files:
new_pc = os.path.basename(pc_name)
self.output.warn('copy .pc file %s' % os.path.basename(pc_name))
shutil.copy(pc_name, new_pc)
prefix = tools.unix_path(root) if self.settings.os == 'Windows' else root
tools.replace_prefix_in_pc_file(new_pc, prefix)

def build(self):
for p in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**p)

self._copy_pkg_config("glib")
self._copy_pkg_config("gstreamer")
with tools.environment_append(VisualStudioBuildEnvironment(self).vars) if self._is_msvc else tools.no_op():
SSE4 marked this conversation as resolved.
Show resolved Hide resolved
meson = self._configure_meson()
meson.build()

def _fix_library_names(self, path):
# regression in 1.16
if self.settings.compiler == "Visual Studio":
with tools.chdir(path):
for filename_old in glob.glob("*.a"):
filename_new = filename_old[3:-2] + ".lib"
self.output.info("rename %s into %s" % (filename_old, filename_new))
shutil.move(filename_old, filename_new)

def package(self):
self.copy(pattern="COPYING", dst="licenses", src=self._source_subfolder)
with tools.environment_append(VisualStudioBuildEnvironment(self).vars) if self._is_msvc else tools.no_op():
meson = self._configure_meson()
meson.install()

self._fix_library_names(os.path.join(self.package_folder, "lib"))
self._fix_library_names(os.path.join(self.package_folder, "lib", "gstreamer-1.0"))
tools.rmdir(os.path.join(self.package_folder, "share"))
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.rmdir(os.path.join(self.package_folder, "lib", "gstreamer-1.0", "pkgconfig"))
tools.remove_files_by_mask(self.package_folder, "*.pdb")

def package_info(self):
gst_plugin_path = os.path.join(self.package_folder, "lib", "gstreamer-1.0")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is missing setting the names for the pkg_config generator.
It looks like a lot of libraries are built.
Does this need components?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be honest, no idea.
I've taken bincrafters recipe which didn't have this.
for me it worked, also CI passes, so not sure if anything else is required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't test pkg_config on CI.
It will be some obscure dependency that will flag an error.
Probably best to add a FIXME: missing pkg_config name(s) + components.

if self.options.shared:
self.output.info("Appending GST_PLUGIN_PATH env var : %s" % gst_plugin_path)
self.env_info.GST_PLUGIN_PATH.append(gst_plugin_path)
else:
self.cpp_info.defines.append("GST_PLUGINS_BASE_STATIC")
self.cpp_info.libdirs.append(gst_plugin_path)
self.cpp_info.libs.extend(["gstaudiotestsrc",
"gstaudioconvert",
"gstaudiomixer",
"gstaudiorate",
"gstaudioresample",
"gstvideotestsrc",
"gstvideoconvert",
"gstvideorate",
"gstvideoscale",
"gstadder",
"gstapp",
"gstcompositor",
"gstencoding",
"gstgio",
"gstopengl",
"gstoverlaycomposition",
"gstpbtypes",
"gstplayback",
"gstrawparse",
"gstsubparse",
"gsttcp",
"gsttypefindfunctions",
"gstvolume"])
if not self.options.with_gl:
self.cpp_info.libs.remove("gstopengl")
self.cpp_info.libs.extend(["gstallocators-1.0",
"gstapp-1.0",
"gstaudio-1.0",
"gstfft-1.0",
"gstpbutils-1.0",
"gstriff-1.0",
"gstrtp-1.0",
"gstrtsp-1.0",
"gstsdp-1.0",
"gsttag-1.0",
"gstvideo-1.0",
"gstgl-1.0"])
if not self.options.with_gl:
self.cpp_info.libs.remove("gstgl-1.0")
self.cpp_info.includedirs = ["include", os.path.join("include", "gstreamer-1.0")]
11 changes: 11 additions & 0 deletions recipes/gst-plugins-base/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.1)
project(test_package)


include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

find_package(gst-plugins-base CONFIG REQUIRED)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} gst-plugins-base::gst-plugins-base)
17 changes: 17 additions & 0 deletions recipes/gst-plugins-base/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from conans import ConanFile, CMake, tools
import os


class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package_multi"

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
44 changes: 44 additions & 0 deletions recipes/gst-plugins-base/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <gst/gst.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this source can be easily converted to c.
It would also test whether the cppstd library is linked correctly, if needed by a dependency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can be converted, but it needs some minor modifications (e.g. replace std::iostream with printf)

#include <gst/gstplugin.h>

#ifdef GST_PLUGINS_BASE_STATIC

extern "C"
{
GST_PLUGIN_STATIC_DECLARE(audiotestsrc);
GST_PLUGIN_STATIC_DECLARE(videotestsrc);
}

#endif

#include <iostream>

int main(int argc, char * argv[])
{
gst_init(&argc, &argv);

#ifdef GST_PLUGINS_BASE_STATIC

GST_PLUGIN_STATIC_REGISTER(audiotestsrc);
GST_PLUGIN_STATIC_REGISTER(videotestsrc);

#endif

GstElement * audiotestsrc = gst_element_factory_make("audiotestsrc", NULL);
if (!audiotestsrc) {
std::cerr << "failed to create audiotestsrc element" << std::endl;
return -1;
} else {
std::cout << "audiotestsrc has been created successfully" << std::endl;
}
gst_object_unref(GST_OBJECT(audiotestsrc));
GstElement * videotestsrc = gst_element_factory_make("videotestsrc", NULL);
if (!videotestsrc) {
std::cerr << "failed to create videotestsrc element" << std::endl;
return -1;
} else {
std::cout << "videotestsrc has been created successfully" << std::endl;
}
gst_object_unref(GST_OBJECT(videotestsrc));
return 0;
}
3 changes: 3 additions & 0 deletions recipes/gst-plugins-base/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
versions:
"1.19.1":
folder: all