Передача нескольких значений в свойство Wix DefineConstants с помощью MSBuild

В настоящее время я интегрирую свои проекты Wix в MSBuild. Мне необходимо передать в проект Wix несколько значений. Одно значение будет работать (ProductVersion в примере ниже).

<Target Name="BuildWixSetups">
    <MSBuild Condition="'%(WixSetups.Identity)'!=''"
                Projects="%(WixSetups.Identity)"
                Targets="Rebuild" Properties="Configuration=Release;OutputPath=$(OutDir);DefineConstants=ProductVersion=%(WixSetups.ISVersion)" ContinueOnError="true"/>
</Target>

Однако как передать несколько значений ключу DefineConstants? Я перепробовал все «логические» разделители (пробел, запятая, точка с запятой, вертикальная черта), но это не работает.

Кто-нибудь еще сталкивался с этой проблемой?

Решения, которые не работают:

  1. Попытка добавить элемент DefineConstants не работает, потому что DefineConstants необходимо выразить в атрибуте Properties.

person Sardaukar    schedule 03.02.2009    source источник


Ответы (12)


Проблема:

Задача MSBuild (не MSBuild.exe, задача MSBuild с именем MSBuild) не может обрабатывать несколько констант, используемых проектами WIX. Обычно вы должны указывать свойства в своем сценарии сборки, например:

<MSBuild Projects="YourSolution.sln" Properties="Configuration=MyConfig;Platform=x86;DefineConstants=&quot;SOMETHING=1;SOMETHINGELSE=2&quot;" />

Однако при просмотре журналов сборки вы видите, что MSBuild разделяет константы и не сохраняет значения, сгруппированные вместе, как вы ожидаете - аналогично:

Task "MSBuild" Global Properties:
Configuration=MyConfig
Platform=x86
DefineConstants="SOMETHING=1
SOMETHINGELSE=2"

Поэтому, когда свеча пытается использовать эти константы, она обычно отвечает сообщением «ошибка CNDL0150: Неопределенная переменная препроцессора '$ (var.SOMETHINGELSE)'. Это означает, что задача MSBuild неправильно обрабатывает свойства, которые содержат несколько знаков '=' даже в значении. когда они сгруппированы в кавычках. Без сгруппированных значений свойств в кавычках их, очевидно, следует рассматривать как отдельные свойства, а не как одно значение.

Временное решение:

Чтобы решить эту проблему, вам необходимо вызвать MSBuild.exe напрямую и передать ему эти значения вручную.

msbuild.exe /p:Configuration=MyConfig /p:Platform=x86 /p:DefineConstants="SOMETHING=1;SOMETHINGELSE=2" YourSolution.sln

Это позволит вашим константам работать так, как вы хотите, без необходимости переделывать проект установки WiX.

ПРИМЕЧАНИЕ. Если вы используете только одну константу, вы все равно можете использовать задачу MSBuild следующим образом:

<MSBuild Projects="YourSolution.sln" Properties="Configuration=MyConfig;Platform=x86;DefineConstants=&quot;SOMETHING=1&quot;" />
person Jeff Winn    schedule 26.04.2010
comment
Есть способ сделать это с помощью задачи MSBuild вместо вызова exe: stackoverflow.com/questions/506687/ - person Rory MacLeod; 25.11.2010
comment
похоже, что если вы не используете msbuild 4, это путь - person Daniel Powell; 29.06.2011

Проблема заключается в передаче пар имя-значение в задачу MSBuild, а затем в том, чтобы MSBuild правильно проанализировал их, чтобы их можно было передать задаче Candle. Кажется, что MSBuild может обрабатывать список простых имен или одну пару имя-значение, но не список пар.

Мое решение - выйти из списка, когда он передается в задачу MSBuild, и снова отключить его, когда он перейдет в задачу Candle.

В вашем файле MSBuild определите пары в свойстве следующим образом:

<PropertyGroup>
    <WixValues>
        One=1;
        Two=2;
        Three=3;
    </WixValues>
</PropertyGroup>

Когда вы вызываете задачу MSBuild, избегайте свойства (требуется MSBuild 4):

<MSBuild 
    Projects="setup.wixproj"
    Properties="WixValues=$([MSBuild]::Escape($(WixValues)))" />

Неэкранирование должно быть выполнено в файле wixproj, но нет необходимости редактировать файл вручную. Просто откройте свойства проекта, перейдите на вкладку «Сборка» и там, где написано «Определить переменные препроцессора», введите:

$([MSBuild]::Unescape($(WixValues)))

Это работает, даже если в этом поле уже есть другие переменные; просто добавьте это в список вместе с точкой с запятой.

В журнале MSBuild вы увидите, что инструмент candle.exe правильно принимает аргументы:

candle.exe -dOne=1 -dTwo=2 -dThree=3 -dConfiguration=Release...
person Rory MacLeod    schedule 25.11.2010

У меня все еще было много проблем с тем, чтобы заставить это работать, но части каждого ответа выше внесли свой вклад в мое решение, поэтому я хотел поделиться.

Среда: TFS Build Server 2010 - Powershell вызывает MSBuild.exe Wix 3.6 установлен на сервере сборки

Цель состоит в том, чтобы передать номер версии сборки и 5 каталогов в MSBuild, чтобы Candle.exe правильно их получил.

Сборка вызывает командный файл в конце сборки, и этот командный файл включает шаг для вызова сценария PowerShell для сборки установщика Wix. Он передает номер версии для сборки, а также исходный и выходной каталоги (вывод - это ссылка на общий доступ к файлам UNC \ tfsbuildserver ..)

Чтобы заставить его работать, в файле Powershell ps1,

  • используйте одиночный / p: DefineConstants =, который начинается с двойного "
  • кодировать все разделение; как% 3b
  • = нормально не закодированы
  • не должно быть дополнительных кавычек вокруг имен файлов с пробелами

    $msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
    
    $options = " /p:Configuration=Release /p:Platform=x64 "
    $options = $options + " /p:DefineConstants="""
    $options = $options + "SolutionDir=" + $SourceDir
    $options = $options + "%3bTFSBuildSourceLanding=" + $OutputLocation + "SharepointWebRoot\Landing"
    $options = $options + "%3bTFSBuildSourceLandingAdmin=" + $OutputLocation + "SharepointWebRoot\LandingAdmin"
    $options = $options + "%3bTFSBuildSourceRegistration=" + $OutputLocation + "Extranet_Registration"
    $options = $options + "%3bTFSBuildSourceGAC=" + $OutputLocation + "GAC"
    $options = $options + "%3bTFSBuildSourceSQL=" + $OutputLocation + "SQL"
    $options = $options + "%3bProductVersion=" + $BuildVersion + """" 
    
    
    $build = $msbuild + " ""EUM WIX\EUM Wix.wixproj"" " + $options + " /t:Build"
    $clean = $msbuild + " ""EUM WIX\EUM Wix.wixproj"" " + $options + " /t:Clean"
    
    
    Write-Host "Building Wix Installer..."
    Invoke-Expression $clean
    Invoke-Expression $build
    
  • Внутри файла wixproj мы должны отменить экранирование (внизу, где говорится, что нужно раскомментировать, чтобы изменить)

      <Target Name="BeforeBuild">
          <CreateProperty Value="$([MSBuild]::Unescape($(DefineConstants)))">
             <Output TaskParameter="Value" PropertyName="DefineConstants" />
          </CreateProperty>
      </Target>
    
  • Также обратите внимание, что в Visual Studio я буду использовать настройки отладки, и я могу установить значения по умолчанию для этих значений на вкладке «Сборка», «Определить переменные препроцессора».

  • в настройках выпуска этот элемент должен быть пустым, так как он будет передан в командной строке выше.

person Mark Jones    schedule 30.08.2012

При использовании задачи MSBuild для создания решения Visual Studio у меня работает следующее:

<MSBuild Projects="Solution.sln"
         Targets="Rebuild"
         Properties="Configuration=Debug;DefineConstants=DEBUG%3bTRACE" />

Хитрость заключается в использовании %3b для экранирования разделителя ; внутри значения DefineConstants. Я не уверен, что это сработает и для =. Возможно, их нужно экранировать как %3d, или это может вообще не сработать ...

Также есть атрибут TargetAndPropertyListSeparators в элементе MSBuild. Я не могу найти для него никакой документации, но, возможно, можно будет использовать его для установки разделителя, отличного от ;.

person Dave    schedule 13.09.2010
comment
Это работает, когда вы передаете простые имена, такие как отладка и трассировка, но не когда вы хотите передавать пары имя-значение, такие как config = debug; log = trace. - person Rory MacLeod; 25.11.2010

Вы можете передать его как параметр, а не как константу. Код будет выглядеть так:

<MSBuild ...
    Properties="ProductVersion=%(WixSetups.ISVersion)" />

Теперь в проекте WiX добавляем константу:

<DefineConstants>BuildVersion=$(ProductVersion)</DefineConstants>

И при необходимости используйте его в файле * .wxs:

$(var.BuildVersion)

Например:

<Product Id="*" Name="My Company" Language="1033" Version="$(var.BuildVersion)"... />

Это будет работать с несколькими параметрами.

person Ruslan    schedule 13.03.2012

Я знаю, что документы MSDN полны ошибок и иногда вводят в заблуждение: вот что там говорится о DefineConstants

Определяет условные константы компилятора. Пары символ / значение разделяются точкой с запятой и указываются с использованием следующего синтаксиса:

символ1 = значение1; символ2 = значение2

Это свойство эквивалентно переключателю компилятора / define.

http://msdn.microsoft.com/en-us/library/bb629394.aspx

Согласно MSDN, вы можете 1. определить несколько констант и 2. (@Sayed) присвоить значения

ОДНАКО я не смог добиться того, чтобы ожидаемое поведение этого свойства задачи MSBuild работало должным образом, и рекомендовал обходной путь Джеффа Винна, и его сообщение должно быть отмечено как ответ.

person RyBolt    schedule 06.05.2010
comment
Сделанный. Спасибо за объяснение. - person Sardaukar; 10.05.2010

Следующие строки работали, когда я включил их в файл .wixproj (используя Visual Studio 2010).

<PropertyGroup>
  <DefineConstants>Const1=Value1;Const2=Value2;Const3=Value3</DefineConstants>
</PropertyGroup>
person Kyle McClellan    schedule 09.11.2010

Думаю, что-то вроде этого должно сработать.

 <DefineConstants>DEBUG;TRACE</DefineConstants> 

Проверьте это сообщение в блоге, чтобы узнать, может ли оно вам помочь. http://www.sedodream.com/PermaLink,guid,9b1d23aa-6cb2-48cb-a47a-9cef29622676.aspx

Также проверьте это сообщение на форуме. Решает ту же проблему, что и ваша. http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/3f485bf4-1b00-48bf-b5d0-4b83341ce4a6/.

person Aamir    schedule 03.02.2009
comment
Это не работает, потому что DefineConstants необходимо выражать ВНУТРИ атрибута Properties. Он не работает как атрибут сам по себе. - person Sardaukar; 03.02.2009
comment
Спасибо, но я уже прочитал обе эти статьи. Даже если первый работает, я все равно считаю его взломом, потому что проекты нужно собирать два раза. - person Sardaukar; 03.02.2009
comment
Я не могу проверить это сам, но после определения этого элемента не можете ли вы использовать его как Properties = DefineConstants = $ (DefineConstants)? - person Aamir; 04.02.2009

Обходной путь.

Предположения:

  • Возможные значения SomeEnumValue: EnumValue1 и EnumValue2.

В MSBuild:

<DefineConstants>Debug;use_$(SomeEnumValue)</DefineConstants>

В WiX:

<?ifdef $(var.use_EnumValue1) ?>
  ...
<?elseif $(var.use_EnumValue2) ?>
  ...
<?endif?>
person donpark    schedule 30.07.2010

Мое решение - избежать точки с запятой, используя &#59;, следующим образом:

<MSBuild
    Projects="MyApplication.sln"
    Properties="DefineConstants=Sources=$(OutputPath)\MyApplication\&#59;Configuration=$(Configuration)&#59;OutDir=$(OutputPath)\WiX\"
    Targets="Clean;Rebuild"
/>
person Marlos    schedule 05.06.2013

Почему вы указываете DefineContstants = ProductVersion = XXXXXX?

Для DefineConstants вы не назначаете значения, либо константа (например, DEBUG или TRACE) определена, либо нет. Это свойство относится к переключателю компилятора C # / define. Что ты на самом деле пытаешься сделать?

Также я не уверен, что вы имеете в виду, когда говорите, что мой пост в блоге - это «взлом», весь смысл в том, что он был построен дважды.

Сайед Ибрагим Хашими

Моя книга: Внутри Microsoft Build Engine: использование MSBuild и Team Foundation Сборка

person Sayed Ibrahim Hashimi    schedule 01.07.2009
comment
Сказал, я действительно купил вашу книгу, потому что хотел лучше понять MSBuild. Я вернусь к вашему вопросу, когда закончу вашу книгу ;-) - person Sardaukar; 27.07.2009
comment
Wix перепрофилировал элемент DefineConstants как способ передачи пар имя-значение препроцессору, поэтому вы присваиваете значения. - person Rory MacLeod; 25.11.2010

Это сработало для меня и позволило мне передать элементы с еще не определенными парами ключ-значение. Не самый элегантный, но я не программист.

msbuild test.proj / p: PassedInProp = "ProductVersion = 45; rt = 669; wewanttoknow = test5"

<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
    <test Include="$([MSBuild]::Unescape($(PassedInProp)))" />
  </ItemGroup>
 <Target Name ="Test">
    <CreateItem Include ="$([System.String]::New('%(test.identity)').Split('=')[0])" AdditionalMetadata="value=$([System.String]::New('%(test.identity)').Split('=')[1])">
      <Output TaskParameter="Include" ItemName ="Test2"/>
    </CreateItem>
    <Message Text ="Key: %(test2.identity)  Value: %(test2.value)"/>
  </Target>
</Project>
person Piet    schedule 22.06.2012