-
-
Notifications
You must be signed in to change notification settings - Fork 816
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
Package components #2636
Comments
I remember discussing this issue many times before. I will not consider it for the time being. |
I know we discussed the issue multiple times before on Discord, but the issue remains, which is why I'm exposing solutions here as for now there's no real solution to this problem. At least if we had a way to tell a package config doesn't change its key, it would be a bit better (and would allow to handle packages like SFML) |
cmake's find_package has something like a component, although this can be wrapped into a package component-like pattern. But it's a bit complicated to implement, and I don't have a good solution yet, nor do I have much time to think about it. Maybe in the future, in my spare time, I'll think further about how to improve it, but it should be a while yet. Of course, I would welcome some better solutions and design ideas to be presented here. |
The current parsing scope (target,package,rule ..) only supports a single level and cannot support nested levels, it involves the core of the parser and the complexity and risk of change is too high. Furthermore, it is not just the implementation that is complex, we also need to ensure that the complexity of maintaining the package does not increase. Even if we support a sub-package or component model in the future, we need to design configurations that are simpler and easier to maintain. |
I understand the scope issue, maybe something like this: package("sfml")
...
add_components("system", { links = "sfml-system" })
add_components("network", { deps = { "system" }, links = "sfml-network" }) Which could handle callbacks as well: add_components("network", {
component_deps = { "system" },
links = "sfml-network",
on_load = function (package)
if package:is_plat("windows", "mingw") then
package:add("syslinks", "ws32")
end
end
}) It's less readable but it maintains a single-scope API. If you don't have time for this, I could try to work on this by myself, as a proof of concept. |
It is still a bit complex, and there is no interface design that I am fully satisfied with yet that is simple and readable, yet flexible enough. There are differences in the way it is implemented for different interfaces. But I still haven't figured out how to design them yet. |
I think it would be better to configure the components in a single on_load. If it's a simple component, you can avoid having to configure it in on_load at all. package("sfml")
add_components("graphics", {description = "Use the graphics module", deps = "system", links = "sfml-graphics"})
add_components("system", {description = "Use the system module", default = true, links = "sfml-system"})
add_components("network", {description = "Use the network module", default = true})
on_load(function (package)
-- more flexible configuration components
local network = package:component("network")
network:add("links", "sfml-network")
network:add("deps", "system")
if package:is_plat("windows") then
network:add("syslink", "ws2_32")
end
end)
on_install(function (package)
-- compiles everything
end) add_requires("sfml")
target("test")
add_packages("sfml", {components = "graphics"}) |
Looks good, but how would that handle this case: add_requires("sfml")
target("library")
set_kind("shared")
add_packages("sfml", { components = "network", public = true })
target("server")
add_deps("library")
target("client")
add_deps("library")
add_packages("sfml", { components = { "graphics", "audio" }) Does client have network component as well? |
|
Yes sorry, I forgot about it. With |
I can't be sure now. |
There are also some other issues, if you switch to components, then the determination of whether a component is enabled is made in the actual link stage, not in on_load. However, some package dependencies that depend on components must be added at the on_load stage. if package:config("window") or package:config("graphics") then
if package:is_plat("linux") then
package:add("deps", "libx11", "libxrandr", "freetype", "eudev")
package:add("deps", "opengl", "glx", {optional = true})
end
end |
I think the safest option now would be to combine them, I don't see when you would to override them.
I feel like even now we have this issue, with both on_load and on_fetch requiring to do the same thing (see https://github.com/NazaraEngine/xmake-repo/blob/master/packages/n/nazaraengine/xmake.lua#L144 ) |
However, it is now possible to disable some deps in on_load, as the configs are configured in add_requires. But with the components, we don't have any chance to disable some deps |
If those deps are necessary to build the package, then they should always be there, since component feature requires a fully-built package to work from my understanding. However we could make them private and make them public only if a component is enabled. |
If some of the components are not used in the project, this can introduce a lot of unnecessary deps. This will make the compilation and installation slower and take up more disk space. Therefore, we also need to add add_configs("xxx") to allow the user to disable it. This will be. package("sfml")
add_components("graphics", {description = "Use the graphics module", deps = "system", links = "sfml-graphics"})
add_components("system", {description = "Use the system module", default = true, links = "sfml-system"})
add_components("network", {description = "Use the network module", default = true})
add_configs("graphics", {description = "Use the graphics module", deps = "system", links = "sfml-graphics"})
add_configs("system", {description = "Use the system module", default = true, links = "sfml-system"})
add_configs("network", {description = "Use the network module", default = true})
on_load(function (package)
if package:config("window") or package:config("graphics") then
if package:is_plat("linux") then
package:add("deps", "libx11", "libxrandr", "freetype", "eudev")
package:add("deps", "opengl", "glx", {optional = true})
end
end
-- more flexible configuration components
local network = package:component("network")
network:add("links", "sfml-network")
network:add("deps", "system")
if package:is_plat("windows") then
network:add("syslink", "ws2_32")
end
end) |
Having both would indeed fix the issue for a package like SFML (plus it wouldn't break compatibility). As for Qt (and perhaps Boost), only components would be required. This seems like a good solution, maybe the syntax can be improved (I'm not sure how yet) to keep package simple. What you suggest seems right. |
I'll consider trying to implement it when I have time later. But it will take some time, I'm working on some c++ modules. |
No problem, thank you for considering this! |
I will add my thoughts on this but related to external sources. I always prefer to rely on precompiled packages. If we take as an exemple ffmpeg, we have the followings:
So, when adding
For example:
This means:
|
I have supported it on #2932 Use components to control compilation and linksadd_requires("sfml")
target("graphics")
set_kind("static")
add_files("src/graphics.cpp")
add_packages("sfml", {components = "graphics", public = true})
target("network")
set_kind("static")
add_files("src/network.cpp")
add_packages("sfml", {components = "network", public = true})
target("test")
set_kind("binary")
add_files("src/main.cpp")
add_deps("graphics", "network") Package configurationDefine components listin description scope: package("sfml")
add_components("graphics", "windows", "audio", "system") or in script scope: package("sfml")
on_load(function (package)
package:add("components", "graphics", "windows", "audio", "system")
end) Configure the components we can use according to configs. package("sfml")
on_load(function (package)
for _, component in ipairs({"graphics", "window", "audio", "network"}) do
if package:config(component) then
package:add("components", component)
end
end
end) configure each componentsWe can configure links, defines, includedirs etc. for each component individually package("sfml")
on_component("graphics", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-graphics" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("links", "freetype")
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end)
on_component("window", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-window" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end) Components dependenciesWith component dependencies, we can further simplify the use of components for the user. for example, if we use graphics component, the add_packages("sfml", {components = "graphics") package("sfml")
on_load(function (package)
-- ...
package:add("components", "graphics", {deps = {"window", "system"}})
end) Therefore, the user does not need to relate to the internal dependencies of the components, but only needs to enable the components they need. Show package components informationShow info in current project $ xmake require --info sfml
The package info of project:
require(sfml):
-> description: Simple and Fast Multimedia Library
-> version: 2.5.1
...
-> components:
-> system:
-> graphics: system, window
-> window: system
-> audio: system
-> network: system Use xrepo to show info in global $ xrepo info sfml Full exampleadd_rules("mode.debug", "mode.release")
add_requires("sfml")
target("graphics")
set_kind("static")
add_files("src/graphics.cpp")
add_packages("sfml", {components = "graphics", public = true})
target("network")
set_kind("static")
add_files("src/network.cpp")
add_packages("sfml", {components = "network", public = true})
target("test")
set_kind("binary")
add_files("src/main.cpp")
add_deps("graphics", "network")
package("sfml")
set_homepage("https://www.sfml-dev.org")
set_description("Simple and Fast Multimedia Library")
if is_plat("windows", "linux") then
set_urls("https://www.sfml-dev.org/files/SFML-$(version)-sources.zip")
add_urls("https://github.com/SFML/SFML/releases/download/$(version)/SFML-$(version)-sources.zip")
add_versions("2.5.1", "bf1e0643acb92369b24572b703473af60bac82caf5af61e77c063b779471bb7f")
elseif is_plat("macosx") then
if is_arch("x64", "x86_64") then
set_urls("https://www.sfml-dev.org/files/SFML-$(version)-macOS-clang.tar.gz")
add_versions("2.5.1", "6af0f14fbd41dc038a00d7709f26fb66bb7ccdfe6187657ef0ef8cba578dcf14")
add_configs("debug", {builtin = true, description = "Enable debug symbols.", default = false, type = "boolean", readonly = true})
add_configs("shared", {description = "Build shared library.", default = true, type = "boolean", readonly = true})
end
elseif is_plat("mingw") then
if is_arch("x64", "x86_64") then
set_urls("https://www.sfml-dev.org/files/SFML-$(version)-windows-gcc-7.3.0-mingw-64-bit.zip")
add_versions("2.5.1", "671e786f1af934c488cb22c634251c8c8bd441c709b4ef7bc6bbe227b2a28560")
elseif is_arch("x86", "i386") then
set_urls("https://www.sfml-dev.org/files/SFML-$(version)-windows-gcc-7.3.0-mingw-32-bit.zip")
add_versions("2.5.1", "92d864c9c9094dc9d91e0006d66784f25ac900a8ee23c3f79db626de46a1d9d8")
end
end
if is_plat("linux") then
add_syslinks("pthread")
end
add_configs("graphics", {description = "Use the graphics module", default = true, type = "boolean"})
add_configs("window", {description = "Use the window module", default = true, type = "boolean"})
add_configs("audio", {description = "Use the audio module", default = true, type = "boolean"})
add_configs("network", {description = "Use the network module", default = true, type = "boolean"})
if is_plat("windows", "mingw") then
add_configs("main", {description = "Link to the sfml-main library", default = true, type = "boolean"})
end
if is_plat("macosx") then
add_extsources("brew::sfml/sfml-all")
end
on_component("graphics", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-graphics" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("links", "freetype")
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
component:add("deps", "window", "system")
component:add("extsources", "brew::sfml/sfml-graphics")
end)
on_component("window", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-window" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
component:add("deps", "system")
component:add("extsources", "brew::sfml/sfml-window")
end)
on_component("audio", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-audio" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("links", "openal32", "flac", "vorbisenc", "vorbisfile", "vorbis", "ogg")
end
component:add("deps", "system")
component:add("extsources", "brew::sfml/sfml-audio")
end)
on_component("network", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-network" .. e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("syslinks", "ws2_32")
end
component:add("deps", "system")
component:add("extsources", "brew::sfml/sfml-network")
component:add("extsources", "apt::sfml-network")
end)
on_component("system", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-system" .. e)
if package:is_plat("windows", "mingw") then
component:add("syslinks", "winmm")
end
if package:is_plat("windows", "mingw") and package:config("main") then
component:add("deps", "main")
end
component:add("extsources", "brew::sfml/sfml-system")
end)
on_component("main", function (package, component)
if package:is_plat("windows", "mingw") then
local main_module = "sfml-main"
if package:debug() then
main_module = main_module .. "-d"
end
component:add("links", main_module)
end
end)
on_load("windows", "linux", "macosx", "mingw", function (package)
if package:is_plat("windows", "linux") then
package:add("deps", "cmake")
end
if not package:config("shared") then
package:add("defines", "SFML_STATIC")
end
if package:is_plat("linux") then
if package:config("window") or package:config("graphics") then
package:add("deps", "libx11", "libxext", "libxrandr", "libxrender", "freetype", "eudev")
package:add("deps", "opengl", "glx", {optional = true})
end
if package:config("audio") then
package:add("deps", "libogg", "libflac", "libvorbis", "openal-soft")
end
end
package:add("components", "system")
for _, component in ipairs({"graphics", "window", "audio", "network"}) do
if package:config(component) then
package:add("components", component)
end
end
if package:is_plat("windows", "mingw") and package:config("main") then
package:add("components", "main")
end
end)
on_install("windows", "linux", function (package)
local configs = {"-DSFML_BUILD_DOC=OFF", "-DSFML_BUILD_EXAMPLES=OFF"}
table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))
if package:config("shared") then
table.insert(configs, "-DBUILD_SHARED_LIBS=ON")
else
table.insert(configs, "-DBUILD_SHARED_LIBS=OFF")
if package:is_plat("windows") and package:config("vs_runtime"):startswith("MT") then
table.insert(configs, "-DSFML_USE_STATIC_STD_LIBS=ON")
end
end
local packagedeps
if package:is_plat("linux") and package:config("shared") then
io.replace("src/SFML/Graphics/CMakeLists.txt", "target_link_libraries(sfml-graphics PRIVATE X11)",
"target_link_libraries(sfml-graphics PRIVATE X11 Xext Xrender)", {plain = true})
packagedeps = {"libxext", "libxrender"}
end
table.insert(configs, "-DSFML_BUILD_AUDIO=" .. (package:config("audio") and "ON" or "OFF"))
table.insert(configs, "-DSFML_BUILD_GRAPHICS=" .. (package:config("graphics") and "ON" or "OFF"))
table.insert(configs, "-DSFML_BUILD_WINDOW=" .. (package:config("window") and "ON" or "OFF"))
table.insert(configs, "-DSFML_BUILD_NETWORK=" .. (package:config("network") and "ON" or "OFF"))
import("package.tools.cmake").install(package, configs, {packagedeps = packagedeps})
end)
on_install("macosx", "mingw", function (package)
os.cp("lib", package:installdir())
os.cp("include", package:installdir())
if package:is_plat("mingw") then
os.cp("bin/*", package:installdir("lib"), {rootdir = "bin"})
end
end)
on_test(function (package)
assert(package:check_cxxsnippets({test = [[
void test(int args, char** argv) {
sf::Clock c;
c.restart();
}
]]}, {includes = "SFML/System.hpp"}))
if package:config("graphics") then
assert(package:check_cxxsnippets({test = [[
void test(int args, char** argv) {
sf::Text text;
text.setString("Hello world");
}
]]}, {includes = "SFML/Graphics.hpp"}))
end
if package:config("window") or package:config("graphics") then
assert(package:check_cxxsnippets({test = [[
void test(int args, char** argv) {
sf::Window window(sf::VideoMode(1280, 720), "Title");
sf::Event event;
window.pollEvent(event);
}
]]}, {includes = "SFML/Window.hpp"}))
end
if package:config("audio") then
assert(package:check_cxxsnippets({test = [[
void test(int args, char** argv) {
sf::Music music;
music.openFromFile("music.ogg");
music.play();
}
]]}, {includes = "SFML/Audio.hpp"}))
end
if package:config("network") then
assert(package:check_cxxsnippets({test = [[
void test(int args, char** argv) {
sf::UdpSocket socket;
socket.bind(54000);
char data[100];
std::size_t received;
sf::IpAddress sender;
unsigned short port;
socket.receive(data, 100, received, sender, port);
}
]]}, {includes = "SFML/Network.hpp"}))
end
end)
package_end() |
this looks absolutely amazing. maybe instead of private component, components deps could be considered? as for example with the SFML, "graphics" requires "window" which requires "system". add_components("graphics", { deps = { "window" })
add_components("audio", "network", "window", { deps = "system" })
add_components("system") component dependencies could be supported with a simple algorithm:
since component order doesn't matter this can be easily handled. anyway this is really great and I will test it as soon as I can (I don't have much time lately) |
I don't think this is necessary, we just need to control the dependencies between all the components by the order in which they are added to add_components. like add_links We should avoid introducing unnecessary complexity where possible, as introducing components is already quite complicated. |
I understand, but that means the user has to know how dependencies are related. in your example add_packages("sfml", { components = "graphics" }) will only link "graphics" and "system" components (because system is private), it won't link "window" component and cause a link error at usage which won't be very user-friendly. is there a way to detect this and trigger an error message in the package? to tell the user that "window" component is required by "graphics". |
thinking about it, if we make a Qt package using components (which is a pretty good candidate I think, as all Qt libs are installed), this means we will have to write add_packages("qt5", { components = { "core", "gui", "widgets", "network" } }) instead of add_packages("qt5", { components = { "widgets", "network" } }) -- link error I understand you don't want to make it too complicated from the beginning (and truly, package components seems like an awesome feature, thanks a lot!) but I think this may be a common error for packages using components, so it seems interesting to at least be capable of handling this as an explicit error instead of a link error. |
I have supported it, try it again. package:add("components", "system")
for _, component in ipairs({"graphics", "window", "audio", "network"}) do
if package:config(component) then
local deps = {}
table.insert(deps, "system")
if component == "graphics" then
table.insert(deps, "window")
end
if package:is_plat("windows", "mingw") and package:config("main") then
table.insert(deps, "main")
end
package:add("components", component, {deps = deps})
end
end
if package:is_plat("windows", "mingw") and package:config("main") then
package:add("components", "main")
end |
I have supported to find them from components/extsources, but it only support brew now. I will continue to support apt later. package("sfml")
if is_plat("macosx") then
add_extsources("brew::sfml/sfml-all")
end
on_component("graphics", function (package, component)
-- ...
component:add("extsources", "brew::sfml/sfml-graphics")
end)
on_component("window", function (package, component)
-- ...
component:add("extsources", "brew::sfml/sfml-window")
end) |
I just tested it, it works pretty well package("nazaraengine")
-- ...
add_components("widgets", { deps = "graphics" })
add_components("graphics", { deps = "renderer" })
add_components("renderer", { deps = {"platform", "utility"} })
add_components("platform", { deps = "utility" })
add_components("audio", "network", "physics2d", "physics3d", "utility", { deps = "core" })
add_components("core")
local function BuildLink(package, module)
local prefix = "Nazara"
local suffix = package:config("shared") and "" or "-s"
if package:debug() then
suffix = suffix .. "-d"
end
return prefix .. module .. suffix
end
local regularComponents = {"Audio", "Graphics", "Network", "Physics2D", "Physics3D", "Platform", "Utility", "Widgets"}
for _, componentName in ipairs(regularComponents) do
on_component(componentName:lower(), function (package, component)
component:add("links", BuildLink(package, componentName))
end)
end
on_component("core", function (package, component)
component:add("links", BuildLink(package, "Core"))
if is_plat("linux") then
component:add("syslinks", "pthread")
end
end)
on_component("renderer", function (package, component)
component:add("links", BuildLink(package, "Renderer"))
if package:is_plat("windows", "mingw") then
component:add("syslinks", "gdi32")
component:add("syslinks", "user32")
component:add("syslinks", "advapi32")
end
end) target("Bomberman")
set_kind("binary")
add_headerfiles("src/Client/**.hpp", "src/Client/**.inl", "src/Shared/**.hpp", "src/Shared/**.inl")
add_files("src/Client/**.cpp", "src/Shared/**.cpp")
add_packages("nazaraengine", { components = { "audio", "graphics", "network", "physics3d", "widgets" }})
target("BombermanServer")
set_kind("binary")
add_headerfiles("src/Server/**.hpp", "src/Server/**.inl", "src/Shared/**.hpp", "src/Shared/**.inl")
add_files("src/Server/**.cpp", "src/Shared/**.cpp")
add_packages("nazaraengine", { components = { "network", "physics3d", "utility" }}) Pretty awesome! What's the use of having |
In order to better isolate the configuration of each component, it is clearer and more readable to maintain, rather than all in the on_load configuration. However, it is equivalent to on_load_component, but with a more concise name.
maybe I will use This is probably better and keeps the style consistent with other add_deps interfaces. |
Alright, this will complicate a bit my implementation of the nazaraengine package (since I will have to provide a custom on_component for more modules) but it's not a big deal. or perhaps there is a better way (which would take less lines) to do that with the current interface? Maybe a table which would then be parsed in on_load. For example, if you move local components = {
{
name = "Widgets",
deps = { "graphics" }
},
{
name = "Graphics",
deps = { "graphics" }
},
{
name = "Renderer",
deps = { "platform", "utility" },
custom = function (package, component)
if package:is_plat("windows", "mingw") then
component:add("syslinks", "gdi32", "user32", "advapi32")
end
end
},
{
name = "Platform",
deps = { "utility" }
},
{
name = "Audio",
deps = { "core" }
},
{
name = "Network",
deps = { "core" }
},
{
name = "Physics2D",
deps = { "core" }
},
{
name = "Physics3D",
deps = { "core" }
},
{
name = "Utility",
deps = { "core" }
},
{
name = "Core",
custom = function (package, component)
if package:is_plat("linux") then
component:add("syslinks", "pthread", "dl")
end
end
}
}
for _, comp in ipairs(components) do
add_components(comp.name:lower())
on_component(comp.name:lower(), function (package, component)
local prefix = "Nazara"
local suffix = package:config("shared") and "" or "-s"
if package:debug() then
suffix = suffix .. "-d"
end
component:add("links", prefix .. comp.name .. suffix)
if comp.custom then
comp.custom(package, component)
end
end)
end which is probably more maintenable than: add_components("widgets", "graphics", "renderer", "platform", "physics2d", "physics3d", "network", "utility", "core")
local function BuildLink(package, moduleName)
local prefix = "Nazara"
local suffix = package:config("shared") and "" or "-s"
if package:debug() then
suffix = suffix .. "-d"
end
return prefix .. moduleName .. suffix
end
on_component("widgets", function (package, component)
component:add("deps", "graphics")
component:add("links", BuildLink(package, "Widgets"))
end)
on_component("graphics", function (package, component)
component:add("deps", "renderer")
component:add("links", BuildLink(package, "Graphics"))
end)
on_component("renderer", function (package, component)
component:add("deps", "platform", "utility")
component:add("links", BuildLink(package, "Renderer"))
if package:is_plat("windows", "mingw") then
component:add("syslinks", "gdi32", "user32", "advapi32")
end
end)
on_component("platform", function (package, component)
component:add("deps", "utility")
component:add("links", BuildLink(package, "Platform"))
end)
on_component("audio", function (package, component)
component:add("deps", "core")
component:add("links", BuildLink(package, "Audio"))
end)
on_component("network", function (package, component)
component:add("deps", "core")
component:add("links", BuildLink(package, "Network"))
end)
on_component("physics2d", function (package, component)
component:add("deps", "core")
component:add("links", BuildLink(package, "Physics2D"))
end)
on_component("physics3d", function (package, component)
component:add("deps", "core")
component:add("links", BuildLink(package, "Physics3D"))
end)
on_component("utility", function (package, component)
component:add("deps", "core")
component:add("links", BuildLink(package, "Utility"))
end)
on_component("core", function (package, component)
component:add("links", BuildLink(package, "Core"))
if package:is_plat("linux") then
component:add("syslinks", "pthread", "dl")
end
end) I'm not even sure of which one I like the most, maybe you have a better idea to handle this? It's not a big deal if I have to do this in a package, my package is a bit complicated anyway. |
If you are already using on_component, then continuing to use diff +8 -9 lines And if you don't want to use on_component, you can also configure them directly in on_load, where on_component is optional. package("sfml")
add_components("platform")
add_components("audio", "network", "physics2d", "physics3d", "utility")
add_components("core")
on_load(function (package)
for _, name in ipairs({"audio", "network", "physics2d", "physics3d", "utility"}) do
package:component(name):add("deps", "core")
end
end) Or you can also handle all components in single package("sfml")
add_components("platform")
add_components("audio", "network", "physics2d", "physics3d", "utility")
add_components("core")
on_component(function (package, component)
component:add("deps", "core")
if component:name() == "audio" then
-- ..
end
end) BTW, I have kept the |
I have merged this patch. |
I have updated sfml package to support components in xmake-repo |
Is your feature request related to a problem? Please describe.
One issue I regularly have with xmake package is the fact there's no good way to handle libraries spanning over multiple modules (multiple components).
For example, the SFML has five libraries: sfml-system, sfml-window, sfml-graphics, sfml-audio, sfml-network. Other libraries like Qt, Boost and my own engine have a similar issue.
Let's take the case where we want to have a SFML client and a SFML server, depending on a common library.
xmake currently offers three ways to handle this:
Using add_packages links
Advantages:
Disavantages:
Using package configs
Advantages:
Disavantages:
client
depends on sfml~server and sfml~clientUsing multiple packages
Imagine now there was a package for each sfml component ("sfml-system", "sfml-window", etc.).
Advantages:
Disavantages:
Describe the solution you'd like
I think we should be able to handle multiple components in the same package, installing the lib only once but allowing to select which components we want, without having to rebuild it multiple times.
First solution: handle subpackages
Usage:
Advantages:
add_packages("sfml")
to include all components, this doesn't break any code.Disavantages:
Second solution: allows some configs to not change package key
Usage:
Advantages:
Disavantages:
This feature would make xmake way more awesome compared to conan/vcpkg (which I don't think can handle components) and could be used with libraries such as Qt, Boost and more.
I understand it may be complicated to implemented (especially the first solution), but I think it's worth it. Also the second solution can be implemented quickly to help a bit for now.
It wouldn't break compatibility if we make
add_packages("xxx")
select all components by default.Describe alternatives you've considered
Described at the top.
Additional context
No response
The text was updated successfully, but these errors were encountered: