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.
Related
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.
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.
I am trying to build a NuGet package that includes native DLLs which are to be placed in the output folder when a project uses the package. I have tried to use the several suggestions from this question, but I am always running in the same problem.
My current NuGet package layout is like this:
\build
packageId.targets
file1.dll
file2.dll
\lib
\netstandard1.4
assembly.dll
The contents of packageId.targets is:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)\*.dll"/>
<None Include="#(NativeLibs)" Link="$(RecursiveDir)$(Filename)$(Extension)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
This should, according to the answers of the other questions, lead to my DLLs being placed in the bin\Debug directory of the project using the package. However, they are not. Instead, they are placed in bin\Debug\packages\packageId\build.
Now I have experimented a lot, and I noticed more and more strange behavior which I cannot make any sense of:
If I move the DLLs to the root of the NuGet package (like one answer suggests) and change the .targets file accordingly, they are not copied at all. There also is no error message.
If I change the .targets file to only reference file1.dll in both Include= and Link=, both files get copied anyway.
So I wondered if some policy just ignores the .targets file and copies whatever is in build to that path in the output folder, but when I remove the .targets file, the DLL files will not get copied anymore.
Now I understand even less what's happening.
What do I need to change to get the DLLs copied right into bin\Debug?
The new way to handle runtime-specific assents in NuGet is to use the runtimes folder to place native assets:
\lib
\netstandard2.0
ManagedWrapper.dll
\runtimes
\win-x86
\native
NativeThing.dll
\win-x64
\native
NativeThing.dll
\linux-x64
\native
libNativeThing.so
\osx-x64
\native
libNativeThing.dylib
If the package is consumed from a .NET Framework project, you may need to add a reference to the Microsoft.NETCore.Platforms package wich provides the runtime graph (runtimes.json) for NuGet to provide proper RID mappings if you don't use base RIDs (e.g. win10-x64 falls back to win-x64 resources).
I want to add a custom install script for my VS 2017 NuGet package.
Problem is, support for the install.ps1/uninstall.ps1 mechanism was removed. init.ps1 still works, but it would run every time the solution is opened, and that is unacceptable (it's a potentially lengthy process).
I read it's possible to define custom msbuild targets in the build dir, but I cannot get that to work because it requires manipulating the .nuspec file to include the files, and I can't see how to do that in VS 2017 with just the .csproj file.
but I cannot get that to work because it requires manipulating the .nuspec file to include the files
You can use the NuGet Package Explorer to add custom msbuild .targets in the build directory without manipulating the .nuspec file:
I can't see how to do that in VS 2017 with just the .csproj file.
As you know, Powershell script support was modified to no longer execute install and uninstall scripts, so we could not custom install scripts that is called when installing the nuget package, otherwise, we need to overwrite the NuGet API in visual Studio: IVsPackageInstaller interface(Not recommended).
So as a workaround, we could use define custom msbuild .targets file to achieve what you want achieve by the custom install script after install the nuget package. For example, you want custom install nuget script to change the default dll output, you can use a .target file with copy task to achieve it, you can create a file build\MyNuGet.targets containing:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<MySourceFiles Include="$(ProjectDir)MyFolder\**" />
</ItemGroup>
<Target Name="MyNuGetCustomTarget" AfterTargets="Build">
<Copy SourceFiles="#(MySourceFiles)" DestinationFolder="$(OutDir)" />
</Target>
</Project>
I have a .sln package named MySolution. In that Package I have some dlls, like:
MySolution.sln
\one.dll
\second.dll
\another.dll
I want to install only specific dll to my another Project, so they will add as reference to my Project. I m trying to install like
PM> Install-Package MySolution
In that way all dlls added to my Project, but I only want some of dlls like one.dll and second.dll thats it.
Is there any way to do this?
Your options are:
Add the .dlls you do not want as assembly references as Content files.
<file src="lib\Net40\another.dll" target="content" />
This will add the .dll as a file to the project.
Add the .dlls you do not want as assembly references as Tools files.
<file src="lib\Net40\another.dll" target="tools" />
The tools directory is one of the sub directories where your package is extracted to.
Then use PowerShell to put the files into the location you need them in the project.
Or alternatively you could write a custom MSBuild target file which references the files from the tools directory. Your MSBuild target file is a just an MSBuild file where you can define properties and files just like a standard MSBuild project file. So you can reference the .dlls in the tools directory and have them copied to the output directory.