Excluding nuget package with x64 dll from output directory? - nuget

I've just added the nuget package Grpc.Core.Api into one of my projects.
The build platform target for this project is marked as x86, however the build process is placing both grpc_csharp_ext.x64.dll and grpc_csharp_ext.x86.dll into my output directory.
At ~10.2MB, this feels unnecessary. Is there any way to prevent the x64 variant from being included (other than manually adding a delete command in the Post-build event).

I can see these two .dll files: grpc_csharp_ext.x64.dll and grpc_csharp_ext.x86.dll after installing Grpc.Core NuGet package, and if I only installing Grpc.Core.Api NuGet package, they won’t be generated.
By checking the detailed MSBuild output log, this two files are copied by default task Copy. The logic(or control) of judging whether to copy or skip copying should be stored in .targets file of Grpc.Core NuGet package folder.
I then find the Grpc.Core.targets file under …\MyProject\packages\Grpc.Core.xxxxx\build\net45. If you find and open it, you will see the related settings:
<ItemGroup Condition="'$(Grpc_SkipNativeLibsCopy)' != 'true'">
<Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x86\native\grpc_csharp_ext.x86.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>grpc_csharp_ext.x86.dll</Link>
<Visible>false</Visible>
<NuGetPackageId>Grpc.Core</NuGetPackageId>
</Content>
<Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\grpc_csharp_ext.x64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>grpc_csharp_ext.x64.dll</Link>
<Visible>false</Visible>
<NuGetPackageId>Grpc.Core</NuGetPackageId>
</Content>
...
The <condition="'$(Grpc_SkipNativeLibsCopy)'!='ture'"> and <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> make grpc_csharp_ext.x64.dll be copied to the project output directory.
I don't think this can be overridden or be changed or be prevented by using MSBuild in .csproj files. As you mentioned, manually adding a delete command in the Post-build event should work, but it works after the file has been copied.
What I think/suggest
I may provide a silly or risky workaround. I don't recommend modifying the Grpc.Core.targets file, but if you change to <CopyToOutputDirectory>Never</CopyToOutputDirectory> for grpc_csharp_ext.x64.dll, this file will not be generated again if you only build for x86.
This maybe needs to be changed by author of this NuGet package, unless these actions(copy ..x64 files to output directory when building under x86) are necessary or for some reasons that we don't notice.
Again, I would agree on considering using Post-build event is better.

Related

How to execute custom script when installing nuget package?

I created this project https://github.com/RemiBou/RemiBou.CosmosDB.Migration, for working it needs the user to do 2 things : create the appropriate folders and edit the csproj so the file inside those folders are embedded.
Before we could do that automaticly when installing with install.ps1 but this feature has been deprecated. Do you know any way how I could do this ?
install.ps1 isn't exactly deprecated, but it's a feature unique to packages.config. PackageReference has no concept of install as anyone can simply edit the csproj and add a PackageReference. When you restore, NuGet has no way of knowing if this is the first time the package is restored for the project after the reference was added, or if it's just the first time the project was restored with a clean repo (after a "msbuild /t:clean" or "git clone", for example).
I don't know an alternative for creating the folders other than having documentation that says the convention is to use that folder name. But, an alternative to modifying the csproj is to take advantage of the fact that MSBuild is a generic build system and NuGet packages can include MSBuild props and targets file.
In your specific case, I would create a props file that defines a property something like <RemiBouCosmosDBMigrationPath>CosmosDB\Migrations\</RemiBouCosmosDBMigrationPath>, which allows your package users to change the property to a different path be overwriting the property value in their csproj, if they prefer.
Then create a targets file which contains a target something like
<Target name="RemiBouCosmosDBMigrationsEmbedMigrations" BeforeTargets="???">
<ItemGroup>
<EmbeddedResource Include="$(RemiBouCosmosDBMigrationPath)**\*.js" />
</ItemGroup>
</Target>
You'll need to figure out what the best target name to put in the BeforeTargets attribute, but I hope you understand the idea. A csproj file is nothing more than a MSBuild file with certain conventions. MSBuild files can import other MSBuild files, and MSBuild and NuGet work together to allow MSBuild to import MSBuild files that come from restored packages. Just compose the MSBuild properties and items in a different way, and the end result can still be the same.

nuget package with legacy DLLs

I want to create a nuget package that contains besides .NET assemblies "legacy" DLLs (non .NET DLLs), which are referenced or accessed by the assembly DLLs.
Where do I put these DLLs? How does the users program (exe), which uses my package, get access to these DLLs?
I can only think of two ways the users program can access these DLLs: either there is a PATH environment variable set to the appropriate directory or these DLLs are copied into the bin/Release and bin/Debug directories of the users project.
How would I deal with x86 and x64 versions of the legacy DLLs?
I would look at adding a custom MSBuild .targets to your NuGet package. Inside this .targets file you can define any MSBuild tasks you need which will allow you to hook into the build of the project. So you could have the non-.NET dlls copied into the output directory using MSBuild.
The PostSharp NuGet package is one example that copies extra files around during the build. However its MSBuild .targets file is fairly complex. You would not need to do anything as complicated as that. Probably something simple similar to:
<PropertyGroup>
<PrepareForRunDependsOn>$(PrepareForRunDependsOn);MyPostBuildTarget</PrepareForRunDependsOn>
</PropertyGroup>
<ItemGroup>
<ExtraFile Include="dlls\*.dll" />
</ItemGroup>
<Target Name="MyPostBuildTarget">
<Copy SourceFiles="#(ExtraFile)" DestinationFolder="$(OutputPath)" />
</Target>
The above is only an idea of what you could do.

NuGet Restore Fails when dependency adds a .targets import to the .csproj

I ran into an issue recently with NuGet restore. I added a project dependency (in this case PostSharp) and then enabled restore. I checked in the source, but not the /packages directory (as I shouldn't needed to....right!). When TeamCity or another developer grabs the source and runs MsBuild, they receive the following error:
C:\TeamCity\buildAgent\work\e374975c0264c72e\ProjectName\ProjectName.csproj(70, 3): error MSB4019: The imported project "C:\TeamCity\buildAgent\work\e374975c0264c72e\packages\PostSharp.2.1.5.1\tools\PostSharp.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
The problem is, NuGet hasn't run yet to restore/download PostSharp or it's .targets file. This feels like a NuGet bug to me, but wanted to see if others have this same issue.
Anybody have this issue or know the resolution. Yes, I could check-in the /packages directory, but then why use NuGet at all?
Another approach is to modify the <Import> element in question, to make it conditional, e.g.:
<Import Project="$(CodeAssassinTargets)" Condition="Exists($(CodeAssassinTargets))" />
This depends on a new property defined in an earlier <PropertyGroup>. I usually add one at the top of csproj file with other "global" flags, e.g.:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CodeAssassinTargets>$(SolutionDir)packages\CodeAssassin.ConfigTransform.1.1\tools\CodeAssassin.ConfigTransform.targets</CodeAssassinTargets>
<AutoParameterizationWebConfigConnectionStrings>false</AutoParameterizationWebConfigConnectionStrings>
<UseMsdeployExe>true</UseMsdeployExe>
</PropertyGroup>
Then in an appropriate target, like BeforeBuild, give a helpful error message:
<Target Name="BeforeBuild">
<Error Text="CodeAssassin.ConfigTransforms target is missing. It needs to exist at $(CodeAssassinTargets) in order to build this project!" Condition="!Exists($(CodeAssassinTargets))" />
</Target>
With these modifications, the project will load even if the nuget package restore has never been done. If auto package restore is enabled, the first build attempt should clear up the missing target issue, but if it does not, one manual package restore will.
#porterhouse91, have you checked your csproj file to make sure it has been set up with the appropriate build target?
I haven't yet tried the new built-in Package Restore feature, but I'm assuming it works at least somewhat like the previous workflows out there on the interwebs. If that's the case, enabling Package Restore in your solution only affects the projects in your solution at the time you enable it. If you've added a new project (having NuGet dependencies) to the solution since enabling Package Restore, you're gonna need to enable it again.
Another possibility: the previous workflows involved having a .nuget folder that you needed to check in to VCS, so you might need to check that in if it hasn't been checked in yet (if the built-in Package Restore feature does indeed use this approach).
BTW, if this answer is at all helpful, thank Stephen Ritchie -- he asked me to give it a shot for you.
I had a problem like this as well, but I was able to modify the .targets file in the source package to work around it. Basically, RestorePackages is a build target that runs when the project is built. Unfortunately, the package won't even load properly before the imports are satisfied. The only way I know to fix this is to include the .targets file as content and then change the BuildDependsOn property so it restores the packages before it runs your custom tasks.
<PropertyGroup>
<BuildDependsOn Condition="$(BuildDependsOn.Contains('RestorePackages'))">
RestorePackages;
CustomTarget;
$(BuildDependsOn);
</BuildDependsOn>
<BuildDependsOn Condition="!$(BuildDependsOn.Contains('RestorePackages'))">
CustomTarget;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
To be clear, this doesn't help with pre-built packages, but if you can build the package again yourself, you can fix it.
I ran into this same issue with Visual Studio 2012 and NuGet packages not checked into source control.
The error:
The imported project "\packages\Microsoft.Bcl.Build.1.0.7\tools\Microsoft.Bcl.Build.targets" was not found.
Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
I found a msdn writeup on the situation that gave the following workarounds for grabbing a project from source control without the NuGet packages.
Stop using package restore and check-in all package files
Explicitly run package restore before building the project
Check-in the .targets files
I decided to go with option #2, however, NuGet currently (v2.6) does not include a way to install all packges from the packages.config file from within visual studio. Some searching revealed that you need to use the NuGet Command Line to execute the following command before opening Visual Studio (reference).
c:\path\to\nuget.exe install -o packages project-folder\packages.config

Create nuget package with multiple DLLs

Let's say I have a project with this structure:
MyLibrary\
MyLibrary.sln
MyLibrary.Core\
MyLibrary.Core.csproj
MyLibrary.Extensions\
MyLibrary.Extensions.csproj
MyLibrary.Tests\
MyLibrary.Tests.csproj
I want to create a single NuGet package which packages MyLibrary.Core.dll and MyLibrary.Extensions.dll. I can't seem to figure out how to get NuGet to do this. I've tried building a spec file manually and I've tried building one using "nuget spec MyLibrary.Core.csproj". I've tried adding all of the DLLs to a lib/ folder which I understand to be the convention-based mechanism for adding DLLs to the package. In every case I can get the MyLibary.Core.dll to get into the package but the MyLibrary.Extensions.dll does not end up packaged along with it.
TLDR: What is the best practice for creating a NuGet package with multiple projects / assemblies? Is there a tutorial out there that focuses on this? The tutorials I've found all focus on simple single-project demos.
You'll run NuGet on a single project (or nuspec file), but it supports pointers to other projects via the file element. This element uses the names of your project's References, so you avoid having to a) find the location of other project files, and b) copy files to a particular place as a post-build step.
Supposing you have a nuspec file for MyLibrary.Core.csproj, and it references MyLibrary.Extensions and MyLibrary.Tests such that they end up in the bin directory after a build:
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
...
</metadata>
<files>
<file src="bin\Release\MyLibrary.Extensions.dll" target="lib\net40" />
<file src="bin\Release\MyLibrary.Tests.dll" target="lib\net40" />
</files>
</package>
With this setup, all of your references should end up in the appropriate place in the NuGet package. You still have the hard-coded 'Release' in there, but I'd wager most probably don't distribute NuGet packages of their debug builds anyway.
Did you generate a blank nuspec file with:
nuget spec
If you use that file and then put your dlls in a folder under it named lib, it will package them up.
I had a little trouble with trying to generate a nuspec file from a project or dll. Also, if you manually reference any files in the nuspec file, the conventions are not used. This is probably the problem with nuspecs generated from dlls or projects.
Also, if you are trying to run this from a build script that executes in a different folder, you can tell nuget the location of your .\lib folder via the -BasePath command line:
build\nuget.exe pack nuget\Company.Project.nuspec -BasePath nuget\
Have you tried NuGet Package Explorer? Might be the easiest way:
http://nuget.codeplex.com/releases/view/59864
It seems your problem is the same as this question: Why doesn't nuget include the referenced project when packing?. If so, you can use the -includereferencedprojects option (See http://docs.nuget.org/docs/reference/command-line-reference#Pack_Command).
I recently published a solution for this...
My solution enables automatic creation of NuGet packages when you build the solution where each package can contain multiple assemblies, references to both external NuGets and NuGets created during the same build and even include the source code for debugging.
In your case, all you will need to do is add a new class library project to your solution, reference the projects you want to package, then add a post build event.
You can find an article with a walk-through guide here
and the source code here.
i have some tutorial how i did it with windows and visual studio:
create local folder and call it packages like: c:/packages//lib - important to create another folder in folder call it lib and past there dll.
open nuget package explorer - https://npe.codeplex.com/downloads/get/clickOnce/NuGetPackageExplorer.application
the ui very intuitive just add dll and export it to /lib (for tutorial https://blog.zwezdin.com/2014/building-nuget-packages-with-gui-tool/ it in russian but see on pictures the flow it's about 3 clicks)
it will create nuspec file
open GIT BASH - https://git-for-windows.github.io/ and navigate to: cd c: => cd packages (the path of )
*maybe on windows you will need provide developer options for windows's linux stuff (https://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/)
in GIT BASH enter command: nuget add -source [options]
where: : the full name of nuspec (include .nuspec)
and: the path of folder lib in folder (c:/packages//lib)
after the action ended successfully
in GIT BASH enter another command:
nuget pack .nuspec
not in this folder you have .nupkg file.
How to install a Nuget Package .nupkg file locally? - tutorial how to add it to visual studio.
I had the same problem and I decided to create Nuget which will allow to create other nugets from chosen project.
Package is deployed on the Nuget.org site. After referencing it in the project You need to add nuspeck file to the projects which should generate the projects.
Project with the required nuspeck file
Last thing which should be done by you is invoke command Create-Nuspec in Package Manager. Than the powershell module will take all libraries which are result of the build it will add also the required dependencies and create the nuget in the output directory.
Description about this package is placed here.
I had an issue when adding extra dlls references to a Nuget packages, and testing the package on a sample project, the extra dlls was not being added apparently, no matter the way that I create the Nuget Package.
Then I released that when you uninstall and install again a local Nuget Package with the same version number the changes no take effect, the extra dlls are not added.
So each time you uninstall the package, close visual studio and clear the Nuget Cache,
How to clear NuGet package cache using command line?
Then open again Visual Studio and reinstall the local package to make the change takes effect.
Or make the package version to increase each time to be for Visual Studio to recognize your changes.
For example:
Package-1.0.0
Package-1.0.1
Package-1.0.2
.....
To create a Nuget package from a sample project there are some ways, for example:
Right click to your Visual Studio project and choose the "Pack" option
Then install the nuget package explorer:
https://www.microsoft.com/es-ec/p/nuget-package-explorer/9wzdncrdmdm3?activetab=pivot:overviewtab
And add manually your extra references (dlls files) to your specific targets.
Create a nuget package using a .nuspec file how specified in the documentation:
https://learn.microsoft.com/en-us/nuget/guides/create-packages-for-xamarin
<files>
<file src="Plugin.LoggingLibrary\bin\Release\Plugin.LoggingLibrary.dll" target="lib\netstandard1.4\Plugin.LoggingLibrary.dll" />
<file src="Plugin.LoggingLibrary\bin\Release\Plugin.LoggingLibrary.xml" target="lib\netstandard1.4\Plugin.LoggingLibrary.xml" />
<file src="Plugin.LoggingLibrary.iOS\bin\Release\iOsDependence.dll" target="lib\Xamarin.iOS10\iOsDependence.dll" />
<file src="Plugin.LoggingLibrary.Android\bin\Release\AndroidDependence.dll" target="lib\MonoAndroid10\AndroidDependence.dll" />
</files>
In your files part add your .dll files.
And dont forget, each time you uninstall and install again the nuget package from your local source.
Or you increase the version of the package each time:
Or close Visual Studio, clean the nuget cache and Rebuild your project.
In order to take effect the changes.

Checking in packages from NuGet into version control?

Prior to NuGet, it was common accepted 'best practice' to check-in all external DLLs used on a project. Typically in a Libs or 3rdParty directory.
When working with NuGet, am I supposed to check-in the packages directory, or is there a way for MSBuild to auto download the needed packages from the nuget feed?
No
Since this question was asked there is now an easy workflow to use NuGet without commiting packages to source control
From your package manager console you need to install the 'NuGetPowerTools':
Install-Package NuGetPowerTools
Then to enable your projects to support pack restore you need to run another command:
Enable-PackageRestore
Now you are ready to commit your code base without the packages folder. The previous command changed your project files so that if packages are missing they get automatically downloaded and added.
Source
Using NuGet without committing packages to source control
Yes. Consider the "packages" directory to be equivalent to your "libs" directory that you mentioned in your question. This is the approach I personally take with my OSS projects.
We are investigating features that would allow MSBuild to auto download the needed packages, but that hasn't been implemented (as of NuGet 1.1).
I think some people may have already implemented such features on their own, but our plan is to look at having that feature built in to NuGet 1.2 or 1.3 hopefully.
Despite all the answers here, it is still a plain ole' horrible solution to not have all your dependencies under "some kind" of version control.
For GIT, this would mean GIT-LFS.
The recent episode with NPM shows why: If the internet repository of which you depend breaks, are unavailable etc., well then you're screwed aint you?
You are no longer able to build your stuff - and therefore not able to deliver.
Since asking the question, I've put in the following approach so that I do not have to check in the toplovel Packages directory.
In a toplevel build.msbuild file:
<Target Name="NuGet">
<ItemGroup>
<NuGetPackage Include="*\packages.config" />
</ItemGroup>
<Exec Command='libs\NuGet.exe install "%(NuGetPackage.FullPath)" -o Packages' />
<!-- optional for project that has JavaScript content -->
<CreateItem Include="Packages\*\Content\Scripts\*">
<Output TaskParameter="Include" ItemName="NuGetJSFiles"/>
</CreateItem>
<Copy SourceFiles="#(NuGetJSFiles)" DestinationFolder="MainProj\Scripts\" OverwriteReadOnlyFiles="true" SkipUnchngedFiles="true" />
<Delete Files="MainProj\Scripts\.gitignore" />
<WriteLinesToFile File="MainProj\Scripts\.gitignore" Lines="%(NuGetJSFiles.Filename)%(NuGetJSFiles.Extension)" /
<Delete Files="#(PostNuGetFiles)" />
</Target>
In each project.csproj file
<Target Name="BeforeBuild">
<Error Condition="!Exists('..\Packages\')" Text="You must run > msbuild build.msbuild to download required NuGet
Packages" />
<!-- optional for project that has JavaScript content -->
<ReadLinesFromFile File="Scripts\.gitignore">
<Output TaskParameter="Lines" ItemName="ReqJSFiles" />
</ReadLinesFromFile>
<Message Text="#(ReqJSFiles)" />
<Error Condition="!Exists('Scripts\%(ReqJSFiles.Identity)')" Text="You must run > msbuild build.msbuild to download required NuGet JS Package - Scripts\%(ReqJSFiles.Identity)" />
</Target>
I realize the reality was different when this question has been originally posted and answered, but fortunately the answer changed a bit. It is now possible to use NuGet to download dependencies via MSBuild using a Pre-Build event. You don't need to put the packages folder in your code repository, all dependencies will be downloaded and/or updated on build. It may a workaround, but it looks decent enough. See the following blog post for details: http://blog.davidebbo.com/2011/03/using-nuget-without-committing-packages.html
AS of 09/20/13, there is something called "Nuget Restore". You actually don't have to check in package folder if you wish to do so. (Especially if you are using DVCS)
Check out this: Using NuGet Without commiting packages to source control
http://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages
This post has become very outdated. The answer is still NO, but the solution has changed.
As of NuGet 2.7+ you can enable automatic package restore without including the NuGet.exe file in your source (this is undesirable to say the least) and if you use any modern DVCS you can ignore the packages folder. If you need any special customizations you can create a nuget.config file in the solution root.
http://docs.nuget.org/docs/reference/package-restore
Also, with the new csproj format you can avoid the extra nuget.config files as well since that is integrated now. Please check out this post which explains that better:
Should .nuget folder be added to version control?