11

I have a CMake sample project that I would like to build on Jenkins running on Ubuntu 15.10. I have installed:

https://wiki.jenkins-ci.org/display/JENKINS/CMake+Plugin

And created two build steps:

  1. Run CMake to generate makefiles
  2. Run make all from the build dir

enter image description here

It works fine:

[build] $ cmake -G "Unix Makefiles" -D CMAKE_BUILD_TYPE=Debug /var/lib/jenkins/workspace/cmake-test/cmake-gtest/src
-- Configuring done
-- Generating done
-- Build files have been written to: /var/lib/jenkins/workspace/cmake-test/cmake-gtest/build
[build] $ /usr/bin/make
[  4%] Built target libfoo
[  9%] Built target libbar
[ 14%] Built target myApp
[ 52%] Built target gmock
[ 90%] Built target gtest
[100%] Built target testfoo
[cmake-test] $ /bin/sh -xe /tmp/hudson1792271459427590561.sh
+ cd cmake-gtest/build
+ make all
[  4%] Built target libfoo
[  9%] Built target libbar
[ 14%] Built target myApp
[ 52%] Built target gmock
[ 90%] Built target gtest
[100%] Built target testfoo
Finished: SUCCESS

But is this the recommended approach for using CMake in a CI/Jenkins setup?

Currently, my CMake/Jenkins build will on each push; 1) generate the makefiles, 2) build the project.

I am a bit worried that the first step 1) generate makefiles would eat up build time and it does not really seem optimal to do this step on each push. Especially since I would not expect to change CMakeLists.txt files that often, but when they change newly generated files should, of course, be used.

Is the above approach common practices that I just have to get used to or have I missed something?

Yoon5oo
  • 496
  • 5
  • 11
u123
  • 15,603
  • 58
  • 186
  • 303
  • Does the "generating makefile" take sufficient time to worry about? Whilst it may not be changing very often, having a separate step or messing up the build when there are changes is really not a nice solution ... – Mats Petersson Feb 27 '16 at 17:19
  • Yes that is also my concern, better safe than sorry, a solution would be to make sure to break down my application into smaller faster parts when it grows. Regading the two build steps above, 1) cmake/generate, 2) run make all is there someway to do that as part of the code generation step? Or are they completely independent and should be treated like that? – u123 Feb 27 '16 at 17:45
  • I'm not quite sure what you are asking. My attitude in general, is to "go with the simplest solution that is sufficient to solve the current problem", and not complicate something until you actually have a good reason. I run three different jobs on my Jenkins system (at home): "Build + run all tests with clang++", "Build + run all tests with g++" - these check every 15 minutes for new commits in the git repo, and the third is to download the version of LLVM and my code, and build it all together based on a build script in the project - once a night. – Mats Petersson Feb 27 '16 at 17:57
  • From the above screenshot I have two build steps: 1: generate makefiles, 1: run make. I was just wondering if it could be done in one step and if cmake has some post step command for doing the actual build after the make files have been generated. – u123 Feb 27 '16 at 18:00
  • Seems sensible, of you need to do both anyway. The only advantage of having two parts is if it takes long enough that starting another build of the code before the test finishes, or some such. – Mats Petersson Feb 27 '16 at 18:10
  • If you have some variables in your CMakeLists.txt (like versioning variables) then you need to generate your make file each time to update your versioning variables – SdSaati Sep 16 '18 at 11:22

2 Answers2

6

Yes, you can do it in one step.

For example, in my Jenkins environment, when building the Ubuntu jobs I use the CMake plugin for the whole compilation, as it allows multiple build tool invocations.

My screenshot at the bottom of this post is of a CMake step in a job (I use Ninja instead of Unix Makefiles, but the effect is the same).

I use two build invocations:

  • Blank - equivalent to calling ninja or make in a shell,
  • Install - equivalent to calling DESTDIR=. ninja install.

If I wanted to build additional targets from the makefiles, I could just add extra invocations to this step.

Note that in your screenshot you have a blank invocation in the configuration. This will already be calling make, and as confirmed by your log output, you are in fact compiling your project twice, because of your manual call to make all in the following step.

You can remove your shell step and your project will still build.


Regarding your question on best practices and regenerating CMake, I refer you to this article on Jenkins Best Practices where it states:

To ensure a build can be reproducible, the build must be a clean build, which is built fully from Source Code Control. This practice also implies that all code including third-party jars, build scripts, release notes, etc. must be checked into Source Code Control.

Note that I also check "Clean Build" in my CMake step, so that the entire CMake workspace is wiped out and the project is generated from scratch for every build. This ensures there are no issues caused by stale cache variables, etc.

Screenshot of a CMake step in one of my jobs: Jenkins/CMake config

badgerr
  • 7,802
  • 2
  • 28
  • 43
  • I don't see why this is not accepted (Edit: I poked the user, not it's the accepted one). Anyway, what is a blank invocation? Help me see what do you see in OP's screenshot... :) – gsamaras Nov 16 '18 at 10:02
1

I am not even sure you need this plugin. AFAIR the plugin webpage it is only useful if you want Jenkins to use a specific CMake version, or you want a GUI for which CMake variables you might want to set. I just execute CMake from the command line.

For your second part of the question, If you change CMakeLists.txt, the Makefile will automatically rerun CMake, so strictly speaking it is not necessary to run CMake each time. But on the other side, CMake configuring is quite fast and most likely takes less time than compiling.

Yoon5oo
  • 496
  • 5
  • 11
arved
  • 4,401
  • 4
  • 30
  • 53
  • 1
    This is exactly what I was thinking, but I am not sure if it's correct, so no upvote. Should we use a plugin when we want to to do CI with a C++ project or just call `make` or whatever from the command line? It would be nice if you could expand on that with some references. – gsamaras Nov 16 '18 at 09:55