目标
我们希望使用 MSBuild 和 Jenkins 上的 MSBuild 插件为我们的 Unity 项目设置自动构建。
我的配置
相应的构建步骤如下
Build a Visual Studio project or solution using MSBuild
MSBuild Version VisualStudio-MSBuild-15
MSBuild Build File E:\Jenkins\workspace\000_BUILD\<MyProjectName>
Command Line Arguments /m /p:Configuration=Release /p:Plattform=x86
Pass build variables as properties [x]
Do not use chcp command [ ]
我使用的是 VisualStudio 2017 安装中的 MSBuild。
这最终会生成一个批处理命令,例如
cmd.exe /C " chcp 1252 & E:\VisualStudio\MSBuild\15.0\Bin\msbuild.exe /m /p:Configuration=Release /p:Platform=x86 "E:\Jenkins\workspace\000_BUILDS\MY_PROJECT\My Project.sln" " && exit %%ERRORLEVEL%%
我这样说只是为了表明我的问题并不直接依赖于詹金斯。
我的问题:
我收到 72 条错误消息,其中大多数看起来像(德语翻译)
2>Properties\AssemblyInfo.cs(8,12): 错误 CS0246: 未找到类型或命名空间“AssemblyTitleAttribute”(可能缺少使用指令或 Assemblyreference)。
其中一些人还喜欢(德语翻译)
2>Properties\AssemblyInfo.cs(9,32): 错误 CS0518: 未定义或导入预定义类型“System.String”。
也许是一个暗示? 如果我直接在 VisualStudio 中构建同一个项目(从 git 中提取完成后我停止了 jenkins 作业),它会引发 2 个关于一些已弃用调用的警告,但 AppPackage 构建时没有任何错误。
奇怪的是:
在 VisualStudio 中成功构建项目后,我还可以从命令行使用 MSBuild 构建项目,获得相同的输出(2 个警告但没有错误)并构建我的 AppPackage。
问题
我做错了什么?
VisualStudio 在 GUI 中的作用与 MSBuild 在命令行中的作用有何不同?
我是否可能错过了 MSbuild 的某个步骤或选项?
答案1
问题是在使用 MSBuild 构建之前我没有恢复 Nuget-Packages。 (在 GUI 中打开 Visual-Studio 似乎会自动执行此步骤。)
因此,现在有了从 Unity 项目到 Holo-Lens 应用程序包的完整解决方案,它最终对我有用:
创建 Unity CommandLineBuild 包
首先,为了能够通过命令行构建 Unity 项目,您需要一个特殊的类。
这必须放置在/Assets/Editor
您的项目中:
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System;
namespace JENKINS
{
public class AutoBuilder : ScriptableObject
{
static string[] SCENES = FindEnabledEditorScenes();
// Use real app name here
/* Anyway the App will have the name as configured within the Unity-Editor
This Appname is just for the Folder in which to Build */
static string APP_NAME;
static string TARGET_DIR;
[MenuItem("Custom/CI/Windows Mixed Reality Build (UWP)")]
public static void PerformWindowsMixedRealityBuild()
{
APP_NAME = GetArg("-appName");
TARGET_DIR = GetArg("-buildFolder");
Debug.Log("Jenkins-Build: APP_NAME: " + APP_NAME + " TARGET_DIR: " + TARGET_DIR);
GenericBuild(SCENES, TARGET_DIR + "/" + APP_NAME, BuildTargetGroup.WSA, BuildTarget.WSAPlayer, BuildOptions.AllowDebugging);
}
private static string[] FindEnabledEditorScenes()
{
List<string> EditorScenes = new List<string>();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
if (!scene.enabled) continue;
EditorScenes.Add(scene.path);
}
return EditorScenes.ToArray();
}
private static void GenericBuild(string[] scenes, string app_target, BuildTargetGroup build_target_group, BuildTarget build_target, BuildOptions build_options)
{
EditorUserBuildSettings.SwitchActiveBuildTarget(build_target_group, BuildTarget.WSAPlayer);
string res = BuildPipeline.BuildPlayer(scenes, app_target, build_target, build_options);
if (res.Length > 0)
{
throw new Exception("BuildPlayer failure: " + res);
}
}
/**
* Get Arguments from the command line by name
*/
private static string GetArg(string name)
{
var args = System.Environment.GetCommandLineArgs();
for (int i = 0; i < args.Length; i++)
{
if (args[i] == name && args.Length > i + 1)
{
return args[i + 1];
}
}
return null;
}
}
}
但是由于您不想将此包导入到您的每个项目中,所以让 Jenkins 动态导入它。
并将其导出为AutoBuilder.unityproject
:
构建步骤
和对我来说效果不佳Unity-Plugin
,MSBuild-Plugin
所以我在专用的批处理文件中执行每个步骤。
1.将AutoBuild.unitypackage导入到项目中
首先我们需要将之前创建的unitypackage导入到实际克隆的项目中。
跑步
<\Path\To\Your\Unity\Installation\>Editor\Unity.exe -quit -batchmode -username 'xxxxxxxxxxxxx' -password 'xxxxxxxxxxx' -logFile uniytImportLog.txt -importPackage E:\UnityPackage\AutoBuilder.unitypackage
-quit
:导入完成后退出 Unity-batchmode
:不要打开/加载 GUI 并在出现任何错误时立即退出 1- (可选)
-username
和-password
:提供您的凭证,以便 Unity 可以查找您的许可证(如果需要) - (可选)
-logFile
:将输出写入日志文件(因为批处理模式下的 Unity 不会显示它!) -importPackage
:最后告诉 Unity 要做什么;在本例中导入我们的 unitypackage 文件(将其更改为您存储的位置AutoBuilder.unitypackage
)
2. 运行 Unity-Build 生成 Visual-Studio 解决方案 (.sln)
现在该项目已准备好通过命令行构建到.sln
解决方案中。
跑步
<\Path\To\Your\Unity\Installation\>Editor\Unity.exe -quit -batchmode -username 'xxxxxxxxxxxxx' -password 'xxxxxxxxxxx' -logFile uniytBuildLog.txt -buildTarget wsaplayer -executeMethod JENKINS.AutoBuilder.PerformWindowsMixedRealityBuild -appName %JOB_NAME% -buildFolder %WORKSPACE%\00_BUILD
-quit
:导入完成后退出 Unity-batchmode
:不要打开/加载 GUI 并在出现任何错误时立即退出 1- (可选)
-username
和-password
:提供您的凭证,以便 Unity 可以查找您的许可证(如果需要) - (可选)
-logFile
:将输出写入日志文件(因为批处理模式下的 Unity 不会显示它!) -buildTarget
:在加载项目之前切换到相应的构建目标。对于应用程序包,例如wsaplayer
-executeMethod
:最后告诉 Unity 要做什么;在本例中,执行我们之前导入的 AutoBuilder 类中的方法-appName %JOB_NAME%
和-buildFolder %WORKSPACE%\00_BUILD
:我们调用的方法需要/需要来自命令行的参数。-appName
听起来有点误导,因为它实际上只是 Unity 将构建到的子文件夹。%JOB_NAME%
是实际作业名称的全局 Jenkins 环境变量。-buildFolder
是 Unity 将构建到的主文件夹。%WORKSPACE%
是实际作业工作区文件夹的全局 Jenkins 环境变量。
笔记
在进行下面最后两个步骤之前,你必须知道,.sln
在Unity-Build之后文件是如何被调用的。
我将假设从这里开始类似的内容YourProject.sln
存储到变量中,App_Name
因为它是在 Unity 中定义的:
转至Edit-> Project Settings->Player Settings
并改变Product Name
3.恢复Nuget-Packages(这主要是我之前遗漏的步骤)
要恢复 nuget-packages(Visual-Studio 通常会在 GUI 中打开解决方案时自动执行此操作),请运行
cmd.exe /C " chcp 1252 & <Path\To\Your\Visual-Studio\Installation>\MSBuild\15.0\Bin\msbuild.exe /m /t:restore /p:Configuration=Release /p:Platform=x86 "%WORKSPACE%\00_BUILD\%JOB_NAME%\%App_Name%" "
/m
:指定构建时要使用的最大并发进程数。如果不包含此开关,则默认值为 1。如果包含此开关而不指定值,则 MSBuild 将使用计算机中最多数量的处理器。/t
:构建项目中指定的目标。/p
:设置或覆盖指定的项目级属性,其中 name 是属性名称,value 是属性值。(对于 Holo-Lens 则是Configuration=Release
和Plattform=x86
)WORKSPACE
:Jenkins 的实际作业工作区文件夹的全局环境变量00_BUILD
:我们将其作为参数传递-buildFolder
给 Unity 构建步骤。JOB_NAME
:Jenkins 的全局环境变量,用于指定实际的作业名称App_Name
:如前所述,构建的 Visual-Studio-Solution 的名称(.sln
)
这只会进行恢复,而不会构建项目。
4.使用 MSBuild 构建最终的 App-Package
我不喜欢MSBuild-Plugin
jenkins,所以我将其放在批处理文件中,并使用之前插件生成的命令。但在批处理文件中执行此操作让我在定义目标文件等方面具有更大的灵活性。
cmd.exe /C " chcp 1252 & <Path\To\Your\Visual-Studio\Installation>\MSBuild\15.0\Bin\msbuild.exe /m /t:build /p:Configuration=Release /p:Platform=x86 "%WORKSPACE%\00_BUILD\%JOB_NAME%\%App_Name%" "
/m
:指定构建时要使用的最大并发进程数。如果不包含此开关,则默认值为 1。如果包含此开关而不指定值,则 MSBuild 将使用计算机中最多数量的处理器。/t
:构建项目中指定的目标。/p
:设置或覆盖指定的项目级属性,其中 name 是属性名称,value 是属性值。(对于 Holo-Lens 则是Configuration=Release
和Plattform=x86
)WORKSPACE
:Jenkins 的实际作业工作区文件夹的全局环境变量00_BUILD
:我们将其作为参数传递-buildFolder
给 Unity 构建步骤。JOB_NAME
:Jenkins 的全局环境变量,用于指定实际的作业名称App_Name
:如前所述,构建的 Visual-Studio-Solution 的名称(.sln
)
完成后,你现在应该有最终的应用程序包
%WORKSPACE%\000_BUILD\%JOB_NAME%\%App_Name%\AppPackages