Open Arech opened 10 months ago
"default-features": false
just means the port does not depend on the default features it does not say that you do not want default features. If you do not want default features you need to explicitly say so on the command line or within or projects manifest. If a port is transitively pulled in you also need to mention that port and say you don't want the default features of that.
Thanks for the reply, Alexander
"default-features": false
just means the port does not depend on the default features it does not say that you do not want default features.
I'm not an English language expert and not a native speaker, but to me if that's correct, then the docs with "If the user wants to explicitly disable the default features, they can do so by adding "default-features": false
" is misleading. Or at least semantic of "default-feautures" is different for app manifest file (where it disables them indeed), and for ports (where it means something else).
Can that be documented?
If a port is transitively pulled in you also need to mention that port and say you don't want the default features of that.
Do I get you right, that if I want opencv4[ffmpeg]
to install only 4 features it needs (that are explicitly listed in opencv4 port manifest) instead of 6 default, I should manually specify dependency on ffmpeg
in my app's manifest with these 4 features? So I basically should depend on opencv4
port internal implementation and must also freeze it's version?
, I should manually specify dependency on ffmpeg in my app's manifest with these 4 features?
It is enough to say you want ffmpeg with "default-features": false
. The other features will be pulled in by opencv4
since they are required by it.
Also there is nothing more to document. The docs already say:
Default features are a set of features to be automatically activated if the top-level project does not explicitly request a build without them
@Arech In actual testing, this function is normal and it does disable the build of the default features. But there is currently a problem: the installation log incorrectly displays the default features.
{ORM}
was not passed to install the feature orm
.
at least semantic of "default-features" is different for app manifest file (where it disables them indeed), and for ports (where it means something else).
This is right. In port manifests, it declares a possibility and enables user choice. The actual control is only in user project manifests (or at the command line using pseudo feature core
).
That's a bit confusing... I think I haven't seen that difference mentioned in ports creation documentation, but now I understand it better. Probably should be said somewhere more explicitly...
Anyway, thanks a lot everyone involved and have a great weekend!
(and a personal thanks to @FrankXie05 for spotting the issue)
Currently, I can confirm that this feature is indeed broken. (either from the configuration parameters passed or the actual installed dependencies).
When default-features
is false, the installation dependencies of default-features
will not be prohibited at all.
@JavierMatosD @BillyONeal Could you please help take a look?
Currently, I can confirm that this feature is indeed broken. (either from the configuration parameters passed or the actual installed dependencies).
When
default-features
is false, the installation dependencies ofdefault-features
will not be prohibited at all.
@FrankXie05 please explain what is broken, given the expected behavior presented in
https://github.com/microsoft/vcpkg/issues/35694#issuecomment-1856695326,
https://github.com/microsoft/vcpkg/issues/35694#issuecomment-1857543880,
https://github.com/microsoft/vcpkg/issues/35694#issuecomment-1857861606.
Erm... Here's another test that shows that default-features: false
works in a strange way even in an application manifest:
App manifest file explicitly prohibits default-features
of opencv4
port and explicitly lists only jpeg
feature that depends only on libjpeg-turbo
.
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "myapp",
"version": "1",
"vcpkg-configuration": {
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg-configuration.schema.json",
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "000d1bda1ffa95a73e0b40334fa4103d6f4d3d48"
}
},
"features": {
"common-opencv-port": {
"description": "A single common for the whole repo port of OpenCV",
"dependencies": [
{
"name": "opencv4",
"default-features": false,
"features": [ "jpeg" ]
}
]
},
"irrelevant-feature": {
"description": "heavy ports just for testing, they shouldn't be used",
"dependencies": [ "opencv3", "opencv2" ]
},
"myfeature": {
"description": "will use this feature only. common-opencv-port might be a dependency of many other features of this app",
"dependencies": [
{
"name": "myapp",
"default-features": false,
"features": [ "common-opencv-port" ]
}
]
}
},
"dependencies": []
}
CMakeLists.txt to choose which feature to use depending on build settings
cmake_minimum_required(VERSION 3.16)
# choosing feature list (depending on some CMake vars in a real project)..
set(VCPKG_MANIFEST_FEATURES "myfeature")
# trigger vcpkg
project(MyTestProj)
I expect it to use only `"jpeg" feature of OpenCV4 port.
Now run and observe what vcpkg starts to build:
$ rm -rf ./build;cmake -B ./build -G Ninja -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
-- Running vcpkg install
warning: Embedding `vcpkg-configuration` in a manifest file is an EXPERIMENTAL feature.
Fetching registry information from https://github.com/microsoft/vcpkg (HEAD)...
Detecting compiler hash for triplet x64-windows...
The following packages will be built and installed:
* flatbuffers:x64-windows@23.5.26#1 -- ...\vcpkg\registries\git-trees\2f827d9a5f37614af7cdb44c15075dbaac88d740
* libjpeg-turbo:x64-windows@3.0.1 -- ...\vcpkg\registries\git-trees\481b08127d4002ba7441f144df259e03271e7592
* liblzma:x64-windows@5.4.4 -- ...\vcpkg\registries\git-trees\f285b7c4ffa2cc065c7c6fec4b61006f7fa2714e
* libpng:x64-windows@1.6.40 -- ...\vcpkg\registries\git-trees\1a2a7f489e57c9e55e049b7c5f0a28c8ff4464ed
* libwebp[core,libwebpmux,nearlossless,simd,unicode]:x64-windows@1.3.2 -- ...\vcpkg\registries\git-trees\0b981028589375097039d5e39e7d87659cdfa824
* opencv4[core,default-features,dnn,jpeg,png,quirc,tiff,webp]:x64-windows@4.8.0#12 -- ...\vcpkg\registries\git-trees\c3d46b66df37511cf7b49ceffe96f5ff62acf6ea
* protobuf:x64-windows@3.21.12 -- ...\vcpkg\registries\git-trees\3b145508ba614fe26989b23f6317f15bf6467be4
* quirc:x64-windows@1.1#3 -- ...\vcpkg\registries\git-trees\85b17d675bbbb05448d16af79d434bc5fca51f7b
* tiff[core,jpeg,lzma,zip]:x64-windows@4.6.0#1 -- ...\vcpkg\registries\git-trees\1c0fc716f916833234f0fb5e7061d52e9063e7c6
* vcpkg-cmake:x64-windows@2023-05-04 -- ...\vcpkg\registries\git-trees\88a7058fc7fa73a9c4c99cfcae9d79e2abf87a5a
* vcpkg-cmake-config:x64-windows@2022-02-06#1 -- ...\vcpkg\registries\git-trees\8d54cc4f487d51b655abec5f9c9c3f86ca83311f
* vcpkg-get-python-packages:x64-windows@2023-07-28 -- ...\vcpkg\registries\git-trees\80e0cf9d38d72126b34eb1ee9b33f936c778a696
* zlib:x64-windows@1.3 -- ...\vcpkg\registries\git-trees\5ac18c6e6e3e2bf5a9e3d0bc8a845f198e4c4e05
Additional packages (*) will be modified to complete this operation.
......
vcpkg ignores requirement to use only explicitly specified features and use all defaults instead. And it's not that it shows it wrongly, it really starts to build every other damn feature I don't need.
$ $VCPKG_ROOT/vcpkg.exe --version
vcpkg package management program version 2023-12-12-1c9ec1978a6b0c2b39c9e9554a96e3e275f7556e
$ cmake --version
cmake version 3.27.2-msvc1
The same behavior I see on Ubuntu 20.04 @ WSL
$ $VCPKG_ROOT/vcpkg --version
vcpkg package management program version 2023-12-12-1c9ec1978a6b0c2b39c9e9554a96e3e275f7556e
$ cmake --version
cmake version 3.25.1
You can clone https://github.com/Arech/vcpkg_default_features repo with that code
If I'm doing something wrong here, please advice me on how to modify the code to make it only use explicitly specified features? Current behavior brings enormous toll on our CI and on local devs...
If I'm doing something wrong here, please advice me on how to modify the code to make it only use explicitly specified features?
No, I think you provided a small reproducible example to prove the bug. 💣
VCPKG_MANIFEST_FEATURES
). 👍 I didn't test with CMake but with vcpkg install --dry-run
and file modifications. Please verify my observations with CMake:
Explicitly adding common-opencv-port
to VCPKG_MANIFEST_FEATURES
will give the desired minimal installation.
Please verify my observations with CMake: Explicitly adding common-opencv-port to VCPKG_MANIFEST_FEATURES will give the desired minimal installation.
I don't need to run it to confirm your guess, as I see it regularly in the projects I deal with. Yes, referencing a feature directly will make vcpkg to respect default-features: false
and make a minimal installation.
Assuming that the same code in vcpkg handles feature aggregation for top-level manifests and for ports, it looks like handling of features is somewhat broken for anything but directly and externally requested features. Features of a port dependency (such as I described in the first message) are never requested directly, hence default-features
setting is ignored for them too.
To me the explanation of default-features
behaviour in ports given in the thread ("In port manifests, it declares a possibility and enables user choice. The actual control is only in user project manifests" and so on) looks much more like a rationalization of existing bug->feature p.o.v. than a concious design choice, b/c as a user I absolutely don't need that "declares a possibility and enables user choice". There's absolutely no value in that for me, only headaches how to make ensure that 100s of dependencies are used optimally. I need the fastest runtime and hence the least amount of code to be built, i.e. minimal dependencies by default. Besides anything, that "a possibility that enables choice" just breaks encapsulation of information: a user just shouldn't have to know and do anything to ensure the ports they are using are behaving in an optimal way, so port creators strive to define minimal dependencies and the fact that vcpkg ignores that is a clear bug to me.
I need the fastest runtime and hence the least amount of code to be built, i.e. minimal dependencies by default.
It is a fair requirement for some use cases, and there is much support for adding an option to enable such a minimal-dependencies mode. And there is https://github.com/microsoft/vcpkg-tool/pull/538 which still doesn't seem to get enough interest from Microsoft.
Besides anything, that "a possibility that enables choice" just breaks encapsulation of information: a user just shouldn't have to know and do anything to ensure the ports they are using are behaving in an optimal way.
Doesn't installing minimal features just have the effect of forcing users to know and request all the features which they would expect to be generally included?
Can we really make the general assumption that minimal is optimal for every user when the set of features may vary between "barely usable" and "overkill"?
Nobody claims that the default size fits all. But IMO the concept of default features seems a reasonable approach to avoid forcing users to acquire detailed knowledge about the features of each single port. Until they are really interested in customization.
Doesn't installing minimal features just have the effect of forcing users to know and request all the features which they would expect to be generally included? Can we really make the general assumption that minimal is optimal for every user when the set of features may vary between "barely usable" and "overkill"?
There are several things to unpack here.
(1) I don't propose to force always installing minimal features. I think that current system that have some features enabled by default and a machinery to fully customize features are ideal and probably can't even be improved. I just want vcpkg to respect it's own settings, because actually the current approach (ignoring default-features:false
for all non primary dependencies) is really detrimental and actually doesn't bring value even to those to whom it's supposed to help - I'll talk on that further.
(2)
Doesn't installing minimal features just have the effect of forcing users to know and request all the features which they would expect to be generally included?
I think the answer is definitely no and here's why:
opencv4
port currently depend on libjpeg-turbo
and installs it, doesn't mean, that I can rely on this dependency at all. If I want to use libjpeg-turbo
in my code, I must list it as my code dependency directly in my manifest. Otherwise, should opencv4
abandon this dependency for any reason - my code will just break. That's just an engineering basics of managing dependencies and vcpkg should help people to follow it, not actively prevent that!default-features:false
is not just not helping users, but is provoking really bad engineering practices.(3) The last but not the least, why ignoring default-features:false
is a serious problem that cost lots of money:
Many ports depend on dependencies that are fully external to vcpkg. Be it a platform SDK, system installed packages, or some specific user installed software, - most, if not all, non-trivial ports depend on it. These external dependencies gets updated on it's own schedule and vcpkg does great job on tracking dependent files change, and forcing recompilation of ports that depend on changed files. This is not very frequent on Windows, though even there a compiler might be updated a couple of times per month (requiring to recompile everything), but on Linux... it's a real pain on Linux, because the amount of system dependencies in form of source code is huge, and a system might get several updates per day. Not all these updates are in a dependency chain of some used port, but some of them are. We have quite a modestly sized project depending on boost and opencv ports and due to this, vcpkg has to rebuild many ports several times a week. This takes up to a dozen of minutes locally (multiply that by the number of developers affected) and then there are Azure CI agents that are less powerful than local workstations and depending on amount of changes, sometimes CI jobs even timeouts of an allocated hour of working time. This time is also wasted, because oftentimes developers depend on their PR to get merged before they can proceed further. So all of this stack up to a huge amount of wasted time for the company. I'm active vcpkg advocate in my company. I know what the life was before vcpkg in C++ and I really feel vcpkg is a great tool to solve a huge pain. But people got really annoyed by that frequent rebuilds and I constantly have to address their concerns of wasted time. My main argument is that "it rebuilds dependent ports to integrate the latest updates made to the system and that allows us to release a safer software." But now I must also add this: "Unfortunately vcpkg just ignores the dependency specification and adds a lot of absolutely irrelevant ports to the build plan. Most of rebuilds are caused by a change in some dependency of a port or a feature that we just don't need at all, so indeed most of that person-hours per week taken by rebuilds are just wasted".
Ah, and there's another major independent reason why ignoring default-features:false
in ports is really bad idea: vcpkg's CI doesn't have 100% coverage for all supported platforms. For example, it doesn't cover QNX operating system at all and I repeatedly face challenges and obstacles while building my company's software for it. The latest issue I struggle with is with building some dependency of HDF5 file format support port. I had to totally drop support for QNX for the piece of software in question, because I had no time to address the port building issue. Given that default-features:false
is ignored I'm not even sure that we are blocked because the failing port is important, not that vcpkg is trying to build the damn port just for the sake of some ephemeral completeness that we don't even need. What could possibly be dumber and worse than that situation?
- second, but it is the most important: port dependencies (at least theoretically) must always remain private to the port; It must be only the port's concern on which other ports it depend on. Users mustn't rely on any knowledge of internal implementation of ports they use. Port implementation should be able to change its own dependencies without any fear of breaking user's code. For example, the fact that
opencv4
port currently depend onlibjpeg-turbo
and installs it, doesn't mean, that I can rely on this dependency at all. If I want to uselibjpeg-turbo
in my code, I must list it as my code dependency directly in my manifest. Otherwise, shouldopencv4
abandon this dependency for any reason - my code will just break. That's just an engineering basics of managing dependencies and vcpkg should help people to follow it, not actively prevent that!
Understood. But the interpretation of default-features
doesn't change isolation. Dependencies simply are not "private" here. (gn
and alike do something like this IIUC.) In vcpkg, as soon as one package ("privately") depends on opencv4[jpeg]
, the libjpeg-turbo
dependency of this feature will be installed before opencv4 and found by every other consumer.
There's no way to "expect something installed along with a port".
Agreed, with regard to "installed". But AFAIU the main purposes of "default-features" is not to install dependencies but to provide typical (but optional) capabilities. Like the most common compression modes in tiff
. Or the most common raster and vector formats in gdal
. Or GUI support in qtbase
. Without default-features
, the default installation would provide packages which would frequently be perceived as unusable, or broken, e.g. because they can't read, process or display a "typical" TIFF file.
Maybe that's the key problem: Most of us want minimal dependencies. But what is offered for control are features.
Most of us also want less rebuilds. But the immediate control is to pin versions, not the interpretation of default-features
.
default-features
...The latest issue I struggle with is with building some dependency of HDF5 file format support port.
HDF5 is challenging in all cross-builds. Upstream wants you to detect properties from your target runtime and feed them in at build time. And still, vcpkg cross-builds gdal and opencv4 in CI. With hdf5 kept out of (unconditional?) default features.
But AFAIU the main purposes of "default-features" is not to install dependencies but to provide typical (but optional) capabilities.
Yes, it was a bad phrasing on my side. By "installed" I meant not just installing binary tools, but primarily making additional headers available for inclusion and libraries/entry points into libraries to linking to for the port affected. These additional capabilities usually in the essence are just some additional code a vcpkg user could rely on in a transparent manner.
Anyway, we seems to agree on the definition of the problem.
How can I ping people, who make the decisions that we need here? Who are they and how to reach them? This problem is really huge damn pain in the a*s for me personally and for my company...
- check and fix the handling of transitive dependencies in the user's manifest,
The 'top level manifest' parts were fixed by @dg0yt and landed in https://github.com/microsoft/vcpkg/pull/38339
I just did a git pull
on vcpkg and .\bootstrap-vcpkg.bat
, which updated vcpkg:
Downloading https://github.com/microsoft/vcpkg-tool/releases/download/2024-04-23/vcpkg.exe
[...]
vcpkg package management program version 2024-04-23-d6945642ee5c3076addd1a42c331bbf4cfc97457
I've got a package that I want to depend on opencv4 but not on its default features (because it essentially just needs cv::Mat
, nothing else). vcpkg-custom-overlay/my-test-package/vcpkg.json
:
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "my-test-project",
"version": "1.0.0",
"homepage": "https://gitlab.com/private/private",
"dependencies": [
{
"name" : "vcpkg-cmake",
"host" : true
},
{
"name" : "vcpkg-cmake-config",
"host" : true
},
{
"name": "opencv4",
"default-features": false
}
]
}
As far as I understood this thread, there should be a way of installing my-test-package with its opencv4 dependency without default features? How do I do that? If I do on the command-line: .\vcpkg.exe install my-test-package[core] --overlay-ports=C:\Users\MyUser\vcpkg-custom-overlay --dry-run
, it still pulls in opencv4[core,default-features,dnn,jpeg,png,quirc,tiff,webp]:x64-windows@4.8.0#19
.
Am I misunderstanding this thread, or is this still not possible, or am I doing something wrong?
(The difference in build-time, dependency size etc. between opencv4[core]
and opencv4
(with default-features) is factor 3-5x, this probably warrants a separate issue specific for OpenCV, but in general for vcpkg there needs to be a way for a project that only depends on a dependency's minimal configuration to actually do kick off that build with the dependency being compiled without default-features.)
As far as I understood this thread, there should be a way of installing my-test-package with its opencv4 dependency without default features? How do I do that? If I do on the command-line:
.\vcpkg.exe install my-test-package[core] --overlay-ports=C:\Users\MyUser\vcpkg-custom-overlay --dry-run
, it still pulls inopencv4[core,default-features,dnn,jpeg,png,quirc,tiff,webp]:x64-windows@4.8.0#19
.
You ("user") must ask for it in the command line or in the your "top-level" manifest. (The port manifest is just an enabler.) Command line example:
.\vcpkg.exe install my-test-package opencv4[core] --overlay-ports=C:/Users/MyUser/vcpkg-custom-overlay
Describe the bug I might misunderstand something in vcpkg, but I though that according to the docs,
"default-features": false
should totally disable default feature set defined for a port and install only explicitly selected features. But it's not the case. Default-features are always selected and installed.I have a private repository containing two ports:
X
with two features:heavyA
andlightB
, and"default-features": [ "heavyA" ]
.Y
with several features, one of which, say"featureB"
hasI assumed that when manifest contains a dependency on port
Y[featureB]
, then vcpkg must also install portX
with featurelightB
only, b/c default features, containingheavyA
, are disabled. However, when building a software I noticed that portX
installs both features, -heavyA
(that should be disabled) andlightB
. I've double checked everything and I can't find any potential source of dependency on featureheavyA
of portX
anywhere.I was able to replicate that with publicly available ports: opencv4 port contains a spectra of default-enabled features.
opencv4
hasffmpeg
feature defined in a similar manner with restricted feature set:By default ffmpeg port has these default features:
So I assume that when I install
opencv4[ffmpeg]
only 4 specifically selected by opencv4 manifest's features must be present. However, it's not true:i.e. vcpkg fetches all default features for
ffmpeg
plus those additionally specified, and foropencv4
it also selects all default features plusffmpeg
feature as an addition, instead of using it exclusively. (depend-info
command is used to demonstrate the issue, the same is happening when vcpkg really install ports)This seems like a bug to me. Documentation clearly states:
(see the bottom of the page)
Do I misunderstand something?
Environment The same results in Windows 10:
as well as on Ubuntu20.04 (in WSL with own vcpkg checkout, which hardly matters..)