Reputation: 910
I have several legacy components written in C/C++ and would like to wrap them into the Nuget package and use this package from C# code. What is the best way to actually wrap C++ code in nuget package? I had a look on CoApp solution, but it seems like unsupported now (stable release offline).
Upvotes: 1
Views: 2863
Reputation: 8830
I can answer the how do you package c++ as a nuget package from Visual Studio 2017/2019.
This is what I used to package up a zlib C++ library as a nuget package in visual studio. I make extensive use of T4 templates built into Visual Studio to generate the files we need.
This asumes you wish to package x86/release/debug and x64/release/debug in the same package. You need to build all the targets then build the new project that we create here to generate the nuget packages.
When you include the resultant nuget package in your own code it will automatically use includes and lib, its zero config. You will need to change these parts prop and target file to match your config for this to happen.
This information was quite hard to workout and put together as most nuget packaing instructions cover c# or C++ Unix. I had to work out the secret sauce.
Create new project for a basic c# app in visual studio.
You need to creat and add the files below.
Add the Build Events
Patch up extenal references to things like nuget.exe.
put this in file named: thirdparty.ttinc
<#@ assembly name="System"
#><#@ assembly name="System.Core"
#><#@ import namespace="System.IO"
#><#@ import namespace="System.Linq"
#><#@ import namespace="System.Text"
#><#@ import namespace="System.Configuration"
#><#@ import namespace="System.Collections.Generic"
#><#
string DirRoot = @"c:\work\thirdparty\"; // Git source code package installed at.
string NugetPrefix = "thirdparty"; // base name for 3rd party packages.
#>
put this in file named: _NugetVersionInclude.ttinc
<#@ include file= "thirdparty.ttinc" #><#
// Configuration
// increment this number for each internal release
string NugetInternalVersion = @"1.0.2"; // Internal version number.
// configured once for each new thirdparty set of code
string NugetName = @"zlib"; // Nuget name for this package.
string NugetExternalVersion = @"1_2_11"; // External version number as used by the original author.
// you probably dont need to change below.
string NugetShortname = NugetPrefix + "-" + NugetName;
string NugetRootname = NugetShortname + "_" + NugetExternalVersion;
string NugetFullname = NugetRootname + "." + NugetInternalVersion;
string NugetDescription = NugetPrefix + " " + NugetName + " " + NugetExternalVersion;
string NugetOutDir = "nuget\\";
string DirSolution = Environment.GetEnvironmentVariable("SOLUTIONDIR");
#>
Add this to PreBuildEvent
echo on
start NuGetPackagePack.bat
exit
Add this to PostBuildEvent
echo on
start _UpdateTemplate.bat . "thirdparty-zlib_nuspec.tt" "thirdparty-xlw_nuspec.nuspec"
start _UpdateTemplate.bat . "thirdparty-zlib_props.tt" "thirdparty-xlw_props.props"
start _UpdateTemplate.bat . "thirdparty-zlib_targets.tt" "thirdparty-xlw_targets.targets"
start _UpdateTemplate.bat . "NugetPackagePack.tt" "NugetPackagePack.bat"
start _UpdateTemplate.bat . "NugetPackagePush.tt" "NugetPackagePush.bat"
exit 0
put this in file named: _UpdateTemplate.bat
echo on
del %3
set SOLUTIONDIR=%1
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\TextTransform.exe" -out %3 %2
rem uncomment pause to see output to help debug
rem pause
exit 0
put this in file named: thirdparty-zlib_nuspec.tt
<#@ template debug="true" hostspecific="true" language="C#" #><#@
include file="_NugetVersionInclude.ttinc" #><#@
output extension=".nuspec" #><?xml version="1.0"?>
<package >
<metadata>
<id><#= NugetRootname #></id>
<version><#= NugetInternalVersion #></version>
<description> <#= NugetDescription #> </description>
<authors>Original Authors and Anthony Lambert</authors>
<tags>Native, native</tags>
</metadata>
<files>
<file src="..\nuget\lib\x64\Debug\*" target="lib\native\x64\Debug" />
<file src="..\nuget\lib\x64\Release\*" target="lib\native\x64\Release" />
<file src="..\nuget\lib\x86\Debug\*" target="lib\native\x86\Debug" />
<file src="..\nuget\lib\x86\Release\*" target="lib\native\x86\Release" />
<file src="..\nuget\lib\x86\Debug\*" target="lib\native\win32\Debug" />
<file src="..\nuget\lib\x86\Release\*" target="lib\native\win32\Release" />
<file src="..\..\..\..\zlib.h" target="build\native\include" />
<file src="..\..\..\..\zconf.h" target="build\native\include" />
<file src="..\..\..\..\doc\*" target="doc" />
<file src="README.md" target="" />
<file src="<#= NugetShortname #>_props.props" target="build\native\\<#= NugetRootname #>.props" />
<file src="<#= NugetShortname #>_targets.targets" target="build\native\\<#= NugetRootname #>.targets" />
</files>
</package>
put this in file named: thirdparty-zlib_props.tt
<#@ template debug="true" hostspecific="true" language="C#" #><#@
include file="_NugetVersionInclude.ttinc" #><#@
output extension=".props" #><?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
<!-- lambea 2020-06-24 - the mdd and md sub dirs are not used at present. Not sure any of this is used, picked up from example code. -->
<PropertyGroup>
<LibraryType Condition="'$(Configuration)'=='Debug'">mdd</LibraryType>
<LibraryType Condition="'$(Configuration)'=='Release'">md</LibraryType>
</PropertyGroup>
<ItemGroup>
<FilamentLibs Include="$(MSBuildThisFileDirectory)\lib\native\$(PlatformTarget)\$(Configuration)\*.lib" />
</ItemGroup>
<PropertyGroup>
<!-- Expland the items to a property -->
<FilamentLibraries>@(FilamentLibs)</FilamentLibraries>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile> <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(FilamentLibraries);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>
put this in file named: thirdparty-zlib_targets.tt
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0" >
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)lib\$(Configuration)\$(PlatformName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>zlibstat.lib; zlibwapi.lib; %(AdditionalDependencies) </AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>
put this in file named: NugetPackagePack.tt
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ include file="_NugetVersionInclude.ttinc" #>
<#@ output extension=".bat" #>
_tools\nuget-4.6.2\nuget.exe pack <#= NugetShortname #>_nuspec.nuspec -OutputDirectory <#= NugetOutDir #>
echo "run NugetPackagePush.bat to put on nuget server."
pause
exit
put this in file named: NugetPackagePush.tt
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ include file="_NugetVersionInclude.ttinc" #>
<#@ output extension=".bat" #>
_tools\nuget-4.6.2\nuget.exe pack <#= NugetShortname #>_nuspec.nuspec -OutputDirectory <#= NugetOutDir #>
echo "run NugetPackagePush.bat to put on nuget server."
pause
exit
Calling those c lib functions is probably answered else where. Look for pinvoke as a starting point.
Upvotes: 3