Skip to content

Commit

Permalink
Update HostingWithHostFxr to 3.1 (#3909)
Browse files Browse the repository at this point in the history
* Update HostingWithHostFxr to 3.1

Also small changes to the readme

* Fix the VS solution to build

* Use compiler detection and don't rely on environment on Windows

Copied the native build targets from core/interop/pinvoke/marshalling sample.

* Fix build from VS - pick the bitness of the SDK being used

* Update readme to match the latest requirements and behavior

* Fix location of inc dir on Linux

* PR feedback and cleanup
  • Loading branch information
vitek-karas authored Oct 5, 2020
1 parent 067de6f commit c232a34
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 30 deletions.
17 changes: 8 additions & 9 deletions core/hosting/HostWithHostFxr/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# .NET Core Hosting Sample

This project demonstrates a way for a native process to host .NET Core using the `nethost` and `hostfxr` libraries. Documentation on the `nethost` and `hostfxr` APIs can be found [here](https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/native-hosting.md).
This project demonstrates a way for a native process to host .NET Core using the `nethost` and `hostfxr` libraries. Documentation on the `nethost` and `hostfxr` APIs can be found [here](https://github.com/dotnet/runtime/blob/master/docs/design/features/native-hosting.md).

## Key Features

Expand All @@ -9,13 +9,13 @@ Demonstrates how to locate and initialize .NET Core 3.0 from a non-.NET Core pro
The `nethost` header and library are part of the `Microsoft.NETCore.DotNetAppHost` package and are also installed as a runtime pack by the .NET Core SDK. The library should be deployed alongside the host. This sample uses the files installed with the .NET Core SDK.
*Note: The `Microsoft.NETCore.DotNetAppHost` package is a [metapackage](https://docs.microsoft.com/dotnet/core/packages#metapackages) that doesn't actually contain the files. It only references RID-specific packages that contain the files. For example, the package with the actual files for `linux-x64` is `runtime.linux-x64.Microsoft.NETCore.DotNetAppHost`.*

The `coreclr_delegates.h` and `hostfxr.h` files are copied from the [core-setup](https://github.com/dotnet/core-setup) repo.
The `coreclr_delegates.h` and `hostfxr.h` files are copied from the [dotnet/runtime](https://github.com/dotnet/runtime) repo - [coreclr_delegates.h](https://github.com/dotnet/runtime/blob/master/src/installer/corehost/cli/coreclr_delegates.h) and [hostfxr.h](https://github.com/dotnet/runtime/blob/master/src/installer/corehost/cli/hostfxr.h).

Additional comments are contained in source and project files.

## Prerequisites

* [.NET Core 3.0 SDK](https://dotnet.microsoft.com/download) or a later version
* [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) or a later version

* C++ compiler
* Windows: `cl.exe`
Expand All @@ -25,10 +25,9 @@ Additional comments are contained in source and project files.

1. In order to build and run, all prerequisites must be installed. The following are also required:

* The C++ compiler (`cl.exe` or `g++`) must be on the path.
* On Windows, a [Developer Command Prompt for Visual Studio](https://docs.microsoft.com/cpp/build/building-on-the-command-line#developer_command_prompt_shortcuts) should be used.
* The C++ compiler (`cl.exe` or `g++`) and `dotnet` must be the same bitness (32-bit or 64-bit).
* On Windows, the default developer command prompt for VS uses the 32-bit compilers, but `dotnet` is typically 64-bit by default. Make sure to select the "x64 Native Tools Command Prompt for VS 2019" (or 2017).
* On Linux/macOS, the C++ compiler (`g++`) must be on the path.
* The C++ compiler (`cl.exe` or `g++`) and `dotnet` must be the same bitness (32-bit versus 64-bit).
* On Windows, the sample is set up to use the bitness of `dotnet` to find the corresponding `cl.exe`

1. Navigate to the root directory.

Expand All @@ -41,7 +40,7 @@ Additional comments are contained in source and project files.

The expected output will come from the `DotNetLib` class library and include the arguments passed to the managed library from the host:

```
```console
Hello, world! from Lib [count: 1]
-- message: from host!
-- number: 0
Expand All @@ -60,5 +59,5 @@ Note: The way the sample is built is relatively complicated. The goal is that it

## Visual Studio support

The `src\HostWithHostFxr.sln` solution file can be used to open the sample in Visual Studio 2019. In order to be able to build from Visual Studio, though, it has to be started from the correct developer environment. From the developer environment console, start it with `devenv src\HostWithHostFxr.sln`. With that, the solution can be built. To run it, set the startup project to `build/NativeHost`.
The `src\HostWithHostFxr.sln` solution file can be used to open the sample in Visual Studio 2019. To run the sample, set the startup project to `build/NativeHost`.
Note that with mixed mode debugging (that is, a debugger that can see both native and managed code at the same time), there's a known limitation where no breakpoints will be hit before the runtime starts. So it is not possible to debug the parts of the sample before (and including) the call to `load_assembly_and_get_function_pointer` like that. To debug those, start the process from a native-only debugger.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>

Expand Down
2 changes: 0 additions & 2 deletions core/hosting/HostWithHostFxr/src/HostWithHostFxr.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Debug|Any CPU.ActiveCfg = Debug|Win32
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Debug|x64.ActiveCfg = Debug|x64
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Debug|x64.Build.0 = Debug|x64
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Debug|x86.ActiveCfg = Debug|Win32
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Debug|x86.Build.0 = Debug|Win32
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Release|Any CPU.ActiveCfg = Release|Win32
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Release|x64.ActiveCfg = Release|x64
{B99BC289-621D-4DB6-A964-2D869F8E0DD3}.Release|x64.Build.0 = Release|x64
Expand Down
100 changes: 85 additions & 15 deletions core/hosting/HostWithHostFxr/src/NativeHost/NativeHost.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand All @@ -19,33 +19,103 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
<Content Include="inc.vs/*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>

<!-- Target to build the native project -->
<Target Name="BuildNativeProject"
AfterTargets="Build">
<PropertyGroup>
<NativeBinDir>$(BinRoot)/$(Configuration)</NativeBinDir>
<NativeOutputName>nativehost</NativeOutputName>

This comment has been minimized.

Copy link
@wegylexy

wegylexy Jan 11, 2021

Contributor

When nativehost.exe is copied, attempting to run it causes Windows Defender to detect it as Trojan:Script/Wacatac.B!ml and delete it.
May need to change the native output name to e.g. dotnetlibhost as it only loads DotNetLib.runtimeconfig.json.


<NativePlatform>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)</NativePlatform>
<NativeObjDir>$(MSBuildThisFileDirectory)obj/$(Configuration)/$(NativePlatform)/</NativeObjDir>
<NativeHostDirectory>$(MSBuildThisFileDirectory)</NativeHostDirectory>
</PropertyGroup>

<!-- Properties for MSVCFindCompilerPaths -->
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('Windows'))">
<MSVCPlatform>x64</MSVCPlatform>
<MSVCPlatform Condition="$(NETCoreSDKRuntimeIdentifier.Contains('x86'))">x86</MSVCPlatform>
</PropertyGroup>

<ItemGroup>
<NativeSource Include="nativehost.cpp" />
<Clean Include="$(NativeBinDir)/$(NativeOutputName).*" />
<Clean Include="$(NativeObjDir)/*.*" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="CompilerPaths"
Version="[1.0.2, )"
Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
</ItemGroup>

<!-- Targets to build the native project. The output goes directly to the bin directory -->
<Target Name="PrepareForNativeBuild">
<PropertyGroup>
<NativeBinDir>$(BinRoot)/$(Configuration)</NativeBinDir>
<NativeOutputExtension Condition="$([MSBuild]::IsOsPlatform('Linux'))"></NativeOutputExtension>
<NativeOutputExtension Condition="$([MSBuild]::IsOsPlatform('OSX'))"></NativeOutputExtension>
<NativeOutputExtension Condition="$([MSBuild]::IsOsPlatform('Windows'))">.exe</NativeOutputExtension>
<NativeOutputFilePath>$(NativeBinDir)/$(NativeOutputName)$(NativeOutputExtension)</NativeOutputFilePath>

<SourceFiles>@(NativeSource-> '&quot;%(RootDir)%(Directory)%(Filename)%(Extension)&quot;', ' ')</SourceFiles>

<NetHostDir>$(NetCoreTargetingPackRoot)/Microsoft.NETCore.App.Host.$(NETCoreSdkRuntimeIdentifier)/$(BundledNETCoreAppPackageVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native</NetHostDir>

<NetHostName Condition="$([MSBuild]::IsOsPlatform('Windows'))">nethost.dll</NetHostName>
<NetHostName Condition="$([MSBuild]::IsOsPlatform('Linux'))">libnethost.so</NetHostName>
<NetHostName Condition="$([MSBuild]::IsOsPlatform('OSX'))">libnethost.dylib</NetHostName>
</PropertyGroup>

<Exec Command="g++ nativehost.cpp -I&quot;$(NetHostDir)&quot; -Iinc -D LINUX -std=c++11 -o &quot;$(NativeBinDir)/nativehost&quot; -ldl -lnethost -L&quot;$(NetHostDir)&quot; -g -Wl,-rpath,'$ORIGIN',--disable-new-dtags"
ConsoleToMsBuild="true"
Condition="$([MSBuild]::IsOsPlatform('Linux'))" />
<MakeDir Directories="$(NativeBinDir)" />
<MakeDir Directories="$(NativeObjDir)" />
</Target>

<Target Name="BuildNativeProjectUnix"
AfterTargets="Build"
DependsOnTargets="PrepareForNativeBuild"
Condition="$([MSBuild]::IsOsPlatform('Linux')) OR $([MSBuild]::IsOsPlatform('OSX'))">
<PropertyGroup>
<IncPaths>-I$(NativeHostDirectory)inc -I&quot;$(NetHostDir)&quot;</IncPaths>
<CompilerArgs>-g</CompilerArgs>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('Linux'))">
<PreprocessorDefines>-D LINUX</PreprocessorDefines>
<LinkArgs>-ldl -lnethost -L&quot;$(NetHostDir)&quot; -Wl,-rpath,'$ORIGIN',--disable-new-dtags</LinkArgs>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('OSX'))">
<PreprocessorDefines>-D OSX</PreprocessorDefines>
<LinkArgs>-ldl -lnethost -L&quot;$(NetHostDir)&quot; -Wl,-rpath,'@loader_path'</LinkArgs>
</PropertyGroup>

<Exec Command="g++ $(SourceFiles) $(IncPaths) $(PreprocessorDefines) -std=c++11 -o &quot;$(NativeOutputFilePath)&quot; $(CompilerArgs) $(LinkArgs)"
WorkingDirectory="$(NativeObjDir)"
ConsoleToMsBuild="true" />

<Exec Command="g++ nativehost.cpp -I&quot;$(NetHostDir)&quot; -Iinc -D OSX -std=c++11 -o &quot;$(NativeBinDir)/nativehost&quot; -ldl -lnethost -L&quot;$(NetHostDir)&quot; -g -Wl,-rpath,'@loader_path'"
ConsoleToMsBuild="true"
Condition="$([MSBuild]::IsOsPlatform('OSX'))" />
<Copy SourceFiles="$(NetHostDir)/$(NetHostName)"
DestinationFolder="$(NativeBinDir)"
SkipUnchangedFiles="True" />
</Target>

<Target Name="BuildNativeProjectWindows"
AfterTargets="Build"
DependsOnTargets="PrepareForNativeBuild;MSVCFindCompilerPaths"
Condition="$([MSBuild]::IsOsPlatform('Windows'))">
<PropertyGroup>
<IncPaths>@(MSVCIncludePaths-> '/I &quot;%(RootDir)%(Directory)%(Filename)&quot;', ' ')</IncPaths>
<IncPaths>$(IncPaths) /I inc /I &quot;$(NetHostDir)&quot;</IncPaths>
<CompilerArgs>/EHsc /Od /GS /sdl /Zi</CompilerArgs>
<PreprocessorDefines>/D WINDOWS</PreprocessorDefines>
<LibPaths>@(MSVCLibPaths-> '/LIBPATH:&quot;%(RootDir)%(Directory)%(Filename)&quot;', ' ')</LibPaths>
<LibPaths>$(LibPaths) &quot;$(NetHostDir)\nethost.lib&quot;</LibPaths>
</PropertyGroup>

<Exec Command="cl.exe nativehost.cpp /I &quot;$(NetHostDir)&quot; /I inc /D WINDOWS /EHsc /Od /GS /sdl /Zi /Fo&quot;$(NativeBinDir)\\&quot; /Fd&quot;$(NativeBinDir)\nativehost.pdb&quot; /link &quot;$(NetHostDir)\nethost.lib&quot; /out:&quot;$(NativeBinDir)\nativehost.exe&quot;"
ConsoleToMsBuild="true"
Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
<Exec Command="&quot;$(MSVCCompilerPath)&quot; $(SourceFiles) $(IncPaths) $(PreprocessorDefines) $(CompilerArgs) /link $(LibPaths) /out:&quot;$(NativeOutputFilePath)&quot;"
WorkingDirectory="$(NativeObjDir)"
ConsoleToMsBuild="true" />

<!-- Copy the nethost library to the demo directory -->
<Copy SourceFiles="$(NetHostDir)/$(NetHostName)"
DestinationFolder="$(NativeBinDir)"
SkipUnchangedFiles="True" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WINDOWS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>inc;inc.vs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
Expand All @@ -104,8 +105,9 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WINDOWS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
Expand Down Expand Up @@ -151,6 +153,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="inc.vs\nethost.h" />
<ClInclude Include="inc\coreclr_delegates.h" />
<ClInclude Include="inc\hostfxr.h" />
</ItemGroup>
Expand All @@ -160,4 +163,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
<ClInclude Include="inc\hostfxr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="inc.vs\nethost.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="nativehost.cpp">
Expand Down
99 changes: 99 additions & 0 deletions core/hosting/HostWithHostFxr/src/NativeHost/inc.vs/nethost.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#ifndef __NETHOST_H__
#define __NETHOST_H__

#include <stddef.h>

#ifdef _WIN32
#ifdef NETHOST_EXPORT
#define NETHOST_API __declspec(dllexport)
#else
// Consuming the nethost as a static library
// Shouldn't export attempt to dllimport.
#ifdef NETHOST_USE_AS_STATIC
#define NETHOST_API
#else
#define NETHOST_API __declspec(dllimport)
#endif
#endif

#define NETHOST_CALLTYPE __stdcall
#ifdef _WCHAR_T_DEFINED
typedef wchar_t char_t;
#else
typedef unsigned short char_t;
#endif
#else
#ifdef NETHOST_EXPORT
#define NETHOST_API __attribute__((__visibility__("default")))
#else
#define NETHOST_API
#endif

#define NETHOST_CALLTYPE
typedef char char_t;
#endif

#ifdef __cplusplus
extern "C" {
#endif

// Parameters for get_hostfxr_path
//
// Fields:
// size
// Size of the struct. This is used for versioning.
//
// assembly_path
// Path to the compenent's assembly.
// If specified, hostfxr is located as if the assembly_path is the apphost
//
// dotnet_root
// Path to directory containing the dotnet executable.
// If specified, hostfxr is located as if an application is started using
// 'dotnet app.dll', which means it will be searched for under the dotnet_root
// path and the assembly_path is ignored.
//
struct get_hostfxr_parameters {
size_t size;
const char_t *assembly_path;
const char_t *dotnet_root;
};

//
// Get the path to the hostfxr library
//
// Parameters:
// buffer
// Buffer that will be populated with the hostfxr path, including a null terminator.
//
// buffer_size
// [in] Size of buffer in char_t units.
// [out] Size of buffer used in char_t units. If the input value is too small
// or buffer is nullptr, this is populated with the minimum required size
// in char_t units for a buffer to hold the hostfxr path
//
// get_hostfxr_parameters
// Optional. Parameters that modify the behaviour for locating the hostfxr library.
// If nullptr, hostfxr is located using the enviroment variable or global registration
//
// Return value:
// 0 on success, otherwise failure
// 0x80008098 - buffer is too small (HostApiBufferTooSmall)
//
// Remarks:
// The full search for the hostfxr library is done on every call. To minimize the need
// to call this function multiple times, pass a large buffer (e.g. PATH_MAX).
//
NETHOST_API int NETHOST_CALLTYPE get_hostfxr_path(
char_t * buffer,
size_t * buffer_size,
const struct get_hostfxr_parameters *parameters);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // __NETHOST_H__

0 comments on commit c232a34

Please sign in to comment.