I have two packages installed, and both contain the same precompiled assembly file. This causes an error in Unity and I have no idea how to resolve this issue. Both files are necessary for the packages to function, so deleting them is not in question. How should I resolve this error?
I've forked one of the packages and attempted to rename the DLL file and re-add everything into the Assembly References section of the Assembly Definition Import file - however, one version of the DLL file is 3.8.0.0 while the other is 3.15.0.0.
The DLL file is Google.Protobuf.DLL
Many thanks.
Welcome to the Dependency Hell =)
If we are talking about how to resolve this - don't think there is some easy solution =/ I can suggest several options but both are not perfect at all.
Let's say that package A requires protobuf v3.8.0.0 and package B requires protobuf v 3.15.0.0.
First of all, you can try to check older releases of package B to try to find one with protobuf v3.8 dependency instead of v3.15. Or, vice versa, try to find newer release of package A with v3.15 dependency instead of v3.8. If you are lucky enough - it can help.
If package A or package B has source code available (for example, it is a git repo), you can try to adapt it to another version of the protobuf library manually (create your custom version or even make a pull request to the package repo). But this variant can cause future problems with package updates as you will have to support your custom changes.
Related
Context
I have a Managed C++/CLR library which is built using CMake 3.17, and packaged into a NuGet package using CPack. The resulting nupkg file cannot be imported into a C# project, as the Package Manager issues the following error: "[snip] the package does not contain any assembly references or content files that are compatible with [.NETFramework,Version=v4.5.2]". However, adding a reference to either the project when added to the solution, or the corresponding library file generated by the build, works as intended.
C++/CLR Details
The code itself is very basic and produces a valid library which can be referenced from another project, when manually adding a reference via Visual Studio 2017 -> Add Reference (either the project or the corresponding library can be added this way and it works all the same).
The code consists of the class itself, and AssemblyInfo.cpp provides attributes which describe the metadata and version information only. The dependencies include only System, System::Runtime::InteropServices, and a raft of pre-built native libraries.
I have not added a .nuspec file, nor a nuget.config file, the latter which I believe is generated by the CPack NuGet generator when the package is built.
CMake / CPack Details
CPack NuGet support is relatively new, and I have been unsuccessful in finding a working example, but I have managed to successfully generate a nupkg file. Firstly CMake is instructed to build a Managed C++ library with the included source files, and the following properties set on the corresponding target ManagedLibrary:
set_target_properties (ManagedLibrary PROPERTIES DOTNET_TARGET_FRAMEWORK_VERSION "v4.5.2")
set_target_properties (ManagedLibrary PROPERTIES COMMON_LANGUAGE_RUNTIME "")
The documentation states that this will generate CLR/Mixed code and works as advertised, so I am able to successfully build against the target framework. The next step was to install the library in what I believe is the correct location:
install (TARGET ManagedLibrary DESTINATION . COMPONENT MixedCLR)
And supporting (native C++) libraries are installed similarly:
install (FILES [various..] DESTINATION . COMPONENT MixedCLR)
I also set CPACK_GENERATOR to 'NuGet', and then run the PACKAGE step from the CLI using cmake --build . --target PACKAGE which successfully produces the nupkg file.
Question
How does NuGet know what libraries to add a reference to?
Is a nuspec file required? If so, what must minimally be included in it, and how do I include it in the target CMakeLists.txt?
Is it acceptable to put the managed library, along with supporting native libraries, in the root of the package? If not, where should they go?
Are any other files generally included in a nupkg file?
Finally, if anyone knows anything about packaging and multi-targeting in C++/CLR to support different framework versions / architectures / build configurations, any notes on that would be highly appreciated.
How does NuGet know what libraries to add a reference to?
Primarily NuGet infers the libraries to reference from the package structure. Managed assemblies must be put in a directory which is libs/<TFWM> where TFWM is the Target Framework Moniker (eg: .NET Framework 4.5.2 => net452).
Is a nuspec file required? If so, what must minimally be included in it, and how do I include it in the target CMakeLists.txt?
The nuspec file is automatically generated by CPack at package generation time. The generated file is saved to the output directory, and will preserve the directory structure specified by the install command.
Is it acceptable to put the managed library, along with supporting native libraries, in the root of the package? If not, where should
they go?
As already discussed, the managed libraries go in libs/blah. Native libraries, on the other hand, go in runtimes/<RID>/native where RID is the Runtime ID. In my case I wanted to target Windows 64-bit, so the Runtime ID is win-x64.
Are any other files generally included in a nupkg file?
I bundle the PDB for convenience, but I didn't need to specify any other files or properties.
Finally, if anyone knows anything about packaging and multi-targeting
in C++/CLR to support different framework versions / architectures /
build configurations, any notes on that would be highly appreciated.
If targeting multiple framework versions it's simply a case of creating and installing multiple targets into the respective folders, there's nothing more complex to deal with.
Finally, my finished package structure looks like the following:
libs/
net452/
ManagedLib.dll
ManagedLib.pdb
runtimes/
win-x64/
native/
NativeLib1.dll
NativeLib2.dll
...
I hope this helps someone in the future.
I'm looking for a way to detect problems with assembly references in a large Visual Studio solution:
Binary references to bad locations, like a path not in source control or in the output of another project
Binary references to multiple versions of the same assembly across projects in the solution
Binary references without a path, that may be redirected to the GAC
Binary references that should have been project references
The whole story
I work on a large C# project with almost at 200 projects.
One of the problems that is creeping in over time is that references to assemblies are added but not always to the same version or to the correct location.
For example, a project may get a reference to System.Web.Mvc without a hint path, making it reference what ever version is in the GAC. Visual Studio (and Resharper) will also offer to add a missing reference but may do so by adding a reference to the output folder of another project.
Now the recent Windows Update catastrophy left some team members dead in the water, unable to build the solution. As you can imagine, this bumped up the priority of assembly reference management for us.
To detect some of the most obvious problems I've already setup an msbuild file that can be included in every csproj file and will detect bad references.
However, new project files will need to be edited manually to include that script. So that will inevitably be forgotten.
What I would really like is to check all project files in a solution for 'bad' references during the continuous build, so that all projects will be checked always.
I've been googling for a solution like this for some time and found lots of static analysis and code analysis tools but nothing to analyze project files in a solution.
So, before I go off and roll my own solution, is there a way to do this already?
Update
In order to clean up the code base I've created a bit of ScriptCS code that'll scan all csproj files for referenced to assemblies in Nuget packages and fix them. It's up on GitHub.
You can create a NuGet package where the sole purpose is incorporating a custom .targets file into a project. I recently used this strategy to solve another problem (error messages for missing .snk files).
Testing strong names of NuGet-distributed assemblies
Rackspace.KeyReporting source code
If you create a similar package, it's easy to right click on your solution node and verify that it is installed in all of your C# projects.
If your analysis is more complicated and requires the use of an assembly (custom build tasks) in addition to the .targets file, you can use an approach like I use for the Antlr4 NuGet package, which contains build tasks, resources, and custom .props and .targets files, but no actual assemblies that are referenced by the project it gets installed in.
ANTLR 4 C# Target source code (includes the Antlr4 package source and build scripts)
Instead of adding it to all projects in your solution, why not create some kind of test (unit test, build file, whatever) that can take a project file as input, parse it, and throw an error if OE or more references are incorrect. Much easier than adding (and checking out, committing etc) custom build steps to project files.
Even if you would use a nuget package as proposed earlier, you'd still have to check manually whether all your projects (200 projects? Really?) Reference the package.
I have an c# application with two libraries ( moon-apns, tweetsharp ) .. Each library has a reference for newtonsoft.json.dll but different versions ... My app build successfully but one library works fine and the other one throws an exception ( can't find the dll file ).
I think that when i build only one version goes to the bin folder, but i don't know what to do.
Thanks in advance.
You can force both libraries to reference the same version by using Assembly Binding Redirects in your app.config or web.config. Obviously this only works as long as the library versions are compatible.
Since you stated you have access to the source of the two libraries:
In both projects, set the reference to newtonsoft to not required Specific Version. Rebuild those projects.
Now, when you build your main project, the two libraries should be ok with the same version of the newtonsoft DLL as long as there is no compatibility issues
I'm curious how others do it, or if there's an easier way...
I'm having multiple projects which are referencing the same DLL i.e. nhibernate.dll.
Those dlls are stored in version folders like NHibernate-3.2.0.
If a new version comes out and we are going to upgrade to it, we create a new version folder and need to update all referencing projects to the new dll.
Is there some easier way to do that? Like some central project (lets call it REF_PROJ) which references nhibernate and all other projects are only referencing REF_PROJ?
So the updating of the new version has only be done at one central place, the REF_PROJ.
Your solution is one way. The "better" way IMHO is to use nuget packages. Specifically the nhibernate nuget package. Then you can right click on the solution and update all the nhibernate packages when a new version comes out.
EDIT: To add to the other answer. If you wish to use a specific version of the nuget package that targets a particular version of the assembly in the package, use --version when you install them from the package manager console.
Just have a root folder, not version specific. Or if you really need version specific, then have 2 copies - one in the root folder and one in a version specific folder.
here is an example of what i mean.
nhibernate
--> nhibernate 3.2
----> nhibernate.dll
--> nhibernate.dll
Another solution is to using the GAC
register your assemblies into gac, and add reference to it from multiple projects without specifing assembly version . and update it easy with gac util.
I'm trying to figure out what the best way to handle this scenario is.
Let's say I have a library that's referenced by multiple different non-related solutions, let's call it WebServiceInterface.dll. This library has a dependency on JSON.NET.
Before NuGet
The JSON.NET binary was referenced via a SVN external in the WebServiceInterface project. Other solutions which had a dependency on WebServiceInterface referenced the project (also as an SVN external) and as a result pulled both the project, and it's dependencies.
With NuGet
I haven't figured out how to force the JSON.NET reference to be stored under the WebServiceInterface project (as opposed to the RandomSolution\packages location). I found reference # nu-get to project-level and solution-level pacakges, but I can't seem to find out how to specify this when I add a dependency via nu-get.
The goal here is that when someone checks out WebServiceInterface and adds it to a new solution that it builds (instead of having broken references to JSON.NET which point to the packages directory under whatever the last solution was that checked in).
When I went to find out if Chris B had created a NuGet issue for this, I couldn't find one. EDIT: He did, see his comment below. But I did find a semi-documented feature of NuGet that I used to solve this problem: Allow specifying the folder where packages are installed
Let me break this question into 2 issues:
getting NuGet to allow for multiple solutions to use the same packages location
getting the NuGet packages to automagically fetch from source control when you include a project that has NuGet packages
Problem 1:
By default NuGet stores packages in a packages folder in the solution's folder. To change that location, create a nuget.config file in the solution's root folder with the following contents:
<settings>
<repositoryPath>..\..\..\Utilities\Library\nuget.packages</repositoryPath>
</settings>
<repositoryPath> is relative to your solution; so obviously make it whatever you want. Make each solution have it's own relative path to the same packages folder.
As far as NuGet's flow, from that point, the paths in repositories.config are relative to the folder containing repositories.config, not the solution, so now all projects/packages are managed independent of the solution location.
This allows multiple solutions to use the same packages in source control, and if those solutions use the same projects (that use NuGet packages), those solutions/projects will all be kept in sync no matter which solution updates the package.
Problem 1 completely solved.
Problem 2:
Let me address this from 2 perspectives. This applies to Visual Studio and TFS -- I'll leave SVN for someone else to address.
First: if you have no source code on your drive and do a get of a solution (not a project), I prefer to make it so that you get everything that solution needs to build. There shouldn't be any missing references to go manually grab. That much we can do by adding the package files as solution items. Yes, in each solution. A bit of work, yes, but when it's done the package files will fetch/update from source control automagically.
Second: In a new solution, when you include an existing source control project that has NuGet packages, you have to manually fetch the packages from source control and add them as solution items. At least anyone else getting your solution in the future will automagically get everything they need to successfully build. At least with VS/TFS, this is just the way it is, AFAIK. If projB depends on projA, and you add projB to a new solution, VS/TFS won't automatically grab projA from TFS. You have to do that manually. So then the same goes for dll references (like NuGet packages).
Summary of my solution:
Only one copy of packages in source control for all solutions
Any solution can update packages and all the other solutions will be kept in sync*
* Once one solution updates packages to new paths or file names, they will appear as missing references to the other solutions and you'll have to manually clean that up. But at least you know right where the packages are in source control "(as opposed to the RandomSolution\packages location)."
The packages are always stored at the solution level, so if you install a package into multiple projects, they came from the same place. I don't believe you can configure it so that each project has its own packages folder.
I'm not sure there's a nice way to do what you're trying. You could maybe have a build step on the project that fetches the package, but I don't know how well that will suit you.
I'd recommend posting in the NuGet Issue Tracker to get a discussion going. The people working on it seem pretty active, so it might be something they can add support for in a future version :-)