如何在 Wix 工具集中排除文件
How to exclude files in Wix toolset
在为 heat.exe 收集文件时,我想从输入文件夹中排除扩展名为 .exe 的文件,因为它会首先获取文件夹中的所有文件。
下面是我的代码。
%WIX_PATH%\Heat.exe" dir "%input_folder%" -cg SourceProjectComponents
-dr INSTALLLOCATION -scom -sreg -srd -var var.BasePath -gg -sfrag
-var var.BasePath -out "%output_folder%\Output.wxs
PS:input_folder 由多个 .dll 和 .exe 文件组成。因此无法单独收集文件。
提前致谢。
您将需要使用 XSLT 转换。
像这样的东西应该适合你;只需在您的热命令行中包含 -t <Path to the xslt file>
。
此 XSLT 输出一个新的 XML 文件,其中包含输入的所有 XML 个节点,除非任何节点是具有 .exe
[=14= 的 <Component>
个元素] 元素。
RemoveExeComponentsTransform.xslt
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns="http://schemas.microsoft.com/wix/2006/wi"
version="1.0"
exclude-result-prefixes="xsl wix"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!--
Find all <Component> elements with <File> elements with Source="" attributes ending in ".exe" and tag it with the "ExeToRemove" key.
<Component Id="cmpSYYKP6B1M7WSD5KLEQ7PZW4YLOPYG61L" Directory="INSTALLDIR" Guid="*">
<File Id="filKUS7ZRMJ0AOKDU6ATYY6IRUSR2ECPDFO" KeyPath="yes" Source="!(wix.StagingAreaPath)\ProofOfPEqualsNP.exe" />
</Component>
Because WiX's Heat.exe only supports XSLT 1.0 and not XSLT 2.0 we cannot use `ends-with( haystack, needle )` (e.g. `ends-with( wix:File/@Source, '.exe' )`...
...but we can use this longer `substring` expression instead (see https://github.com/wixtoolset/issues/issues/5609 )
-->
<xsl:key
name="ExeToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.exe' ]"
use="@Id"
/> <!-- Get the last 4 characters of a string using `substring( s, len(s) - 3 )`, it uses -3 and not -4 because XSLT uses 1-based indexes, not 0-based indexes. -->
<!-- We can also remove .pdb files too, for example: -->
<xsl:key
name="PdbToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.pdb' ]"
use="@Id"
/>
<!-- By default, copy all elements and nodes into the output... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- ...but if the element has the "ExeToRemove" key then don't render anything (i.e. removing it from the output) -->
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'ExeToRemove', @Id ) ]" />
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'PdbToRemove', @Id ) ]" />
</xsl:stylesheet>
我遇到了同样的问题,我有很多文件需要包含到项目的 WXS 文件中,我编写了一个开源命令行应用程序来生成目录结构、文件和组件的 XML,同时忽略文件夹、扩展名、文件等通过 .wixignore 文件(格式类似于 .gitignore)。
你可以看看here。
如果您使用的是 WiX 工具集 4.0:
在您设置正确的命名空间之前,xsl 过滤器将无法工作 (xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
)
我一直处于从 3.11 升级到 4.0 的情况,我花了几个小时才找出为什么过滤器根本不起作用。在 VS 解决方案或命令行 (heat.exe) 版本中。
希望这对某人有所帮助
我喜欢 WiX,但 heat.exe
是一个使用起来比制作起来更难的实用程序。您可以编写自己的替代品。您只需枚举目录中的文件,然后输出一些 XML。下面是一些跳过 .pdb 文件的代码:
foreach (string file in Directory.EnumerateFiles(directoryName))
{
string extension = Path.GetExtension(file) ?? "";
if (extension.Equals(".pdb", OrdinalIgnoreCase)) continue;
string relativePath = GetRelativePath(wixProjectDirectoryName, file);
string guid = Guid.NewGuid().ToString("D").ToUpperInvariant();
stringBuilder.AppendLine($"<Component Id=\"Comp{fileName}\" Guid=\"{guid}\">");
stringBuilder.AppendLine($" <File Source=\"{relativePath}\" />");
stringBuilder.AppendLine("</Component>");
}
public static string GetRelativePath(string baseDirectoryName, string fileFullPath)
{
string[] absDirs = baseDirectoryName.Split('\');
string[] relDirs = fileFullPath.Split('\');
int len = absDirs.Length < relDirs.Length
? absDirs.Length
: relDirs.Length;
int lastCommonRoot = -1;
int index;
for (index = 0; index < len; index++)
{
if (absDirs[index] == relDirs[index]) lastCommonRoot = index;
else break;
}
if (lastCommonRoot == -1)
throw new ArgumentException("No common base");
var relativePath = new StringBuilder();
for (index = lastCommonRoot + 1; index < absDirs.Length; index++)
{
if (absDirs[index].Length > 0) relativePath.Append("..\");
}
for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++)
relativePath.Append(relDirs[index] + "\");
relativePath.Append(relDirs[relDirs.Length - 1]);
return relativePath.ToString();
}
这可能非常明显,但最简单的方法是使用 wix 中的预构建事件创建一个目录,其中只包含您需要的文件,然后 运行 heat.exe 在那上面。
在为 heat.exe 收集文件时,我想从输入文件夹中排除扩展名为 .exe 的文件,因为它会首先获取文件夹中的所有文件。
下面是我的代码。
%WIX_PATH%\Heat.exe" dir "%input_folder%" -cg SourceProjectComponents
-dr INSTALLLOCATION -scom -sreg -srd -var var.BasePath -gg -sfrag
-var var.BasePath -out "%output_folder%\Output.wxs
PS:input_folder 由多个 .dll 和 .exe 文件组成。因此无法单独收集文件。
提前致谢。
您将需要使用 XSLT 转换。
像这样的东西应该适合你;只需在您的热命令行中包含 -t <Path to the xslt file>
。
此 XSLT 输出一个新的 XML 文件,其中包含输入的所有 XML 个节点,除非任何节点是具有 .exe
[=14= 的 <Component>
个元素] 元素。
RemoveExeComponentsTransform.xslt
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns="http://schemas.microsoft.com/wix/2006/wi"
version="1.0"
exclude-result-prefixes="xsl wix"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!--
Find all <Component> elements with <File> elements with Source="" attributes ending in ".exe" and tag it with the "ExeToRemove" key.
<Component Id="cmpSYYKP6B1M7WSD5KLEQ7PZW4YLOPYG61L" Directory="INSTALLDIR" Guid="*">
<File Id="filKUS7ZRMJ0AOKDU6ATYY6IRUSR2ECPDFO" KeyPath="yes" Source="!(wix.StagingAreaPath)\ProofOfPEqualsNP.exe" />
</Component>
Because WiX's Heat.exe only supports XSLT 1.0 and not XSLT 2.0 we cannot use `ends-with( haystack, needle )` (e.g. `ends-with( wix:File/@Source, '.exe' )`...
...but we can use this longer `substring` expression instead (see https://github.com/wixtoolset/issues/issues/5609 )
-->
<xsl:key
name="ExeToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.exe' ]"
use="@Id"
/> <!-- Get the last 4 characters of a string using `substring( s, len(s) - 3 )`, it uses -3 and not -4 because XSLT uses 1-based indexes, not 0-based indexes. -->
<!-- We can also remove .pdb files too, for example: -->
<xsl:key
name="PdbToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.pdb' ]"
use="@Id"
/>
<!-- By default, copy all elements and nodes into the output... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- ...but if the element has the "ExeToRemove" key then don't render anything (i.e. removing it from the output) -->
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'ExeToRemove', @Id ) ]" />
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'PdbToRemove', @Id ) ]" />
</xsl:stylesheet>
我遇到了同样的问题,我有很多文件需要包含到项目的 WXS 文件中,我编写了一个开源命令行应用程序来生成目录结构、文件和组件的 XML,同时忽略文件夹、扩展名、文件等通过 .wixignore 文件(格式类似于 .gitignore)。
你可以看看here。
如果您使用的是 WiX 工具集 4.0:
在您设置正确的命名空间之前,xsl 过滤器将无法工作 (xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
)
我一直处于从 3.11 升级到 4.0 的情况,我花了几个小时才找出为什么过滤器根本不起作用。在 VS 解决方案或命令行 (heat.exe) 版本中。
希望这对某人有所帮助
我喜欢 WiX,但 heat.exe
是一个使用起来比制作起来更难的实用程序。您可以编写自己的替代品。您只需枚举目录中的文件,然后输出一些 XML。下面是一些跳过 .pdb 文件的代码:
foreach (string file in Directory.EnumerateFiles(directoryName))
{
string extension = Path.GetExtension(file) ?? "";
if (extension.Equals(".pdb", OrdinalIgnoreCase)) continue;
string relativePath = GetRelativePath(wixProjectDirectoryName, file);
string guid = Guid.NewGuid().ToString("D").ToUpperInvariant();
stringBuilder.AppendLine($"<Component Id=\"Comp{fileName}\" Guid=\"{guid}\">");
stringBuilder.AppendLine($" <File Source=\"{relativePath}\" />");
stringBuilder.AppendLine("</Component>");
}
public static string GetRelativePath(string baseDirectoryName, string fileFullPath)
{
string[] absDirs = baseDirectoryName.Split('\');
string[] relDirs = fileFullPath.Split('\');
int len = absDirs.Length < relDirs.Length
? absDirs.Length
: relDirs.Length;
int lastCommonRoot = -1;
int index;
for (index = 0; index < len; index++)
{
if (absDirs[index] == relDirs[index]) lastCommonRoot = index;
else break;
}
if (lastCommonRoot == -1)
throw new ArgumentException("No common base");
var relativePath = new StringBuilder();
for (index = lastCommonRoot + 1; index < absDirs.Length; index++)
{
if (absDirs[index].Length > 0) relativePath.Append("..\");
}
for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++)
relativePath.Append(relDirs[index] + "\");
relativePath.Append(relDirs[relDirs.Length - 1]);
return relativePath.ToString();
}
这可能非常明显,但最简单的方法是使用 wix 中的预构建事件创建一个目录,其中只包含您需要的文件,然后 运行 heat.exe 在那上面。