12

There are often many swiches to enable/disable when trying to build a project that uses CMake.

How do you store the build settings made by some user to make a build reproduceable on another machine? Is there some kind of export functionality or do you just copy the build (cache) folder?

Beachwalker
  • 7,685
  • 6
  • 52
  • 94
  • 2
    I would set default values in the cmake files. I doubt there is a general approach, and I do not think copying caches around is a good idea: what cached variables often contain are local path. Good question though! – Antonio Jul 11 '13 at 09:34
  • @Antonio But I don't want to change the CMakeLists.txt of 3rd party dependencies. I can change the settings through the command line but what is a good (not to say the best) practice to keep them and start an automized build? – Beachwalker Jul 11 '13 at 13:44
  • @Antonio Your hint with .cmake files given with parameter -C works. Didn't knew that param. Thanks – Beachwalker Jul 11 '13 at 16:00

3 Answers3

17

There is an option to pre-load a script for populating the cache file with cmake using

cmake -C <initial-cache>

The initial-cache is a file containing variables set in the following way, e.g. for the install prefix:

set(CMAKE_INSTALL_PREFIX "/my/install/prefix" CACHE PATH "")

Then just pass this file while populating the cache with cmake. Easy, but I didn't know that and found no good sample. As a plus, this is an platform independent way instead of writing a script or batch file.

I create a separate script folder next to the sources out of the generated out-of-source build folder. My files containing the settings are stored there for each lib/executable to build.

You can put all the settings into a separate file and at the end of the day there are just a few calls left:

cmake -E make_directory build/somelib
cmake -E chdir build/somelib cmake -C ../../script/cmake/somelib.cmake ../../source/somelib/src
cmake --build build/somelib --target install

Simple, isn't it?

Automatically generate initial-cache file:

If you are on a *nix system you can run the following inside your build dir:

cmake -N -LA | tail -n+2 | sed -r 's/([A-Za-z_0-9]+):([A-Z]+)=(.*)/set(\1 "\3" CACHE \2 "")/' >cmake-init.txt

On Windows, something like the following cmake script should work:

# list all cache variables
# this should be run in your build dir

set(filename ${CMAKE_ARGV3})
message(STATUS "Writing to ${filename}")
if(NOT filename)
    message(FATAL_ERROR "Must provide an output filename")
    return()
endif()

execute_process(COMMAND "${CMAKE_COMMAND}" "-N" "-LA" OUTPUT_VARIABLE cacheVars)
string(REPLACE "\n" ";" cacheVars ${cacheVars})
file(WRITE ${filename} "")

foreach (variable ${cacheVars})
    string(REGEX REPLACE "([A-Za-z_0-9]+):([A-Z]+)=(.*)$" "set(\\1 \"\\3\" CACHE \\2 \"\")\n" output ${variable})
    if(CMAKE_MATCH_0)
        file(APPEND ${filename} ${output})
    endif()
endforeach()

Save it to, e.g., get_cache_vars.cmake and run it like:

cd <your build-dir>
cmake -P path\to\get_cache_vars.cmake <outputfile.txt>
Beachwalker
  • 7,685
  • 6
  • 52
  • 94
  • 2
    Nice solution, thanks. But unfortunately there is no way to create this cache by simple way. For example: `echo 'cmake -DOPTION1=val ' > build.sh && bash build.sh` is much simpler... It will be great if cmake maintainers will create something like `cmake - -DOPTION1=val ` - it will be much more clear. – avtomaton Jan 26 '16 at 20:11
  • I had some CMake variables with `.` characters in it. I used `sed -r 's/([A-Za-z_0-9\.]+):([A-Z]+)=(.*)/set(\1 "\3" CACHE \2 "")/'` instead – Benjamin Apr 10 '18 at 15:40
2

The best way to replicate this on another machine is to use -DSETTING=TRUE/FALSE args.

If you have a LOT of these options differing from the default you can build your cmake call using a script.

Ex:

#!/bin/bash
cmake -G "Unix Makefiles \
   -DOPTION1=TRUE
   -DOPTION2=FALSE

Distribute the helper bash script to the other machine.

JonnyRo
  • 1,844
  • 1
  • 14
  • 20
  • 3
    I already knew this way but where to store the command line values entered during the call to make this reproduceable? Bash script... does not work for other environments like Windows, so this is no platform independen solution. I've found an option to pre-load a script to populate the cache file with cmake -C . These files contains set() calls instead of commandline vars and seems a little bit more easier to handle for many settings in a platform independent way. Nevertheless, +1 and thanks for your answer. – Beachwalker Jul 11 '13 at 15:58
1

CMake 3.19 added support for project- and user-level preset files. For example, if CMakeUserPresets.json in your top-level source directory contained the following

{
  "version: 4,
  "configurePresets": [
    {
      "name": "localdev",
      "displayName": "Local development",
      "description": "Local development",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "ENABLE_CCACHE": "ON",
        "GO_FASTER": "ON",
        "MY_LIB_INCLUDEDIR": "/usr/local/my-lib/include",
        "MY_LIB_LIBDIR": "/usr/local/my-lib/lib",
      },
      "environment": {
        "CMAKE_PREFIX_PATH": "/usr/local/foo"
      }
    }
  ]
}

you could use the "localdev" presets by running cmake --preset localdev. At the time of this writing the format is still changing with each version, but it's more flexible and comprehensive that the -C <initial cache> option.

Gerald Combs
  • 1,374
  • 10
  • 12