การใช้ msbuild.exe เพื่อสร้างโครงการที่มีการขึ้นต่อกันซึ่งต้องใช้คุณสมบัติแพลตฟอร์มอื่น

ฉันมีโครงการ C# ที่ค่อนข้างตรงไปตรงมาสองโครงการ: โปรแกรมที่สามารถสร้างเป็น x86 หรือ AnyCPU ซึ่งอ้างอิง (ผ่าน <ProjectReference>) โครงการ DLL ที่มีการกำหนดค่า AnyCPU เท่านั้น ทั้งหมดนี้ทำงานได้ตามที่คาดไว้ภายใน Visual Studio

ฉันกำลังพยายามสร้างเวอร์ชัน x86 ของโปรเจ็กต์ปฏิบัติการ (และการขึ้นต่อกัน) จากบรรทัดคำสั่งด้วย /p:Platform="x86" ซึ่งทำให้การสร้างโครงการ DLL ล้มเหลว (ในขณะที่ /p:Platform="AnyCPU" ใช้งานได้ อาจเป็นเพราะใช้ได้กับทั้งสองโครงการ)

บรรทัดคำสั่งทั้งหมดที่ฉันใช้คือ:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild MyProject\MyProject.csproj /t:Build /p:Configuration="Release" /p:Platform="x86"

ตัวเลือกของฉันในการทำให้บิลด์นี้ทำงานจากบรรทัดคำสั่งมีอะไรบ้าง ควรโดยไม่ต้องแก้ไขโครงการ DLL เลย หรือแก้ไขโครงการในลักษณะที่รบกวนการใช้งานตามปกติใน Visual Studio

(เป้าหมายสูงสุดที่นี่คือแบตช์ไฟล์ที่สามารถสร้างเวอร์ชันใหม่ของโปรเจ็กต์เพื่อการเผยแพร่)


ข้อมูลเพิ่มเติม:

ทั้งสองโครงการมีการกำหนดค่า "Debug" และ "Release" โครงการที่ปฏิบัติการได้มี "x86" และ "AnyCPU" ภายใต้แพลตฟอร์ม โครงการ DLL มีเพียง "AnyCPU" ที่พร้อมใช้งานภายใต้แพลตฟอร์ม ตัวเลือก "เป้าหมายแพลตฟอร์ม" ตรงกับ "แพลตฟอร์ม" ในทุกกรณี (ไม่มีตัวเลือก "ชอบ 32 บิต" เนื่องจากฉันใช้ VS2010)

ดูเหมือนว่าข้อผิดพลาดจะเป็นข้อผิดพลาดที่เกี่ยวข้องกับการคอมไพล์ ("ไม่อนุญาตให้ใช้รหัสที่ไม่ปลอดภัย") ใน DLL ซึ่ง - แม้ว่าฉันจะไม่แน่ใจ 100% - ดูเหมือนว่าจะเป็นเพราะไม่มีองค์ประกอบ <PropertyGroup> ในโครงการ DLL ใดที่ตรงกัน (เนื่องจาก Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " ฯลฯ) ที่จะระบุพารามิเตอร์ที่จำเป็นสำหรับการคอมไพล์ (เช่น AllowUnsafeBlocks และ DefineConstants)


person Andrew Russell    schedule 05.10.2017    source แหล่งที่มา
comment
คุณสมบัติแพลตฟอร์มตั้งค่า แพลตฟอร์มโซลูชัน รายละเอียดการกำหนดค่าที่สำคัญกับโปรเจ็กต์ C++ เท่านั้น แต่การตั้งค่าจริงที่คุณต้องการเปลี่ยนคือการตั้งค่าที่ปรากฏบนแท็บโครงการ > คุณสมบัติ > สร้าง ตราบใดที่คุณเพิ่มหลายแพลตฟอร์ม มันค่อนข้างสำคัญที่จะต้องจับคู่ให้ตรงกัน ไม่เช่นนั้นความสับสนอาจถึงแก่ชีวิตได้ โดยปกติแล้วจะไม่เป็นเช่นนั้น ค่าเริ่มต้นของโปรเจ็กต์คือ AnyCPU สำหรับแพลตฟอร์ม แต่ได้ทำเครื่องหมายในช่อง "ต้องการ 32 บิต" อย่าลืมเปลี่ยนการตั้งค่าทั้งสำหรับการกำหนดค่า Debug และ Release   -  person Hans Passant    schedule 05.10.2017
comment
@HansPassant ฉันไม่เข้าใจว่าคุณกำลังพูดอะไร เป้าหมายแพลตฟอร์มในการตั้งค่าโปรเจ็กต์ (เช่น: <PlatformTarget> ในไฟล์โปรเจ็กต์) ตรงกับแพลตฟอร์มที่ระบุโดย $(Platform) (เช่น: แพลตฟอร์มใดก็ตามที่เลือกไว้สำหรับบิลด์) ในลักษณะปกติที่คุณคาดหวังสำหรับไฟล์โปรเจ็กต์ เช่น: <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> Visual Studio จะสร้างชุด x86 EXE + AnyCPU DLL ได้ดี ฉันจะทำสิ่งนี้จากบรรทัดคำสั่งได้อย่างไร มีวัตถุประสงค์เพื่อสร้าง EXE ในการกำหนดค่าทั้งสอง   -  person Andrew Russell    schedule 06.10.2017
comment
หืม นั่นคือสิ่งที่ผมหมายถึงถึงขั้นเสียชีวิต คลิกขวาที่โครงการ EXE ของคุณ > คุณสมบัติ > แท็บสร้าง มีสองคอมโบบ็อกซ์ที่ด้านบนและการตั้งค่าสองรายการที่คุณสนใจ ได้แก่ เป้าหมายแพลตฟอร์ม และ ต้องการ 32 บิต มีค่าที่เป็นไปได้ 4 ค่าสำหรับคอมโบบ็อกซ์ ซึ่งเป็นการรวมกันของ Debug/Release และ x86/AnyCPU จดค่าทั้งหมดของการตั้งค่าสำหรับชุดค่าผสมทั้ง 4 รายการนี้แล้วโพสต์ไว้ในคำถามของคุณ   -  person Hans Passant    schedule 06.10.2017
comment
@HansPassant ต่อท้ายข้อมูลนั้นต่อท้ายคำถามของฉัน สำหรับฉันดูเหมือนว่าคำถามของฉันอาจเป็นไปตามว่ามีวิธีสกัดกั้นสิ่งที่ <ProjectReference> ทำหรือไม่ (มันจะง่ายพอที่จะสร้าง DLL แยกกัน) ฉันไม่แน่ใจว่ามันใช้งานได้จริงแค่ไหน แต่เห็นได้ชัดว่า VS ใช้งานได้ (แพลตฟอร์ม x86 โซลูชัน ใช้แพลตฟอร์ม AnyCPU DLL โครงการ)   -  person Andrew Russell    schedule 06.10.2017
comment
VS2010 อุ๊ย ยากที่จะทำซ้ำ นี่เป็นเรื่องเกี่ยวกับช่องทำเครื่องหมายอนุญาตรหัสที่ไม่ปลอดภัยในโครงการ DLL สูตรเดียวกัน คุณมีค่าที่เป็นไปได้ 4 ค่า และการตั้งค่าเป้าหมายแพลตฟอร์มสำหรับโครงการ DLL ไม่มีบทบาท เนื่องจากคุณต้องการใช้ AnyCPU สำหรับทั้ง 4 ค่า ตรวจสอบให้แน่ใจว่าได้ทำเครื่องหมายที่ช่องทำเครื่องหมายสำหรับชุดค่าผสมที่เป็นไปได้ทั้ง 4 ชุด   -  person Hans Passant    schedule 06.10.2017
comment
@HansPassant สิ่งที่คุณแนะนำดูเหมือนจะเป็นเพียงแค่เข้าไปและเพิ่มชุดค่าผสม $(Configuration)|$(Platform) ที่คุณส่งผ่านและให้การตั้งค่าที่ถูกต้อง ซึ่งดูเหมือนเป็นวิธีแก้ปัญหามากกว่า (ก็ค่อนข้างเจ็บปวดเช่นกัน เนื่องจากฉันพยายามหลีกเลี่ยงการแก้ไขไฟล์โครงการของ DLL) ฉันเดาว่านี่เป็นคำถาม <ProjectReference> ทำงานอย่างไรมากกว่าคำถามที่ทำให้ข้อผิดพลาดหายไป   -  person Andrew Russell    schedule 06.10.2017
comment
คำถามของฉันอาจคล้ายกับคำถามนี้ ซึ่งตัวเองไม่ได้รับคำตอบที่น่าพอใจจริงๆ: stackoverflow.com/questions/12348645/   -  person Andrew Russell    schedule 06.10.2017


คำตอบ (1)


ตอบคำถามของฉันเอง... ก่อนอื่นเลย MSBuild สามารถสร้างไฟล์โซลูชันได้ นี่เป็นสิ่งที่คุณคาดหวังอย่างแน่นอน:

msbuild MySolution.sln /p:Configuration="Release" /p:Platform="x86"

ผลลัพธ์คือการปฏิบัติการ x86 ด้วย AnyCPU DLL (ตามที่โซลูชันระบุ)

มีบางคนบนอินเทอร์เน็ตแนะนำว่าพฤติกรรมของมันไม่ สมบูรณ์แบบ ตรงกับ Visual Studio ในบางกรณีที่คลุมเครือ แต่ดูเหมือนว่าจะทำงานได้ดีสำหรับจุดประสงค์ของฉัน (ฉันคิดว่าพวกเขากำลังมีปัญหากับลำดับสิ่งต่าง ๆ ที่ถูกสร้างขึ้น)

ฉันรู้ว่า MSBuild สามารถสร้างไฟล์โซลูชันได้ แต่ - โอ๊ะโอ - ฉันละเลยที่จะทดสอบมันในกรณีการผลิตซ้ำแบบง่าย ๆ ของฉัน หลังจากที่มันล้มเหลวในสิ่งที่ซับซ้อนกว่าที่ฉันกำลังทำอยู่


ข้างต้นเพียงอย่างเดียวไม่เพียงพอสำหรับคำตอบที่น่าพึงพอใจโดยเฉพาะอย่างยิ่งหากจำเป็นต้องปรับแต่งสิ่งต่าง ๆ วิธีที่ MSBuild สร้างไฟล์โซลูชันคือการสร้างไฟล์โครงการจำลองตามไฟล์โซลูชัน ซึ่งสามารถตรวจสอบได้โดยการตั้งค่าตัวแปรสภาพแวดล้อมก่อนดังนี้:

set MSBuildEmitSolution=true

การดำเนินการนี้จะปล่อยไฟล์โครงการจำลองถัดจากไฟล์โซลูชัน ซึ่งจากนั้นจึงสามารถตรวจสอบได้

ฉันยังไม่ได้วิเคราะห์ว่ามันกำลังทำอะไรอยู่อย่างสมบูรณ์ แต่ดูเหมือนว่าจะค่อนข้างตรงไปตรงมาเหมือนกับว่ากำลังใช้ <MSBuild> งาน พร้อมด้วยพารามิเตอร์ Projects ที่ส่งผ่านในโซลูชันที่ระบุ Configuration และ Platform ที่เหมาะสมสำหรับแต่ละโครงการ ตามเอกสารดูเหมือนว่าจะใช้เอกสารที่ระบุใน AdditionalProperties (สิ่งนี้ก็ดูเหมือนจะมีประโยชน์เช่นกัน)


เพื่อเป็นการอ้างอิง นี่คือโค้ดที่เกี่ยวข้องบางส่วนที่แยกมาจากไฟล์โปรเจ็กต์ที่สร้างขึ้น:

<Target Name="Build" Outputs="@(CollectedBuildOutput)">
  <MSBuild Projects="@(ProjectReference)" BuildInParallel="True" Properties="BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
</Target>

โดยที่ @(ProjectReference) กำลังดึงข้อมูลจาก:

<ItemGroup>
  <ProjectReference Include="X:\Solution\MyProject\MyProject.csproj">
    <ToolsVersion>
    </ToolsVersion>
    <SkipNonexistentProjects>False</SkipNonexistentProjects>
    <AdditionalProperties>Configuration=Release; Platform=x86; VisualStudioVersion=10.0</AdditionalProperties>
    <Configuration>Release</Configuration>
    <Platform>x86</Platform>
  </ProjectReference>
  <ProjectReference Include="X:\Solution\DLLProject\DLLProject.csproj">
    <ToolsVersion>
    </ToolsVersion>
    <SkipNonexistentProjects>False</SkipNonexistentProjects>
    <AdditionalProperties>Configuration=Release; Platform=AnyCPU; VisualStudioVersion=10.0</AdditionalProperties>
    <Configuration>Release</Configuration>
    <Platform>AnyCPU</Platform>
  </ProjectReference>
</ItemGroup>

(โปรดสังเกต AdditionalProperties ที่แตกต่างกัน)

person Andrew Russell    schedule 06.10.2017