सशर्त संकलन और रूपरेखा लक्ष्य


124

कुछ छोटे स्थान हैं जहां मेरी परियोजना के लिए कोड में काफी सुधार किया जा सकता है अगर लक्ष्य रूपरेखा एक नया संस्करण था। मैं सी # में बेहतर लीवरेज सशर्त संकलन करने में सक्षम होना चाहता हूं ताकि इन्हें आवश्यकतानुसार स्विच किया जा सके।

कुछ इस तरह:

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

क्या इनमें से कोई प्रतीक मुफ्त में आता है? क्या मुझे प्रोजेक्ट कॉन्फ़िगरेशन के हिस्से के रूप में इन प्रतीकों को इंजेक्ट करने की आवश्यकता है? यह करना काफी आसान लगता है क्योंकि मुझे पता होगा कि MSBuild से किस रूपरेखा को लक्षित किया जा रहा है।

/p:DefineConstants="NET40"

लोग इस स्थिति को कैसे संभाल रहे हैं? क्या आप अलग-अलग कॉन्फ़िगरेशन बना रहे हैं? क्या आप कमांड लाइन के माध्यम से स्थिरांक में गुजर रहे हैं?



यदि आप वीएस में एक सरल प्री-बेक्ड समाधान चाहते हैं, तो कृपया इस उपयोगकर्ता की आवाज, विजुअलस्टडियो.सुअरवॉइस . com / forums / 121579-visual-studio/… पर वोट करें ।
जॉन सी सी

1
इस लिंक पर भी नज़र डालें। सुंदर व्याख्यात्मक। blogs.msmvps.com/punitganshani/2015/06/21/…
Marco Alves

परियोजना समूह, नगेट पुनर्स्थापना, और नगेट रेफरी समूह, अच्छा समाधान: shazwazza.com/post/…
ओजबेक

जवाबों:


119

इसे पूरा करने के सर्वोत्तम तरीकों में से एक है अपनी परियोजना में विभिन्न बिल्ड कॉन्फ़िगरेशन बनाना:

<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 आपको प्रत्येक बार प्रत्येक संस्करण बनाने के लिए एक अलग असेंबली देगा।

फिर अपने विभिन्न संस्करणों को संकलित करने के लिए आफ्टरबिल्ड लक्ष्य बनाएं:

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

यह उदाहरण पहली बिल्ड के बाद NET20 के लिए फ्रेमवर्क चर सेट के साथ पूरे प्रोजेक्ट को फिर से जोड़ देगा (दोनों का संकलन और यह मानते हुए कि पहला निर्माण ऊपर से डिफ़ॉल्ट NET35 था)। प्रत्येक संकलन में सशर्त परिभाषित मूल्य सही ढंग से निर्धारित होंगे।

इस तरीके से आप प्रोजेक्ट फाइल में कुछ फाइलों को छोड़ भी सकते हैं अगर आप चाहते हैं कि w / o को फाइल को #ifdef करना है:

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

या संदर्भ भी

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

उत्तम। मेरे पास बस इतना अनुभव था कि यह बनाने के लिए msbuild प्रारूप को हैक किया जा सकता है, लेकिन सभी विवरणों का पता लगाने के लिए पर्याप्त समय नहीं है। आपका बहुत बहुत धन्यवाद!
ममेमी

यदि आप मेरे संबंधित प्रश्न ( stackoverflow.com/questions/2923181 ) पर इस उत्तर का संदर्भ जोड़ते हैं , तो मैं आपको समाधान के रूप में चिह्नित करूंगा। यह वास्तव में एक ही समय में दोनों को हल करता है।
mckamey

7
उत्तर के लिए धन्यवाद, लेकिन अब VS2010 में पहले से ही "TargetFrameworkVersion" नाम का एक नया टैग शामिल है, अब प्रत्येक प्रॉपर्टी समूह के लिए शर्त के साथ, केवल TargetFrameworkVersion बदल गया है, क्या हमें अभी भी इन सभी को काम करने की आवश्यकता है?
आकाश काव

यह उत्तर केवल ढांचे के लिए परिभाषित स्थिरांक होने के बारे में नहीं है, बल्कि कई रूपरेखाओं के लिए भी निर्माण है
katbyte

4
इस पोस्ट ने मेरे लिए काम किया लेकिन मैं MSBuild में अच्छा नहीं हूं और इसे पता लगाने में थोड़ा समय लगा। मैंने एक परियोजना बनाई जो एक उदाहरण के रूप में काम करती है। dev6.blob.core.windows.net/blog-images/DualTargetFrameworks.zip
TheDev6

44

एक विकल्प जो मेरे लिए अब तक काम कर रहा है, वह है प्रोजेक्ट फ़ाइल में निम्नलिखित जोड़ना:

 <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>

यह TargetFrameworkVersion संपत्ति का मूल्य लेता है, जो "v3.5" की तरह है, "v" और "।" "NET35" (नई प्रॉपर्टी फ़ंक्शंस सुविधा का उपयोग करके ) प्राप्त करने के लिए। यह तब किसी भी मौजूदा "NETxx" मान को निकालता है और इसे DefinedConstants के अंत में जोड़ता है। हो सकता है कि इसे स्ट्रीमलाइन करना संभव हो, लेकिन मुझे फिडेल का समय नहीं मिला।

VS में प्रोजेक्ट प्रॉपर्टीज के बिल्ड टैब को देखने से आपको सशर्त संकलन प्रतीकों सेक्शन में परिणामी वैल्यू दिखाई देगी। एप्लिकेशन टैब पर लक्ष्य फ्रेमवर्क संस्करण को बदलना फिर प्रतीक को स्वचालित रूप से बदल देता है। फिर आप #if NETxxसामान्य तरीके से प्रीप्रोसेसर निर्देशों का उपयोग कर सकते हैं । वीएस में परियोजना को बदलने से कस्टम प्रॉपर्टी ग्रुप को खोना नहीं लगता है।

ध्यान दें कि यह आपको क्लाइंट प्रोफ़ाइल लक्ष्य विकल्पों के लिए कुछ अलग नहीं देता है, लेकिन यह मेरे लिए कोई समस्या नहीं है।


जेरेमी, वाह धन्यवाद यह सही है क्योंकि मैं पहले से ही अपने निर्माण समाधान में अलग से निर्माण कर रहा हूं।
ग्रेग फिनजर

+1। किसने सोचा होगा कि "$ (DefineConstants.Contains ('...") को ढूंढना इतना कठिन होगा? धन्यवाद
CAD

मैंने आखिरकार इस पेज पर अपना रास्ता फिर से खोज लिया, क्योंकि मुझे इस बात पर एक रिफ्रेशर की जरूरत थी कि मुझे अपने निर्माण में ये जादूई कांस्टेंट कैसे मिले। मैं आज उसी परियोजना पर फिर से विचार कर रहा हूं, पुस्तकालय को वश में करने के लिए, और मुझे कुछ उपखंडों में मेरे साथ जाने के लिए प्रतीकों की आवश्यकता है। मैंने अभी इसके ऊपर देखा, और देखा कि आपका उत्तर मूल .CSPROJ फ़ाइल में पहले से ही मान्य है।
डेविड ए। ग्रे

15

मुझे इन समाधानों के साथ समस्या थी, संभवतः क्योंकि मेरे प्रारंभिक स्थिरांक इन गुणों द्वारा पूर्व-निर्मित थे।

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

दृश्य स्टूडियो 2010 ने अर्ध-कॉलनों के कारण एक त्रुटि भी दर्ज की, यह दावा करते हुए कि वे अवैध चरित्र हैं। त्रुटि संदेश ने मुझे संकेत दिया क्योंकि मैं पूर्व-निर्मित स्थिरांक को अल्पविरामों से अलग देख सकता था, अंत में मेरे "अवैध" अर्ध-उपनिवेश के बाद। कुछ सुधार और मालिश के बाद मैं एक समाधान के साथ आने में सक्षम था जो मेरे लिए काम करता है।

<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>

मैं आपके प्रोजेक्ट के कंपाइल टैब पर एडवांस्ड कंपाइलर सेटिंग्स डायलॉग ("एडवांस्ड कंपाइल ऑप्शन्स ..." बटन पर क्लिक करके) का स्क्रीनशॉट पोस्ट करूँगा। लेकिन एक नए उपयोगकर्ता के रूप में, मुझे ऐसा करने के लिए प्रतिनिधि की कमी है। यदि आप स्क्रीनशॉट देख सकते हैं, तो आपको प्रॉपर्टी ग्रुप द्वारा कस्टम कॉन्स्टेंट ऑटो-भरे हुए दिखाई देंगे और फिर आप कहेंगे, "मुझे इसमें से कुछ मिलेगा।"


संपादित करें: आश्चर्य की बात है कि तेजी से प्रतिनिधि मिल गया .. धन्यवाद दोस्तों! यहाँ है कि स्क्रीनशॉट:

उन्नत संकलक सेटिंग्स


4

स्थिरांक को साफ करने के साथ शुरू करें:

<PropertyGroup>
  <DefineConstants/>
</PropertyGroup>

इसके बाद, अपने डीबग, ट्रेस और अन्य स्थिरांक का निर्माण करें:

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

अंतिम, अपनी रूपरेखा स्थिरांक बनाएँ:

<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>

मुझे लगता है कि यह दृष्टिकोण बहुत पठनीय और समझने योग्य है।


3

एक मौजूदा <DefineConstants>DEBUG;TRACE</DefineConstants>लाइन के बाद, एक .croroj फ़ाइल में, इसे जोड़ें:

<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>

डीबग और रिलीज़ बिल्ड कॉन्फ़िगरेशन के लिए यह करें। फिर अपने कोड में उपयोग करें:

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

3
डिफ़ॉल्ट और नामित पैरामीटर .NET फ्रेमवर्क 4 की विशेषता नहीं है, लेकिन .NET 4 कंपाइलर की एक विशेषता है। उनका उपयोग .NET 2 या .NET 3 को लक्षित करने वाली परियोजनाओं में भी किया जा सकता है जब तक कि उन्हें विजुअल स्टूडियो 2010 में संकलित किया जाता है। यह सिर्फ वाक्यगत चीनी है। दूसरी ओर, डायनेमिक .NET फ्रेमवर्क 4 की एक विशेषता है, और आप इसे इससे पहले फ्रेमवर्क को लक्षित करने वाली परियोजनाओं में उपयोग नहीं कर सकते हैं।
थानैसिस आयोनिडिस

2

@Azarien, आपके जवाब को जेरेमी के साथ जोड़कर इसे डिबग के बजाय एक स्थान पर रखा जा सकता है। रिलीज आदि।

मेरे लिए, दोनों बदलावों का संयोजन सबसे अच्छा काम करता है, जिसमें #if NETXX का उपयोग करते हुए कोड में स्थितियां शामिल हैं और एक ही बार में विभिन्न फ्रेमवर्क संस्करणों के लिए निर्माण भी।

मेरे पास मेरी .csproj फ़ाइल में ये हैं:

  <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>

और लक्ष्यों में:

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

0

यदि आप .NET कोर बिल्ड सिस्टम का उपयोग कर रहे हैं, तो आप इसके पूर्वनिर्धारित प्रतीकों का उपयोग कर सकते हैं (जो वास्तव में आपके उदाहरण से पहले से मेल खाते हैं और आपको अपने परिवर्तनों की आवश्यकता नहीं है .csproj!):

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

पूर्वनिर्धारित प्रतीकों की सूची क्रॉस प्लेटफ़ॉर्म टूल्स और #if (C # संदर्भ) के साथ विकासशील पुस्तकालयों में प्रलेखित है :

.NET फ्रेमवर्क: NETFRAMEWORK , NET20, NET35, NET40, NET45, NET451, NET452, NET46, NET461, NET462, NET47, NET471, NET472,NET48

नेट मानक: NETSTANDARD , NETSTANDARD1_0, NETSTANDARD1_1, NETSTANDARD1_2, NETSTANDARD1_3, NETSTANDARD1_4, NETSTANDARD1_5, NETSTANDARD1_6, NETSTANDARD2_0,NETSTANDARD2_1

नेट कोर: NETCOREAPP , NETCOREAPP1_0, NETCOREAPP1_1, NETCOREAPP2_0, NETCOREAPP2_1, NETCOREAPP2_2,NETCOREAPP3_0

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.