Right now it looks like if you run
vcpkg install foo
vcpkg install bar
vcpkg export --nuget foo
vcpkg export --nuget bar
and then install the foo and bar nuget packages in Visual Studio then the settings like include path for the second package are duplicated from the first one.
Is there a workaround for this problem at this time?
I've also experienced this bug today and created a script that "fixes" NuGet packages created by vcpkg export --nuget by introducing "namespaces" to MsBuild properties used by generated NuGet packages:
https://gist.github.com/AlexBAV/61598f8a7f21e65a0299cdcc6ccbc7e0
Is there a workaround for this problem at this time?
You can include multiple packages into a single NuGet package and then using that package will give you all of the packages that it contains. In your example:
vcpkg install foo bar
vcpkg export foo bar --nuget
Will yield a NuGet package that contains both libraries and does not conflict with each other.
That is correct, but I think that having separate packages is more convenient for the following two reasons:
Packages can be used by multiple projects. For example, project A uses both foo and bar, while project B only uses foo.
Packages can be updated separately. For example, when foo updates from version 1.0.0 to version 1.2.0, you don't need to repackage both foo and bar and end up having three packages in your NuGet store: foo.1.0.0, foo.1.2.0 and bar.1.0.0.
Moreover, it is the way "classic" NuGet works: you have separate boost and ChakraCore packages instead of one giant meta-package.
This seems to be happening because all the vcpkg.targets files define properties and targets with the same name, and if you use multiple packages then they conflict with each other.
We were able to work around this by updating the /scripts/buildsystems/msbuild/vcpkg.targets file so that each NuGet package uses
Do you mean that this issue is now fixed in the vcpkg sources?
Having a single NuGet package has merits.
Even though NuGet indeed works with separate packages per library for C#, C++ doesn't compose as well. In general you can't easily mix and match C++ packages like you can in C#.
For example, if you have built cpprestsdk it matters a lot which versions[1] of boost, zlib, websockets (those are its dependencies) you used to compile it. If you used boost 1.68 to build, I agree it would be convenient to grab the just-released boost 1.69 and simply change only that package, but unless binary compatibility was retained between versions, it won't work. Worse, you may get very difficult to diagnose runtime errors. If you update to boost 1.69, you need to rebuild all the libraries that depend on it (vcpkg upgrade will do it for you).
Another risk is the diamond problem. Let's say we have the simple dependency graph:
A-> B -> D
A-> C -> D
If you can replace B,C you might end up with packages that were built against different versions of D.
This is one of the major reasons vcpkg works via sources. As for export, when you export to NuGet (or zip etc), you get the libraries you asked for and all the transitive dependencies that they were built against, guaranteeing consistency across the entire library-set. Separate NuGet packages would make it extremely easy to unknowingly get trapped into an inconsistent state between libraries.
[1] In fact, version number might not be sufficient. A stronger guarantee (that vcpkg provides) is that the exact same sources are used. For example, if I apply a patch that adds a bool to a public class of a library, all libraries that depend on it should be rebuilt, because it is a change that breaks binary compatibility.
This also prevents using an exported NuGet packaged with local MSBuild integration since they use the same mechanism (%appdatalocal%\vcpkg\vcpkg.user will include the local targets file first which claims the VcpkgRoot variable and prevents the NuGet package content to be found).
@LilyWangL @dwcullop I have a fix that I think is worth putting in vcpkg to resolve this issue, which follows a similar idea to this comment.
When vcpkg exports a raw folder, the vcpkg.targets file it generates should contain a unique VcpkgRoot element name for the given package. So for example when raw exporting cpprestsdk rather than having an element called VcpkgRoot, the vcpkg.targets file will have an element called VcpkgRootCpprestsdk. Does this sound OK to create a PR for, or is it something you don't want added to vcpkg?
Most helpful comment
That is correct, but I think that having separate packages is more convenient for the following two reasons:
Packages can be used by multiple projects. For example,
project Auses bothfooandbar, whileproject Bonly usesfoo.Packages can be updated separately. For example, when
fooupdates from version 1.0.0 to version 1.2.0, you don't need to repackage bothfooandbarand end up having three packages in your NuGet store:foo.1.0.0,foo.1.2.0andbar.1.0.0.Moreover, it is the way "classic" NuGet works: you have separate
boostandChakraCorepackages instead of one giant meta-package.