Skip to content

Package dependencies are not transitive #5745

Description

@SirLynix

Is your feature request related to a problem? Please describe.

Hello,

As described here, the way package dependencies are handled can cause subtle bugs.

For example

add_requires("libsdl 2.28", "libsdl_ttf")

this will install two different versions of libsdl, because libsdl_ttf doesn't specify a version:

checking for Microsoft Visual Studio (x64) version ... 2022
note: install or modify (m) these packages (pass -y to skip confirm)?
in xmake-repo:
  -> libsdl 2.28.5 [runtimes:"MT"]
  -> libsdl#1 2.30.8 [runtimes:"MT", from:libsdl_ttf]
  -> libsdl_ttf 2.22.0 [runtimes:"MT"]
please input: y (y/n/m)

this may duplicate symbols, fail compilation or even worse, introduce subtle bugs that will just prevent the application to work without failing compilation.

An example would be something that happened countless times to my students:

package("student_engine", function ()
    add_deps("libsdl")
end)

add_requires("student_engine")
add_requires("libsdl", { configs = { shared = true }})

here we have two versions of libsdl, one static linked to student_engine and one shared linked to the main app, which was causing bugs because libsdl uses global variables internally, they were initializing it in the engine but SDL calls were failing in the app because it wasn't the same libsdl instance.

Another example would be openssl, a common package dependency, which restricts you to use multiple openssl versions across the project, if you use package locking or simply if you set the package version you can get multiple openssl versions.

Describe the solution you'd like

I think xmake should try to merge configs whenever possible, for example:

package("student_engine", function ()
    add_deps("libsdl")
end)

add_requires("student_engine")
add_requires("libsdl", { configs = { shared = true }})

here, student_engine.libsdl doesn't care about being shared or not, so we could merge both configs.

however:

package("student_engine", function ()
    add_deps("libsdl", { configs = { shared = false })
end)

add_requires("student_engine")
add_requires("libsdl", { configs = { shared = true }})

there should be two instances of libsdl here (or an error).

A quick way to do this would be to make add_requires("foo x.y", { configs = { ... }) implicitly add an add_requireconfs("**.foo", { version = "x.y", configs = { ... })` call.

Since it's a breaking change, this could be a policy, but it seems like a good default for xmake 3.0.

Describe alternatives you've considered

Using add_requireconfs by yourself is a way to fix it, however this can lead to more complex xmake.lua and you also need to understand how packages depend on each other, which is not simple.

Simpler xmake should be less error-prone in my opinion.

Additional context

Note that vcpkg does something like this at least for versions: https://learn.microsoft.com/en-us/vcpkg/users/versioning.concepts

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions