IT story

조건부 컴파일 및 프레임 워크 대상

hot-time 2020. 7. 16. 08:02
반응형

조건부 컴파일 및 프레임 워크 대상


대상 프레임 워크가 최신 버전 인 경우 내 프로젝트의 코드를 크게 향상시킬 수있는 몇 가지 사소한 곳이 있습니다. C #에서 조건부 컴파일을 더 잘 활용하여 필요에 따라 이러한 조건을 전환하고 싶습니다.

다음과 같은 것 :

#if NET40
using FooXX = Foo40;
#elif NET35
using FooXX = Foo35;
#else NET20
using FooXX = Foo20;
#endif

이 기호들 중 어떤 것이 무료입니까? 프로젝트 구성의 일부로이 기호를 주입해야합니까? MSBuild의 대상이되는 프레임 워크를 알기 때문에 쉽게 할 수있을 것 같습니다.

/p:DefineConstants="NET40"

사람들은이 상황을 어떻게 처리하고 있습니까? 다른 구성을 작성 중입니까? 커맨드 라인을 통해 상수를 전달하고 있습니까?


이를 수행하는 가장 좋은 방법 중 하나는 프로젝트에서 다른 빌드 구성을 작성하는 것입니다.

<PropertyGroup Condition="  '$(Framework)' == 'NET20' ">
  <DefineConstants>NET20</DefineConstants>
  <OutputPath>bin\$(Configuration)\$(Framework)</OutputPath>
</PropertyGroup>


<PropertyGroup Condition="  '$(Framework)' == 'NET35' ">
  <DefineConstants>NET35</DefineConstants>
  <OutputPath>bin\$(Configuration)\$(Framework)</OutputPath>
</PropertyGroup>

그리고 기본 구성 중 하나에서 :

<Framework Condition=" '$(Framework)' == '' ">NET35</Framework>

다른 곳에서 정의되지 않은 경우 기본값을 설정합니다. 위의 경우 OutputPath는 각 버전을 빌드 할 때마다 별도의 어셈블리를 제공합니다.

그런 다음 AfterBuild 대상을 만들어 다른 버전을 컴파일하십시오.

<Target Name="AfterBuild">
  <MSBuild Condition=" '$(Framework)' != 'NET20'"
    Projects="$(MSBuildProjectFile)"
    Properties="Framework=NET20"
    RunEachTargetSeparately="true"  />
</Target>

이 예제는 첫 번째 빌드 후 Framework 변수가 NET20으로 설정된 전체 프로젝트를 다시 컴파일합니다 (둘 다 컴파일하고 첫 번째 빌드가 위의 기본 NET35라고 가정). 각 컴파일에는 조건부 정의 값이 올바르게 설정됩니다.

이런 식으로 파일을 #ifdef하지 않고 프로젝트 파일에서 특정 파일을 제외 할 수도 있습니다.

<Compile Include="SomeNet20SpecificClass.cs" Condition=" '$(Framework)' == 'NET20' " />

또는 참조

<Reference Include="Some.Assembly" Condition="" '$(Framework)' == 'NET20' " >
  <HintPath>..\Lib\$(Framework)\Some.Assembly.dll</HintPath>
</Reference>

지금까지 나를 위해 일하는 대안은 프로젝트 파일에 다음을 추가하는 것입니다.

 <PropertyGroup>
    <DefineConstants Condition=" !$(DefineConstants.Contains(';NET')) ">$(DefineConstants);$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</DefineConstants>
    <DefineConstants Condition=" $(DefineConstants.Contains(';NET')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(";NET"))));$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", ""))</DefineConstants>
  </PropertyGroup>

"v3.5"와 같은 TargetFrameworkVersion 속성 값이 "v"와 "."를 대체합니다. "NET35"를 가져옵니다 (새로운 속성 기능 사용). 그런 다음 기존 "NETxx"값을 제거하고 DefinedConstants 끝에 추가합니다. 이것을 능률화하는 것이 가능할 수도 있지만, 바이올린을 칠 시간이 없습니다.

VS에서 프로젝트 속성의 빌드 탭을 보면 조건부 컴파일 기호 섹션에 결과 값이 표시됩니다. 응용 프로그램 탭에서 대상 프레임 워크 버전을 변경하면 기호가 자동으로 변경됩니다. 그런 다음 #if NETxx일반적인 방식으로 프리 프로세서 지시문 을 사용할 수 있습니다 . VS에서 프로젝트를 변경해도 사용자 정의 PropertyGroup이 손실되지 않습니다.

Note that this doesn't give seem to give you anything different for the Client Profile target options, but that's not an issue for me.


I had problems with these solutions, possibly because my initial constants were pre-built by these properties.

<DefineConstants />
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<DebugSymbols>true</DebugSymbols>

Visual Studio 2010 also threw up an error because of the semi-colons, claiming they are illegal characters. The error message gave me a hint as I could see the pre-built constants seperated by commas, eventually followed by my "illegal" semi-colon. After some reformatting and massaging I was able to come up with a solution that works for me.

<PropertyGroup>
  <!-- Adding a custom constant will auto-magically append a comma and space to the pre-built constants.    -->
  <!-- Move the comma delimiter to the end of each constant and remove the trailing comma when we're done.  -->
  <DefineConstants Condition=" !$(DefineConstants.Contains(', NET')) ">$(DefineConstants)$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants>
  <DefineConstants Condition=" $(DefineConstants.Contains(', NET')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", NET"))))$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants>
  <DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 2.0 ">$(DefineConstants)NET_20_OR_GREATER, </DefineConstants>
  <DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 3.5 ">$(DefineConstants)NET_35_OR_GREATER</DefineConstants>
  <DefineConstants Condition=" $(DefineConstants.EndsWith(', ')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", "))))</DefineConstants>
</PropertyGroup>

I would post a screenshot of the Advanced Compiler Settings dialog (opened by clicking the "Advanced Compile Options..." button on the Compile tab of your project). But as a new user, I lack the rep to do so. If you could see the screenshot, you would see the custom constants auto-filled by the property group and then you'd be saying, "I gotta get me some of that."


EDIT: Got that rep surprisingly fast.. Thanks guys! Here's that screenshot:

Advanced Compiler Settings


Begin with clearing the constants:

<PropertyGroup>
  <DefineConstants/>
</PropertyGroup>

Next, build up your debug, trace and other constants like:

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <DefineConstants>TRACE;DEBUG;$(DefineConstants)</DefineConstants>
</PropertyGroup>

Last, build your framework constants:

<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v2.0' ">
  <DefineConstants>NET10;NET20;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v3.0' ">
  <DefineConstants>NET10;NET20;NET30;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v3.5' ">
  <DefineConstants>NET10;NET20;NET30;NET35;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">
  <DefineConstants>NET10;NET20;NET30;NET35;NET40;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v4.5' ">
  <DefineConstants>NET10;NET20;NET30;NET35;NET40;NET45;$(DefineConstants)</DefineConstants>
</PropertyGroup>

I think this approach is very readable and understandable.


In a .csproj file, after an existing <DefineConstants>DEBUG;TRACE</DefineConstants> line, add this:

<DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' ">NET_40_OR_GREATER</DefineConstants>
<DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' == '4.0' ">NET_40_EXACTLY</DefineConstants>

Do this for both Debug and Release build configurations. Then use in your code:

#if NET_40_OR_GREATER
   // can use dynamic, default and named parameters
#endif

@Azarien, your answer can be combined with Jeremy's to keep it at one place rather than Debug|Release etc.

For me, combining both variations works best i.e. including conditions in code using #if NETXX and also building for different framework versions in one go.

I have these in my .csproj file:

  <PropertyGroup>
    <DefineConstants Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' ">NET_40_OR_GREATER</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' == '3.5' ">
    <DefineConstants>NET35</DefineConstants>
    <OutputPath>bin\$(Configuration)\$(TargetFrameworkVersion)</OutputPath>
  </PropertyGroup>

and in targets:

  <Target Name="AfterBuild">
    <MSBuild Condition=" '$(TargetFrameworkVersion.Replace(&quot;v&quot;,&quot;&quot;))' &gt;= '4.0' "
      Projects="$(MSBuildProjectFile)"
      Properties="TargetFrameworkVersion=v3.5"
      RunEachTargetSeparately="true"  />
  </Target>

참고URL : https://stackoverflow.com/questions/2923210/conditional-compilation-and-framework-targets

반응형