Использование 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.

(Конечной целью здесь является пакетный файл, который может создать чистую версию проекта для распространения.)


Дополнительная информация:

Оба проекта имеют конфигурации «Отладка» и «Выпуск». Исполняемый проект имеет «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
Свойство Platform задает платформу решения. Деталь конфигурации, имеющая значение только для проектов C++. Но фактическая настройка, которую вы хотите изменить, — это та, которая отображается на вкладке «Проект» > «Свойства» > «Сборка». Пока вы добавляете несколько платформ, очень важно, чтобы они совпадали, иначе путаница будет фатальной. Обычно это не так, по умолчанию в проекте используется AnyCPU для платформы, но установлен флажок Prefer 32-bit. Обязательно измените настройку как для конфигурации отладки, так и для конфигурации выпуска.   -  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 solution использует платформу AnyCPU DLL project).   -  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
Мой вопрос, возможно, похож на этот вопрос, который сам по себе не получил удовлетворительного ответа: -via-msbuild?rq=1" title="создание проекта Visual Studio с различными платформами через msbuild">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