-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Vendoring dependencies presents maintenance issues #1991
Comments
Those are some very good points.
|
I was referring to FetchContent at configuration time. I want to avoid having 3rd party code in our repo since that presents its own maintenance problems.
If every dependency is hosted on GitHub (or GitLab or Bitbucket) then it's safe to assume that someone can build SFML. If a dependency is only available on a server running in someone's basement then I understand the concern but I don't believe that's the case for any of our dependencies. Certainly I want to verify that all dependencies are hosted publicly on reputable websites without downtime issues. If someone really cares deeply about avoiding this network dependency we can still let them modify a CMake variable via the command line which will switch their build over to using
|
Downtime is not the only problem. GitHub repos change, are renamed, deleted, transferred, ... I don't like the thought of people's build to break because one of the dependency maintainer decides to changes something or makes a mistake. You probably heard of the leftpad disaster, or just a few weeks ago, colors and faker. The first case made every single dependent code break, the second still broke everything with "use latest version" policy. And those are published in npm, likely the most widespread package manager, which at least has some basic stability. Unlike a GitHub repo which can change entirely through And those are just some of the issues, security is another one. If any contributor with push access in any of these repos decides to go rogue (or is hacked), and even if this only remains undetected for a few hours, a SFML user can end up downloading malware. If we don't want to version external code in SFML's own repo, we can always create a separate
I agree here, but does the C++ ecosystem actually take semver seriously? I haven't had the impression that semver is something that's particularly well-known or taught to library writers. More a curiosity question -- as you say correctly, we can't do more than hope for the best. |
I'm not proposing we use FetchContent to track the latest version. I want to use FetchContent to track a specific tag in that repo or maybe even a commit hash to be more specific since tags can move even if it's not likely they do."
This is addressed by pulling a specific commit hash instead of dynamically fetching whatever the latest version of the trunk branch is.
I think it does. Any popular C++ project I've seen or worked with takes semver seriously (or doesn't use semver as is the case with Boost).
Every popular C++ project I've worked with has taken semver seriously (or not used semver). |
I'm going to close this issue for now because I need to figure out more about a viable implementation. I don't want this issue cluttering up the issue tracker if I myself don't really know what changes I want to make. |
I think it's legitimate to keep issues open, even if there is no clearly agreed design yet (otherwise it might already be a PR). |
Okay then I'll reopen this so we can keep this as our designated spot to discuss dependency management. I won't personally have much to share about this in the short term but hope to take another deep look at this problem in a few weeks. |
Why can't we just use vcpkg? From what I can tell, all dependencies that sfml has in extlibs are all in vcpkg, and that's practically a universal package manager for all OSes and all architectures that SFML supports (and could support in future). |
That's a totally reasonable solution. I don't think anyone on the team or other frequent contributors have much experience with it but I'm sure we'd all love to see what a solution using vcpkg would look like. |
There's no reason to lock-in on a specific package manager, when one can just use FetchContent in CMake, plus it enables also additional intermixing with other package managers. Additionally, I've seen quite some horrible hacks on how vcpkg achieves its recipe packaging and quite dislike their library "discovery", which can't actually handle system library dependencies... Overall, I don't want to force SFML users to install vcpkg, just to build SFML. |
I support a solution where the CMake code exclusively uses |
I think we don't have to concern ourselves too much with a supply chain attack and by picking a specific version, we ensure that things shouldn't randomly break. The topic of availability can't be fully dismissed, but at the same time we're not using very niche libraries, as such they won't be suddenly gone and unrecoverable. Moving things to our own repo doesn't really seem to provide a huge benefit, while actually costing us maintenance resources and limiting people from easily updating to some other version on their own. Instead of listing pros + cons there's this method of aligning all the requirements and the solutions and see which one actually fulfills them the best. Here's my attempt that that, might be biased, so feel free to point out, how it could be adjusted. Requirements:
Solutions:
As I'm not too worried about "Offline Usage" and "Not affected by Supply Chain Issues", I see a plain FetchContent to third-party repositories as a winner. Side-note: I didn't include "Using system dependencies" as requirement, since this can be achieved with either option, just that some may make it easier than others. |
Thanks a lot, really appreciate the effort to put this all together in a structured way! 👍 A question for my understanding:
Shouldn't the first row not have a |
Woops, yes. That moved down, then I fixed it in markdown, but then regenerated the table and forgot to update it in the "source". |
Does this imply that you're only considering solutions that provide users a choice between automatic dependency resolution or manual dependency resolution? I'm surprised you didn't include a pure |
I will add it for completeness (don't want to edit the table on my phone), but it wouldn't fall under easy to use and would immediately disqualify for me. It might be okay for a Linux distro, where your OS package manager provides all our libraries, but if you look at how much people just struggle getting SFML to link, imagine how many would just give up if you told them they needed to build all the dependencies on their own as well, or figure out how to use a package manager |
I was curious how much code we could remove if we dropped x86 support so I did it. We can remove a fair few binaries and a few dozen lines of CMake. Getting rid of |
There's no point in removing binaries without actually having the new dependencies handling in place. An incremental approach is fine, but that increment should be on one dependency at a time and not on one architecture at a time. We already know that some things can be "removed" if we drop 32-bits support, as @vittorioromeo has already created a PR for this in the past (#1931), but we rejected that for the same reasons we already discussed on Discord. |
FYI CMake 3.24 introduce AlternativeIf you want more fine control e.g. chose to small exampleCMakelist.txt: # Force build of all deps (convenient super option for "hermetic" build)
option(BUILD_DEPS "Build all dependencies" OFF)
# Foo deps
# default: OFF aka rely on find_package(foo) BUT forced to ON if BUILD_DEPS=ON
include(CMakeDependentOption)
cmake_dependent_option(BUILD_foo "Build the foo dependency Library" OFF "NOT BUILD_DEPS" ON)
...
# To build requested dependencies we'll do it in "subfolder"
# note: CMake create a context per directory so we can force few option for our dependencies
add_subdirectory(cmake/dependencies dependencies)
# Check if we find ou build our deps
# set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
# dev note: the second test is for super build who may have already add_subdirectory(foo) etc..
# and find_package(foo) can't detect it...
# see: https://gitlab.kitware.com/cmake/cmake/-/issues/17735
if(NOT BUILD_Foo AND NOT TARGET foo::foo)
find_package(Foo REQUIRED)
endif()
# Optional since find_package has REQUIRED...
if(NOT TARGET foo::foo)
message(FATAL_ERROR "Target foo::foo not available.")
endif() cmake/dependencies/CMakeLists.txt: # Here we can set options only relevant for dependency build
# e.g. Forcing BUILD_SHARED_LIBS=OFF, disable tests of the deps etc...
# feel free to adapt to your needs
include(FetchContent)
set(FETCHCONTENT_QUIET OFF)
set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_TESTING OFF) # disable dependencies tests
set(CMAKE_Fortran_COMPILER OFF)
if(BUILD_foo)
message(CHECK_START "Fetching Foo")
list(APPEND CMAKE_MESSAGE_INDENT " ")
set(FOO_OPTION_1 ON) # require CMP0077
set(FOO_OPTION_2 ON)
FetchContent_Declare(
foo
GIT_REPOSITORY "https://github.com/orga/foo.git"
GIT_TAG "v1.0"
# PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/foo.patch")
FetchContent_MakeAvailable(foo)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")
endif()
... |
Sadly that's out of the question since Ubuntu 22 only ships with CMake 3.22 and we value ensuring that users on that platform don't need to install a newer version of CMake.
This option already exists in the form of the |
SFML currently vendors a number of binaries and headers for external dependencies. See the
extlibs
directory. Vendoring provides a more convenient developer experience by removing the need to install dependencies at the cost of a few problems.clang-format
are never applied to vendored code.SFML uses vendored dependencies for only a select few operating systems. For example, Linux users end up using
find_package
, CMake's canonical dependency retrieval mechanism. Users on Windows instead get the vendored dependencies. The key discriminator between whether a given OS usesfind_package
or vendored dependencies is the presence or absence of an official package manager. We want to keep this behavior.What I propose as a first step is that we remove all binaries from
extlibs
and replace them with the source code for a given dependency as retrieved by CMake'sFetchContent
module but only on OSes that aren't already usingfind_package
.FetchContent
will automatically download and build the project and provide the SFML build tree with access to all of the CMake targets from a given dependency.This also entails a fully target-based approach for expressing dependencies. No more modifying
CMAKE_INCLUDE_PATH
orCMAKE_LIBRARY_PATH
. No matter how a dependency is retrieved, we must depend on a target from that project. This means that users of a given dependency don't have to know anything about how that dependency is retrieved. Separating the retrieval of dependencies from its usage opens the door for easier future changes to how dependencies are handled and brings with it the other benefits of modern target-based CMake code.I still have more research to do into the existing dependency management scheme and the specifics of SFML's particular dependencies but I hope this issue helps start the conversation so we can start making steps towards improving this situation.
The text was updated successfully, but these errors were encountered: