Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
605 views
in Technique[技术] by (71.8m points)

msbuild - How to reference or copy output of other C# project with a newer framework?

Scenario:

Loader.csproj, which is .NET 4.8; and outputs a .exe with some .dll dependencies
LoaderWrapper.csproj, which is .NET 4.6 and needs to call the .exe of Loader with some arguments.

Main.csproj, which is .NET 4.6 and references LoaderWrapper normally.

I can't create a normal project reference to Loader.csproj from LoaderWrapper.csproj because Loader.csproj is a newer .NET framework.

I can't create an assembly reference as that only copies the .exe file, and not any .dll files the .exe of Loader.csproj depends on.

I can't change the framework version as my application gets loaded in 3d party application Revit, which is .NET 4.6

I can't hardcode the output of Loader.csproj because in my build pipeline I have several different output directories. (eg. for unit tests)

In Visual Studio I can change "Build Dependencies"->"Project Dependencies" on LoaderWrapper.csproj to ensure Loader.csproj gets built, but this doesn't seem to copy/reference the output of Loader.csproj.

So I'm looking for another method to ensure all output of Loader.csproj is included in LoaderWrapper.csproj, and also would end up in Main.csproj through the projectreferences.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Some time ago I solved the similar task - to collect the Content files from one project and include them into the output of another project. It is not exactly the same task as yours, but you can try to adopt my approach.

So, I has project named MainApp and the project called Lib. The Lib project have the txt file ContentFile.txt with Build Action = Content. I need to include ContentFile.txt into the output of MainApp.

I created CustomBuildActions.targets file in the Lib folder with the following contents

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <!--
    Define project to get content files from.
    Definition relies on the fact that this target file stored
    in the same folder with Lib.csproj
    -->
    <ItemGroup>
        <LibProject Include="$(MSBuildThisFileDirectory)/Lib.csproj"/>
    </ItemGroup>

    <!--
    Run msbuild for Lib to collect the list of Content files and store it to the LibContentFiles list.
    Then perform string repace to convert paths to Content files to paths inside app bundle. And store results in the LibContentFileTargetPath.
    -->
    <Target Name="GetBundleFiles" Outputs="@(LibContentFiles)">
        <MSBuild Projects="@(LibProject)" Targets="ContentFilesProjectOutputGroup">
            <Output ItemName="LibContentFiles" TaskParameter="TargetOutputs"/>
        </MSBuild>

        <ItemGroup>
            <LibContentFileTargetPath Include="@(LibContentFiles->Replace($(MSBuildThisFileDirectory), $(AppBundleDir)/Contents/Resources/))"/>
        </ItemGroup> 
    </Target>

    <!-- These targets will fire after mmp creates your bundle but before code signing -->
    <PropertyGroup>
        <CreateAppBundleDependsOn>$(CreateAppBundleDependsOn);GetBundleFiles;CopyOurFiles;</CreateAppBundleDependsOn>
    </PropertyGroup>

    <!-- Since this has inputs/outputs, it will fire only when the inputs are changed or the output does not exist -->
    <Target Name="CopyOurFiles" Inputs="@(LibContentFiles)" Outputs="@(LibContentFileTargetPath)">
        <Message Text="This is us copying a file into resources!" />
        <!-- This could have easily been done w/ a built in build action, but you can extend it arbitrary. -->
        <Copy SourceFiles="@(LibContentFiles)" DestinationFiles="@(LibContentFileTargetPath)" />
</Target>
</Project>

Then import this target in the MainApp project

  <Import Project="../Lib/CustomBuildActions.targets" />

This custom target will collect the Content files from Lib project, transform the paths to preserve folder structure inside MainApp output (e.g. if we will have inside Lib project something like Lib/ContentFolder/Subfolder/contentFile.txt, then inside the bundle if will be placed in Resources/ContentFolder/Subfolder/contentFile.txt) and then copy files inside the bundle.

So, what you can need to adopt:

  1. Use output items of your Loader project instead of content files. So, instead of ContentFilesProjectOutputGroup you will need other target. Please refer to msbuild documentation to find what is best for you.
  2. Change the target dependencies - your custom target should became a dependency of the LoaderWrapper project build steps (in my sample I use CreateAppBundleDependsOn dependency, but it is Xamarin-only thing and you will need to finde the better step to add dependency to).

The full description of my case may be found here https://forums.xamarin.com/discussion/comment/418130


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...