Automation with Unreal Engine and Jenkins-CI
As developers, automation is a very powerful tool to have for many reasons. First and foremost, it ensures that the team almost always has access to the latest build without having to lose their precious time building it. Also, if a developer finds a bug, having a build independant of individual development configurations can tell us if the bug is in the depot or only on his machine. Finally, you can successively build for multiple configurations (x64, x86, Development, Shipping) and send them to the appropriate people.
This is why I absolutely wanted to have automation before even starting to work on Astral Tides. Even though I had never tried to make Jenkins work with Unreal Engine before, I knew it would save us a lot of time and problems down the road.
Since I didn't find a whole lot of guides combining Jenkins and Unreal on the web, I thought I would make one myself and let my fellow developers avoid the mistakes I made. The few guides I found were not bad by any means, but I felt like they were skipping over some basic stuff in favor of more advanced automation setups. They were also not explaining how to automatically compile the C++ code from Jenkins, which quickly becomes a problem as soon as you have more than one programmer working on the project.
This guide will therefore cover the following topics:
- Setup Jenkins
- Create a new Jenkins project
- Link Jenkins with Perforce (optional)
- Automatically Build Your Game
- Parameterize your build (optional)
Setupping Jenkins is really easy: all you need is a server you can install the service on. Even though Jenkins is compatible with Linux, we absolutely need a Windows server to build an Unreal Engine game for Windows. After you have installed the Windows Installer Package available over here and typed localhost:8080 in your favorite browser, you should see the following unlock page:
If you don't see that screen, it probably means that the service didn't start automatically. You can fix that by opening your task manager, going to the "Services" tab and making sure that the status is "Running":
Once you have successfully unlocked Jenkins, you will see the following customization page:
The option you choose is up to you, but for the sake of this tutorial, we will choose the default "Install suggested plugins" option. After the default plugins have all been installed, you will land on the "Create First Admin User" page:
Once again, it's up to you to create a custom admin user or use the default one. If you don't create a custom one, you will have to use the long password you entered earlier every time you need to execute admin actions.
Create a new Jenkins project
First of all, try to access your server's 8080 port directly from its IP address. If you see a "This site can't be reached" error, it's probably due to the 8080 port not being forwarded correctly. If you don't know how to forward a port, this is a good place to start.
Now, go back to localhost:8080 and locate the "New Item" option on the left:
After clicking on it, enter the name of your project in the "Enter an item name" field, select "Freestyle project" and click the "OK" button:
This is now the occasion to tell Jenkins which Source Code Management we wish to use and configure it accordingly:
You might have noticed that Perforce is not there yet. If you want to link Jenkins to Perforce, follow me to the next section. Otherwise, you can configure your own Source Code Management settings and then skip to the next part of this guide, Automatically Build Your Game.
Link Jenkins with perforce (optional)
This part is optional and only relevant if you are using Perforce. If you plan to use Git, Subversion or another source code management system, you can skip it entirely.
There are 2 plugins that we can use in order to link Jenkins with Perforce. The first (older) one is called Perforce Plugin, and the other (official) one is called P4 Plugin. For this guide, I chose to use the older of the two since it's still being updated regularly and I never had any problems with it, but you can use the official P4 Plugin and ignore this part. Like I said, it's entirely optional. You can install the Perforce Plugin directly from Jenkins by clicking on "Manage Jenkins" and then selecting the "Manage Plugins" option:
Now, if you switch to the "Available" tab and type "perforce" in the filter box, you should see the 2 plugins I mentioned earlier. Select "P4 Plugin" and click on the "Download now and install after restart" button:
Jenkins will proceed to install the plugin and, after you check "Restart Jenkins when installation is complete and no jobs are running", you will be able to finally select Perforce as your Source Code Management settings for the project you created earlier.
Now, go back to your project's configuration page, select "Perforce Software" and click on on the "Add" button next to "Perforce Credentials":
A new window will open, and you will have to fill the required fields with your Perforce server's credentials:
- P4Port: The address of your depot under the format hostname:port (usually hostname:1666). If you use SSL, don't put the ssl prefix (tick the "SSL connection" checkbox instead)
- Username: Your perforce username
- Password: Your perforce password
- Trust: The fingerprint of your server. This is only required if you use SSL
Click the "Test Connection" button and, if everything is OK, the "Success" message will appear. You can now go ahead and add this credential.
There are many ways to configure the remaining settings, but my suggestion is to make perforce pull everything from the root of the depot.
- Workspace name: The name of the workspace (folder) where you want Jenkins to store the depot files on your local disk. If the workspace doesn't exist, Jenkins will create it automatically when it starts a job. You can also use wildcards with the job number or perforce revision if you want a new workspace for every job, but this is out of the scope of this tutorial.
- View Mappings: Your depot-workspace link information under the format "//<depot_name>/..." "//<workspace_root>/..."
You can now save, go back to your project page and click the "Build Now" link on the left:
If everything was configured correctly, the build color will be blue and you will see the "Finished: SUCCESS" message at the end of the console output.
Congratulations, your Perforce setup is now over. It wasn't too hard, but people sometimes struggle with one or two things because they are not sure which plugin to download or what to put in the "View Mappings" field.
Automatically build your game
This is where we are going to do the bulk of the job and make our automation setup finally come to life. The first thing you need to specify is how often you want Jenkins to build a new version of your game, under the Build Triggers tab in the project configuration page. Usually, the popular option here is "Poll SCM", which means that jenkins will scan your depot every X seconds, minutes or hours and build only if it sees changes. You rarely want to build periodically since it will trigger a lot of useless builds, especially for smaller teams that don't submit a lot of changelists. For the polling schedule, even though Jenkins explains it well enough if you click on the question mark, it might still be confusing. In my own setup, to poll my SCM every 5 minutes, I used H/5 * * * *:
The Build section is where the magic happens since this is how Jenkins will be able to make a build from your source files. You will need to add 6 "Windows batch command" build steps:
Bellow are the 6 commands you need to add in order to make a successful build. The order is important!
rd /s /q temp
- The purpose of this command is simply to make sure that we have a clean folder to work with every time. This is important to put it at the very beginning since builds may sometimes fail in the middle or be canceled, so we would find ourselves with an existing temporary folder for subsequent builds (and we don't want that). It will be explained later on what to put in this folder.
"<absolute_path_to_unreal_engine_root>/Engine/Binaries/DotNet/UnrealBuildTool.exe" -projectfiles -project="%WORKSPACE%/<project_name>/<project_name>.uproject" -game -rocket -progress
- <absolute_path_to_unreal_engine_root> usually looks like C:/Program Files/Epic Games/<version> and the %WORKSPACE% variable will nicely translate the absolute path of your Jenkins project's workspace for you. This command uses the Unreal Build Tool in order to generate the project files and is the equivalent of right-clicking on the .uproject file and selecting Generate Visual Studio project files. I didn't find any official documentation on this, but I found it was a necessary step to make sure that the .sln exists and that all the prerequisites are up to date.
"<absolute_path_to_MSBuild_root>/<version>/Bin/MSBuild.exe" "<project_name>\<project_name>.sln" /t:build /p:Configuration="Development Editor";Platform=Win64;verbosity=diagnostic
- <absolute_path_to_MSBuild_root> usually looks like C:/Program Files (x86)/MSBuild and <version> is dependant on your version of Visual Studio. This command will make sure that the dll is always up to date. Again, I didn't find any documentation related to this and found the command by trial and error, but I found it to be a crucial step in order to successfully build the game. The reasoning behind it is that since the game's .dll is something you should never version control, Jenkins needs to build it every time it makes a build to make sure it's up-to-date.
"<absolute_path_to_unreal_engine_root>/Engine/Build/BatchFiles/RunUAT.bat" BuildCookRun -rocket -compile -compileeditor -installed -nop4 -project="%WORKSPACE%/<project_name>/<project_name>.uproject" -cook -stage -archive -archivedirectory="%WORKSPACE%/temp/Development/x64" -package -clientconfig=Development -ue4exe=UE4Editor-Cmd.exe -clean -pak -prereqs -distribution -nodebuginfo -targetplatform=Win64 -build -utf8output
- This is where most of the job is done. I am not going to explain every parameters in detail, but this command will essentially build the game by using the .dll we compiled earlier and all the assets and blueprints in your project in order to make an executable. If you want faster builds, you can remove the -clean parameter, but this is unsafe and you might still need to do a clean build regularly to make sure that you don't have leftovers. You can also change the target platform to target Win32 instead.
ren temp\Development\x64\WindowsNoEditor %P4_CHANGELIST%_<project_name>_Development_x64
- This step is completely optional, but it's nice to have and makes things easier to work with. Unreal puts your game in a WindowsNoEditor folder by default, so we simply rename that folder to a name that is directly linked to the revision of the SCM. I used %P4_CHANGELIST% because I'm working with Perforce, but it works for other SCM too. For Subversion, you can use %SVN_REVISION% instead.
"<absolute_path_to_7zip>/7z.exe" a -t7z builds/Development/%P4_CHANGELIST_%<project_name>/%P4_CHANGELIST_%<project_name>.rar "%WORKSPACE%/temp/development/x64/%P4_CHANGELIST%_<project_name>_Development_x64"
- For this command, you can choose the file archiver of your choice; it doesn't really matter. It only needs to be able to archive a folder and produce a .rar or a .zip. Note: If you are using 7zip, you need to provide the full, absolute path to the build folder (e.g. 114700_<project_name>). Otherwise, it will store all the relative folder hierarchy in the .rar archive and bury the executable 5 or 6 folders deep.
When you are done, this will give you a nice big block of commands:
Finally, we need to tell Jenkins where to find our artifact. An artifact is the final result of a build and it's what will be made available over the internet for people to download. In our case, it's the .rar archive we made earlier. We tell Jenkins where to find that artifact in the Post-build Actions section, right below the Build section we just finished with:
You will probably have a doesn't match anything error like me, and it's perfectly normal. This is because we use variables to set the name of the artifact, and Jenkins is freaking out because it doesn't know that. But don't worry; it will still work. Now, if you start a new build, it will hopefully be successful and Jenkins will give you something like this:
Hooray!! We are now essentially done. We can stop here and have a perfectly fine development build that will frequently poll our SCM and start a new build if necessary, or we can do even better. What if, with only one click, we were able to build a Shipping version of the game that will be optimized and ready to be sent to the public? This is exactly what we are going to do in the next section. Let's go!
Parameterize your build (optional)
This guide ended up being longer than I initially thought, but I hope it helped some developers who wanted to try automation with Unreal Engine and Jenkins for the first time. Don't hesitate to contact me on twitter @patvignola if you have any questions or comments for me.