Skip to content

Commit

Permalink
feat: Create a Build task for DsCOM (#102)
Browse files Browse the repository at this point in the history
* feat: Created new project: dscom.build

The project shall be used to create an MsBuild target for
the automated export of Type Libraries.

* feat: [DI/Tesing] Separated interface for testing purposes

* feat: [Logging] Added verbose/detailed logging for TLB export

* feat: [Conversion] Added Default implementation of context

* feat: [Check] Added check for run-time build-parameters

* feat: [Implementation] Added task for type library export

* feat: [DevDependency] Added stubs for automatic build tasks

* feat: [Tracability] Added source link

* fix: Renamed targets file

* fix: Renamed task for better using within targets files

* feat: Added basic property definitions

* feat: First draft of targets file. Hook targets are still missing

* fix: Applied dotnet format to files.

* fix: Added copyrights to props and targets

* feat: Added documentation for task

* fix: Documentation of context implementation

* fix: Something is always wrong.

* fix: Added documentation for FS checks

* fix: applied documentation

* fix: Fixed compilation issues

* fix: Setting up assembly load context

* fix: Improvements on errorhandling and small refactorings

* fix: removed todo - not necessary

for details refer to https://docs.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items?view=vs-2019#comreference

* fix: Made the warning a notice

* Fix: Added some more descriptive hints

* fix: Moved variables to targets

* fix: Reapplied renamed variables

* fix: Removed trailing backslash

* feat: Target Package is renamed to dSPACE.Runtime.InteropServices.BuildTasks

* feat: The package has been renamed

* fix: Weird thing: If ITask is added, the base type will be of TlbExport

The TlbExport Task cannot be loaded. When loading the assembly into a reflector (ILSpy, dotPeek), it is shown, that the assembly does not provide any base types - not even object.
When added ITask as interface, ITask will be the only base type.

THIS IS ACTUALLY PRETTY WEIRD.

* fix: Warning removed

* FIx: Renamed attribute AssemblyName to AssemblyFile

Unless the assembly is installed globally within the context of
MsBuild, the TlbExportTask cannot be loaded using AssemblyName,
but must be loaded using AssemblyFile.

* Fix: MsBuild will only add a string. Converted parameter type

The Guid cannot be added to a task. Convert string to Guid
within the MsBuild task.

* Feat: Added new Guard for Windows Systems Only

The task shall only be executed on Windows based Systems

* FEAT: Made Build Task .NET 4.8 compliant

* Feat: Added items to BuildContext interface for improval of unit tests

* Feat: Initial revision of unit tests

* feat: Use References automatically

If a project has references, include them automatically
into the list of references Assemblies.

* chore: Fix Compiler Warning IDE0250

* fix: Do not treat ASMPath as directory

The ASMPath properties refers to concrete
file paths and should not be treated as a
directory.

* qa: Using moq for mocks in MsBuild test

* chore: Removed Warning IDE0031

* chore: Removed CA1854 Warning

* chore: Removed CA1852 Warning

If .NET 7 SDK is installed, due to "LatestMajor", another FxCop Ruleset
will be activated.
This will cause more warnings on
developer machines.

* refactor: Code cleanup (#95)

* chore: Added me as an author

* chore: Added an extra warning

Added an extra warning to improve builds

* qa: Finished implementation of unit tests

* fix: Treating RefPath as directory

* qa: Finished Unit tests for build tasks

* deploy: Bundle dependent assembly into nuget package

* fix: Override Automatic assembly loading

If assembly is next to task assembly, load it from there,
maybe remove it from there afterward.

* feat: Bundle tool into nuget package

* fix: Task can be used for AnyCPU as well

* chore: Ignore packages folder. Prepares Acceptance test

* fix: Erroneous Cast due to missing nullable

* chore: Fix CA1852

* fix: CS0628 fixed

* fix: Mark Task as NetStandard 2.0 compliant

* feat: Package tool within package to target x86 or Netstandard2.0

* feat: Using task and tools to call tlbexport

* fix: Added check if net6.0-windows is used

* chore: Added a warning if TLB was not found

* fix: Warning is shown, if tools are used

* fix: NuGet produced was not netstandard compliant

* fix: Include netstandard targets in package

* feat: If TLB is missing, Warning can be promoted to error

* feat: Usage of Tools can be enforced

* chore: Clarify enforced tool usage

* qa: (Ab)use Contracts for Acceptance test

* qa: (Ab-)using 32bit example as acceptance test

* qa: Added acceptance test that are automatically executed on pull
request

* deploy: Added deployment steps for build tasks

* ci: added Unit testing step

* ci: Run separate code style check

* qa: Try to use relative path for acceptance test start

* doc: Add ReadMe

The documentation is added to the repository and will be added to
the resulting NuGet package.

* docs: Added first draft of documentation

The build task documentation is added preliminarily

* qa: Using response file for acceptance test

* deploy: Added forgotten RuntimeIdentifier

Restore did not include RID property

* qa: Use a more decent packing

* qa: Fix acceptance test for net4.8

Dotnet SDK has issues when building implicit usings for .NET 4.8
with Implicit using System.Net.Http.

* qa: Acceptance test: Added clean-up step

* qa: Added a step for the acceptance test to restore before add.

* ci: Renamed jobs

* qa: Add matrix as executor

* qa: Acceptance test: Added explicit restore and build

* qa: Fixed build for comtestdotnet / 32-bit

* qa: Removed force of using TLB

* qa: Clean step is superflouos due to matrix

* qa: DsCOM enforce usage of dscom executable

* fix: Always enforce to use tool.

MsBuild fails to host dSPACE.Runtime.InteropServices for TLB Export

* doc: Added sequence diagram for TLB Export

* docs: Fixed return for "result true" alt

* chore: Improvement for packing

Use the dependency property instead of AfterTargets declaration.

* docs: Finished documentation

The dscom build documentation is in a reviewable format.
Should do as a first draft.

* docs: Updated documentation

As requested by @marklechtermann the
user documentation has been moved
to the common section.

* docs: Dropped unmaintained docs

As requested by @marklechtermann and @SOsterbrink the documentation
folder with the unmaintained
documentation was removed while the
documentation of the build task
was moved to the src folder

* chore: Removed doubled entries

Entries that are part of Directory.Build.props
are removed from csproj.
This was requested by @SOsterbrink in #102.

* docs: Corrected links, one sentence per line

The links have been updated to match the new location.
The document now contains one sentence per line as requested by @SOsterbrink

Co-authored-by: Carsten Igel <CIgel@dspace.de>
Co-authored-by: Mark Lechtermann <mark.lechtermann@gmail.com>
  • Loading branch information
3 people authored Dec 15, 2022
1 parent 975ec94 commit 087e6fc
Show file tree
Hide file tree
Showing 33 changed files with 2,963 additions and 15 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/acceptance-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Acceptance Test

on:
workflow_dispatch:
pull_request:


jobs:
acceptance-test-msbuild:
runs-on: windows-2022
strategy:
matrix:
test_suite:
- name: OutProc
path: outproc
- name: 32 Bit
path: 32bit

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.300

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build -c Release

- name: Run ${{ matrix.test_suite.Name }} Acceptance test
run: .\msbuild-acceptance-test.cmd
working-directory: .\examples\${{ matrix.test_suite.path }}\scripts
continue-on-error: false
9 changes: 3 additions & 6 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ jobs:
- name: Build
run: dotnet build -c Release

- name: Check code format (editorconfig)
run: dotnet format --verify-no-changes

- name: Test (Release)
run: dotnet test -c Release --no-build --verbosity normal

- name: Nuget pack library
run: dotnet pack -c Release src/dscom/dscom.csproj

- name: Nuget pack tool
run: dotnet pack -c Release src/dscom.client/dscom.client.csproj

- name: Nuget pack build tools
run: dotnet pack -c Release src/dscom.build/dscom.build.csproj
26 changes: 26 additions & 0 deletions .github/workflows/code-style.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Check code style

on:
workflow_dispatch:
pull_request:

jobs:
check-code-style:
runs-on: windows-2022

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.300

- name: Restore dependencies
run: dotnet restore

- name: Check code format (editorconfig)
run: dotnet format --verify-no-changes
continue-on-error: false
7 changes: 7 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ jobs:
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET }} --source https://api.nuget.org/v3/index.json
working-directory: src/dscom.client/bin/Release

- name: Nuget pack build tools
run: dotnet pack -c Release src/dscom.build/dscom.build.csproj

- name: Nuget push build tools
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET }} --source https://api.nuget.org/v3/index.json
working-directory: src/dscom.build/bin/Release

- name: Publish 32Bit binary
run: dotnet publish .\src\dscom.client\dscom.client.csproj --no-self-contained -c Release -r win-x86 -f net6.0 /p:PublishSingleFile=true; copy src\dscom.client\bin\Release\net6.0\win-x86\publish\dscom.exe src\dscom.client\bin\Release\net6.0\win-x86\publish\dscom32.exe

Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/unit-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Run Unit Tests

on:
workflow_dispatch:
pull_request:

jobs:
unit-test:
runs-on: windows-2022

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.300

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build -c Release

- name: Unit test
run: dotnet test --no-build -c Release
continue-on-error: false
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ Release/
test.results/
.tmp/
_temporary.cs
.publish/
.publish/
_packages
*.binlog
94 changes: 94 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ From the Microsoft documentation:
One main goal is to make `dscom` behave like `tlbexp.exe`.

_Happy IUnknowing and IDispatching ;-)_

- [dSPACE COM tools](#dspace-com-tools)
- [Command Line Client](#command-line-client)
- [Installation](#installation)
Expand All @@ -33,6 +34,15 @@ _Happy IUnknowing and IDispatching ;-)_
- [Migration notes (mscorelib vs System.Private.CoreLib)](#migration-notes-mscorelib-vs-systemprivatecorelib)
- [Why can I load a .NET Framework library into a .NET application?](#why-can-i-load-a-net-framework-library-into-a-net-application)
- [Limitations](#limitations)
- [Build Tasks](#build-tasks)
- [Preface](#preface)
- [Build task usage](#build-task-usage)
- [Using the native build task](#using-the-native-build-task)
- [Using the CLI based task](#using-the-cli-based-task)
- [Enforcing the usage of the CLI](#enforcing-the-usage-of-the-cli)
- [Enforcing to stop the build, if an error occurs](#enforcing-to-stop-the-build-if-an-error-occurs)
- [Parameters](#parameters)

## Command Line Client

The command-line interface (CLI) tool `dscom` is a replacement for `tlbexp.exe` and `OleView` (View TypeLib).
Expand Down Expand Up @@ -255,3 +265,87 @@ classextern forwarder System.Exception
- Color is converted to `OLE_COLOR`(stdole)
- No support for `UnmanagedType.CustomMarshaler`
- No support for .NET Framework assemblies with `AssemblyMetadataAttribute` value ".NETFrameworkAssembly"

## Build Tasks

### Preface

The `dSPACE.Runtime.InteropServices.BuildTasks` assembly and NuGet package provide the ability to create type libraries for a certain assembly at runtime.

For details on the implementation refer to the [documentation](/src/dscom.build/docs/ReadMe.md) section of the repository.

### Build task usage

To create a type library at compile time, simply add a reference to the nuget package, e.g. by using the command line.

```shell
$ dotnet add package dSPACE.Runtime.InteropServices.Build
...
$
```

The result should be a line as follows in your `.csproj` file:

```xml
<PackageReference Include="dSPACE.Runtime.InteropServices.BuildTasks" Version="0.17.0" NoWarn="NU1701">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
```

**Note**: The extra attribute `NoWarn="NU1701"` is only required, if neither `.NET 4.8` nor `.NET 6.0` are targeted, since dotnet pack will currently not create a .NETStandard 2.0 compliant NuGet Package.

#### Using the native build task

The native build task is automatically selected, if a .NET 4.8 or .NET 6.0 assembly for Windows is being build using an x64 platform.

#### Using the CLI based task

The CLI task is automatically selected, if a .NET Standard 2.0 assembly is build. It is also chosen, if the target platform is set to x86.

#### Enforcing the usage of the CLI

It might be necessary to select the CLI based task. To do so, add the following property to your `.csproj` file:

```XML
<_DsComForceToolUsage>true</_DsComForceToolUsage>
```

This will enforce the usage of the DsCom as a command-line tool. Please note, that verbose logging will no longer be working.

#### Enforcing to stop the build, if an error occurs

The build tasks puts a warning to the build log, if the desired type library has not been created, even if the backend has reported a success.

This warning is issued with the warning code `DSCOM001`, which can be collected in the `WarningsAsErrors` array:

```XML
<WarningsAsErrors>$(WarningsAsErrors);DSCOM001</WarningsAsErrors>
```

This way the build stops, if the type library is not exported.

### Parameters

The build task can be parameterized with the following properties:

| **Name** | **Description** | **Default** |
| ------------- | -------------------- | ----------- |
| _DsComTlbExt | Extension of the resulting type library. | .tlb |
| _DsComForceToolUsage | Use DsCom Exe files to create the TLB | false |
| DsComTypeLibraryUniqueId | Overwrite the library UUID | Empty Guid |
| DsComRegisterTypeLibrariesAfterBuild | Use regasm call after the build to register type library after the build | false |
| DsComTlbExportAutoAddReferences | Add referenced assemblies automatically to type libraries | true |
| DsComTlbExportIncludeReferencesWithoutHintPath | If a `Reference` assembly does not provide a `HintPath` Metadata, the item spec shall be task. | false |
| _DsComExportTypeLibraryTargetFile | Path to the resulting file. | `$(TargetDir)\$(TargetName)$(_DsComTlbExt)` * |
| _DsComExportTypeLibraryAssemblyFile | Path to the source assembly file. | `$(TargetPath)` * |

*) This value cannot be overridden.

The build task consumes the following items:

| **Name** | **Description** |
| ---------------------------- | -------------------------------- |
| DsComTlbExportTlbReferences | Referenced type library files. |
| DsComTlbExportReferencePaths | Directories containing type libraries to use for export. |
| DsComTlbExportAssemblyPaths | Assemblies to add for the export. |
7 changes: 7 additions & 0 deletions dscom.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "assembly3", "src\dscom.demo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dscom.test", "src\dscom.test\dscom.test.csproj", "{5B402A1B-18B1-4D88-804A-BC0E58EF3730}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dscom.build", "src\dscom.build\dscom.build.csproj", "{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -52,6 +54,10 @@ Global
{1BAB2994-1423-433B-BFF0-F4698B6D4A04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BAB2994-1423-433B-BFF0-F4698B6D4A04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BAB2994-1423-433B-BFF0-F4698B6D4A04}.Release|Any CPU.Build.0 = Release|Any CPU
{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{54297095-6CB9-4A75-B9C0-41ADA916C27C} = {0A2E33B4-9DF7-4199-BC39-B0FC9C99FA97}
Expand All @@ -61,5 +67,6 @@ Global
{B55E3947-1338-4EDF-A802-B24D91636B31} = {CAAB6257-7EC0-484E-9593-B60CEE8F47D1}
{5B402A1B-18B1-4D88-804A-BC0E58EF3730} = {0A2E33B4-9DF7-4199-BC39-B0FC9C99FA97}
{1BAB2994-1423-433B-BFF0-F4698B6D4A04} = {CAAB6257-7EC0-484E-9593-B60CEE8F47D1}
{F8F68E57-CFFE-4EA5-9C1A-2CD9223B5D85} = {0A2E33B4-9DF7-4199-BC39-B0FC9C99FA97}
EndGlobalSection
EndGlobal
10 changes: 8 additions & 2 deletions examples/32bit/comtestdotnet/comtestdotnet.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<SkipManualTlbExport>false</SkipManualTlbExport>
<SkipManualTlbExport Condition="'$(PerformAcceptanceTest)' != ''">true</SkipManualTlbExport>
</PropertyGroup>

<PropertyGroup>
<TargetFrameworks>net6.0;net48</TargetFrameworks>
<LangVersion>10.0</LangVersion>
Expand All @@ -8,15 +13,16 @@
<ImplicitUsings>disabled</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableComHosting>true</EnableComHosting>
<WarningsAsErrors>$(WarningsAsErrors);DSCOM001</WarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<ComHostTypeLibrary Condition="Exists('comtestdotnet.tlb')" Include="comtestdotnet.tlb" Id="1" />
<Using Remove="System.Net.Http" Condition="'$(PerformAcceptanceTest)' == 'Runtime'" />
</ItemGroup>

<Target Name="tlb" AfterTargets="CoreBuild">
<Target Name="tlb" AfterTargets="CoreBuild" Condition="'$(SkipManualTlbExport)' != 'true'">
<Exec Command="$(ProjectDir)/../bin/dscom32.exe tlbexport $(TargetPath) /out:$(ProjectDir)$(TargetName).tlb" />
<Exec Command="$(ProjectDir)/../bin/dscom32.exe tlbdump $(ProjectDir)$(TargetName).tlb /out:$(ProjectDir)$(TargetName).yaml" />
</Target>

</Project>
72 changes: 72 additions & 0 deletions examples/32bit/scripts/msbuild-acceptance-test.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@ECHO off

SET root=%~dp0\..\..\..\

PUSHD %root%

dotnet pack -p:Configuration=Release

IF NOT EXIST %root%\_packages MKDIR _packages

XCOPY /Y /I /C /F .\src\dscom\bin\Release\*.nupkg _packages\
XCOPY /Y /I /C /F .\src\dscom.build\bin\Release\*.nupkg _packages\

POPD

PUSHD %~dp0\..\comtestdotnet

dotnet msbuild -nodeReuse:False -t:Clean -p:Configuration=Release -p:PerformAcceptanceTest=Runtime

dotnet msbuild -nodeReuse:False -t:Clean -p:Configuration=Release -p:PerformAcceptanceTest=Runtime

dotnet add comtestdotnet.csproj package --prerelease -s %root%\_packages dSPACE.Runtime.InteropServices.BuildTasks

dotnet msbuild -nodeReuse:False -t:Restore -p:Configuration=Release -p:Platform=x64 -p:TargetPlatform=net48 -p:PerformAcceptanceTest=Runtime
dotnet msbuild -nodeReuse:False -t:Build -p:Configuration=Release -p:Platform=x64 -p:TargetPlatform=net48 -p:PerformAcceptanceTest=Runtime -bl
SET ERRUNTIMEX64_NET48=%ERRORLEVEL%

dotnet msbuild -nodeReuse:False -t:Restore -p:Configuration=Release -p:Platform=x64 -p:TargetPlatform=net6.0-windows -p:PerformAcceptanceTest=Runtime
dotnet msbuild -nodeReuse:False -t:Build -p:Configuration=Release -p:Platform=x64 -p:TargetPlatform=net6.0-windows -p:PerformAcceptanceTest=Runtime -bl
SET ERRUNTIMEX64_NET60=%ERRORLEVEL%

dotnet msbuild -nodeReuse:False -t:Restore -p:Configuration=Release -p:Platform=x86 -p:TargetPlatform=net48 -p:PerformAcceptanceTest=Runtime
dotnet msbuild -nodeReuse:False -t:Build -p:Configuration=Release -p:Platform=x86 -p:TargetPlatform=net48 -p:PerformAcceptanceTest=Runtime -bl
SET ERRUNTIMEX86_NET48=%ERRORLEVEL%

dotnet msbuild -nodeReuse:False -t:Restore -p:Configuration=Release -p:Platform=x86 -p:TargetPlatform=net6.0-windows -p:PerformAcceptanceTest=Runtime
dotnet msbuild -nodeReuse:False -t:Build -p:Configuration=Release -p:Platform=x86 -p:TargetPlatform=net6.0-windows -p:PerformAcceptanceTest=Runtime -bl
SET ERRUNTIMEX86_NET60=%ERRORLEVEL%

dotnet remove comtestdotnet.csproj package dSPACE.Runtime.InteropServices.BuildTasks

POPD

SetLocal EnableDelayedExpansion

SET EXITCODE=0

IF NOT "%ERRUNTIMEX64_NET48%" == "0" (
SET EXITCODE=1
ECHO "Runtime specific acceptance test for platform x64 using .NET FullFramework 4.8 failed."
)

IF NOT "%ERRUNTIMEX64_NET60%" == "0" (
SET EXITCODE=1
ECHO "Runtime specific acceptance test for platform x64 using .NET 6.0 failed."
)

IF NOT "%ERRUNTIMEX86_NET48%" == "0" (
SET EXITCODE=1
ECHO "Runtime specific acceptance test for platform x86 using .NET FullFramework 4.8 failed."
)

IF NOT "%ERRUNTIMEX86_NET60%" == "0" (
SET EXITCODE=1
ECHO "Runtime specific acceptance test for platform x64 using .NET 6.0 failed."
)

IF "%EXITCODE%" == "0" (
ECHO "Acceptance test completed successfully."
)

EXIT /B %EXITCODE%
Loading

0 comments on commit 087e6fc

Please sign in to comment.