Monthly Archives: January 2016

Native Windows build jobs on Jenkins

This may not be the most frequent use case, but Jenkins CI server is perfectly capable of running native C/C++ build jobs on Windows. That is, build jobs that use the native platform’s tools, i.e. Visual Studio or possibly other C/C++ compiler suite.

From the user’s perspective, building is a straightforward activity:

  • Launch Visual Studio Command Prompt, aka. vcvarsall.bat.
  • Navigate to your source and invoke MSBuild on the solution,
  • or nmake if you are hardcore and use Makefiles.
    • If you are using a third-party build system such as CMake or Qt’s qmake, you first run that to generate the Makefile.

This translates pretty well into a Freestyle Jenkins build job. You could put all the above mentioned steps into a single Windows batch command build step. But you may prefer one of Jenkins’ plugins for the build system of choice, as these provide a nicer interface than a plain batch file and sometimes more options and allow crazy build scenarios*.

The trouble with Jenkins build plugins is they don’t provide a way to setup the environment for the native build tools, i.e. they don’t call vcvarsall.bat. Now you cannot just add a pre-build step and call vcvarsall.bat in it. That would only setup the environment inside the pre-build step. As each build step starts with a fresh environment, the main build step will be unaffected by it. One option is to run vcvarsall.bat for the logged-in user and also run Jenkins under this user. But that would be severely limiting. What if you want to run one 32-bit build job and another 64-bit job? Also this approach will not work if you run Jenkins as a Service.

Fortunately there is a simple way to apply the effect of vcvarsall.bat over the whole build job. After all, vcvarsall.bat only sets some environment variables – a whole lot of them. This neat little trick uses the EnvInject Jenkins Plugin to record the env variables set by vcvarsall.bat (and possibly other environment setup scripts you may use) and apply them to the whole build job.

  • Check the “Prepare an environment for the run” option.
  • In the “Script content” enter something like this:
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86
set > C:\jenkins\workspace\
  • The last line “set > …” saves all the environment variables set by the previous scripts to the given file.
  • Enter this file name into the “Properties File Path” field.

And voila, the build environment is set for the entire build job.

*) In our specific case, which I admit is a little bit unusual we use Maven as the topmost build tool. This build workflow has been adapted from the Java world and works surprisingly well in the C++ world, too. Maven provides packaging and versioning facility (for which there is no cross-platform standard in the C++ world at this time). Maven’s pom.xml invokes Ant’s build.xml, which describes the build steps in concrete terms. Ant invokes qmake, then nmake and optionally other tools such as Doxygen and finally zips the output to a neat self-contained package. The resulting zip package is attached as Maven artifact and deployed to the client’s Nexus server. Additionally unit tests are run (also as a Maven build phase) and test results are published and visualized by Jenkins.