Skip to content

Commit

Permalink
Update P/Invoke sample to find MSVC compiler as part of build (#3749)
Browse files Browse the repository at this point in the history
* Update P/Invoke sample: metadata and CI build

* PR feedback

* readme -> README

* OSX -> macOS
  • Loading branch information
elinor-fung authored Sep 15, 2020
1 parent e3f2579 commit 3bbeef4
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
.NET Core PInvoke Marshaling Sample
================
---
languages:
- csharp
- cpp
products:
- dotnet-core
page_type: sample
name: "P/Invoke Marshaling Sample"
urlFragment: "pinvoke-marshal-arguments"
description: "A .NET application that demonstrates different ways to marshal arguments to native functions when using P/Invokes."
---

This project demonstrates different ways to marshal arguments to native function when using PInvokes. Documentation can be found here for [PInvokes](https://docs.microsoft.com/dotnet/standard/native-interop/pinvoke) and here for the [Type marshaling](https://docs.microsoft.com/dotnet/standard/native-interop/type-marshaling).
# .NET Core P/Invoke Marshaling Sample

Prerequisites
------------
This project demonstrates different ways to marshal arguments to native functions when using P/Invokes. Documentation can be found here for [P/Invokes](https://docs.microsoft.com/dotnet/standard/native-interop/pinvoke) and here for the [Type marshaling](https://docs.microsoft.com/dotnet/standard/native-interop/type-marshaling).

* .NET Core 3.0 (at least Preview 6) - [https://dot.net](https://github.com/dotnet/core-sdk#installers-and-binaries)
## Prerequisites

* [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download)

* C++ compiler
* Windows: `cl.exe`
* Linux/OSX: `g++`
* See [installation instructions](https://docs.microsoft.com/cpp/build/building-on-the-command-line#download-and-install-the-tools).
* Linux/macOS: `g++`

Build and Run
-------------
## Build and Run

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.
* 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 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 Windows, the sample is set up to use the bitness of `dotnet` to find the corresponding `cl.exe`

1) Navigate to the root directory and run `dotnet build`

Expand All @@ -33,7 +42,6 @@ Build and Run

Note: The way the sample is built is relatively complicated. The goal is that it's possible to build and run the sample with simple `dotnet run` with minimal requirements on pre-installed tools. Typically real-world projects which have both managed and native components will use different build systems for each; for example msbuild/dotnet for managed and CMake for native.

Visual Studio support
---------------------
## Visual Studio support

The `src\MarshalingSample.sln` 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\MarshalingSample.sln`. With that, the solution can be built. To run it set the start project to `MarshalingSample`.
The `src\MarshalingSample.sln` 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\MarshalingSample.sln`. With that, the solution can be built. To run it, set the start project to `MarshalingSample`.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>exe</OutputType>
<DefineConstants Condition="'$(OS)' == 'Windows_NT'">$(DefineConstants);WINDOWS</DefineConstants>

<!-- On most platforms, the .NET SDK uses UseAppHost=true by default. The exception is notarized
versions for macOS Catalina. This demo uses a custom command for 'dotnet run' (see build.proj)
which assumes that the the apphost is created, so we explicitly set UseAppHost=true here -->
<UseAppHost>true</UseAppHost>
</PropertyGroup>

<ItemGroup>
Expand All @@ -12,10 +17,13 @@
</ProjectReference>
</ItemGroup>

<Target Name="SetupForDemo" AfterTargets="Build">
<ItemGroup>
<Clean Include="$(BinRoot)/$(Configuration)/$(TargetName).*" />
</ItemGroup>

<Target Name="SetupForDemo" AfterTargets="Build">
<ItemGroup>
<AllOutputs Include="$(OutputPath)MarshalingSample.*" />
<AllOutputs Include="$(OutputPath)$(TargetName).*" />
</ItemGroup>

<!-- Copy the project outputs to the bin directory -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<PropertyGroup>
<NativeBinDir>$(BinRoot)/$(Configuration)</NativeBinDir>
<NativeOutputName>MarshalingSampleNative</NativeOutputName>

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

<!-- Properties for MSVCFindCompilerPaths -->
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('Windows'))">
<MSVCPlatform>$(NativePlatform)</MSVCPlatform>
</PropertyGroup>

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

<!-- This is to hide all the source files in VS to make the project cleaner,
but also to include them in the build so that when the source is modified the build will rerun the C++ compiler. -->
<ItemGroup>
Expand All @@ -12,19 +31,64 @@
<Visible>false</Visible>
</Content>
</ItemGroup>

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

<!-- Target to build the native project, the output goes directly to the bin directory -->
<Target Name="BuildNativeProject" AfterTargets="Build">
<!-- 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'))">.so</NativeOutputExtension>
<NativeOutputExtension Condition="$([MSBuild]::IsOsPlatform('OSX'))">.dylib</NativeOutputExtension>
<NativeOutputExtension Condition="$([MSBuild]::IsOsPlatform('Windows'))">.dll</NativeOutputExtension>
<NativeOutputFilePath>$(NativeBinDir)/$(NativeOutputName)$(NativeOutputExtension)</NativeOutputFilePath>

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

<MakeDir Directories="$(BinRoot)/$(Configuration)" />
<MakeDir Directories="$(NativeBinDir)" />
<MakeDir Directories="$(NativeObjDir)" />
</Target>

<Exec Command="g++ MarshalingSampleNative.cpp -Iinc -D LINUX -std=c++11 -o &quot;$(NativeBinDir)/MarshalingSampleNative.so&quot; -g -shared -fPIC -ldl -Wl,-rpath,'$ORIGIN',--disable-new-dtags" ConsoleToMsBuild="true" Condition="$([MSBuild]::IsOsPlatform('Linux'))" />
<Target Name="BuildNativeProjectUnix"
AfterTargets="Build"
DependsOnTargets="PrepareForNativeBuild"
Condition="$([MSBuild]::IsOsPlatform('Linux')) OR $([MSBuild]::IsOsPlatform('OSX'))">
<PropertyGroup>
<IncPaths>-Iinc</IncPaths>
<CompilerArgs>-g -shared -fPIC </CompilerArgs>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('Linux'))">
<PreprocessorDefines>-D LINUX</PreprocessorDefines>
<LinkArgs>-ldl -Wl,-rpath,'$ORIGIN',--disable-new-dtags</LinkArgs>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOsPlatform('OSX'))">
<PreprocessorDefines>-D OSX</PreprocessorDefines>
<LinkArgs>-ldl -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" />
</Target>

<Exec Command="g++ MarshalingSampleNative.cpp -Iinc -D OSX -std=c++11 -o &quot;$(NativeBinDir)/MarshalingSampleNative.dylib&quot; -g -shared -fPIC -ldl -Wl,-rpath,'@loader_path'" ConsoleToMsBuild="true" Condition="$([MSBuild]::IsOsPlatform('OSX'))" />
<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</IncPaths>
<CompilerArgs>/EHsc /Od /GS /sdl /Zi</CompilerArgs>
<PreprocessorDefines>/D WINDOWS</PreprocessorDefines>
<LibPaths>@(MSVCLibPaths-> '/LIBPATH:&quot;%(RootDir)%(Directory)%(Filename)&quot;', ' ')</LibPaths>
</PropertyGroup>

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

0 comments on commit 3bbeef4

Please sign in to comment.