CMake command-line help for user options - cmake

I have some options in my CMakeLists.txt file that can be selected with -D on the command line, like this:
# Set some options the user may choose
OPTION(USE_MPI "Use the MPI library for parallelization" OFF)
OPTION(USE_OPENMP "Use OpenMP for parallelization" OFF)
OPTION(TESTING "Enable testing of both Fortran and Python code" OFF)
OPTION(PYTHON_TOOLS "Build the python helper tools" OFF)
OPTION(BUILD_DOCS "Build the documentation; turns on PYTHON_TOOLS" OFF)
and I can activate one of them with something like
$ cmake . -DUSE_MPI=ON
Sometimes I forget what the options I have chosen are. It would be nice if there was some sort of -h flag I could use to display those on the command line in an automated way (in the style of python's argparse).
Is there an automated way to generate help documentation for a particular CMakeLists.txt, and/or call that help with some sort of -h or --help flag? I'm looking for something that will give me this behavior:
$ cmake . --help
USE_MPI - Use the MPI library for parallelization (Default: OFF)
USE_OPENMP - Use OpenMP for parallelization (Default: OFF)
TESTING - Enable testing of both Fortran and Python code (Default: OFF)
PYTHON_TOOLS - Build the python helper tools (Default: OFF)
BUILD_DOCS - Build the documentation; turns on PYTHON_TOOLS (Default: OFF)
If there is no automated way, is there at least an easy way to pass --help or -h to CMakeLists.txt so that I can manually write a help message?

I think the closest to what you're looking for is the -L command line arg. Running cmake . -LH should configure your project, then output all your cached, non-advanced variables along with their help strings.
The i arg also allows you to see the current values of options, but this actually runs cmake in command line "wizard mode" - it configures the project, asking you to set/update each variable one at a time.

Related

How to check for internet connection with CMake? (automatically prevent fails if there is non)

For example, when using the ExternalProject or FetchContent module additional data can be downloaded and used within CMake. If there is no internet connection these modules fail and CMake does not finish configuration no matter if downloading was done successful once. There are flags like FETCHCONTENT_FULLY_DISCONNECTED or FETCHCONTENT_UPDATES_DISCONNECTED to prevent checks and therefore prevent failing. But these have to be set manually. (related question: cmake: external project update and a work offline).
Is it possible to check if there is a connection to afterwards set FETCHCONTENT_FULLY_DISCONNECTED automatically? How to do that? Or are there alternative ways to prevent failing of CMake if there is no internet connection?
In our case we are downloading libraries with FetchContent and than use for example find_package to make them available. Our workflow does currently not include manual adjusting of CMake Options/Variables and we do not want to add that. CMake gets all needed options by the IDEs we use, e.g. CMAKE_BUILD_TYPE or custom flags. We would need to double the targets to have a non-connection version for each existing combination. Therefore this semi-manual approach is also not feasible.
I found a workaround to check for a connection. Although it will not work all the time its good enough for us. I'ts based on CMake's execute_process and the questions https://stackoverflow.com/a/27590444/9909548, https://stackoverflow.com/a/6357629/9909548 and https://superuser.com/q/1406089.
execute_process(
COMMAND ping www.google.com -n 2 -w 1000
RESULT_VARIABLE NO_CONNECTION
)
if(NO_CONNECTION GREATER 0)
set(FETCHCONTENT_FULLY_DISCONNECTED ON)
else()
set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
endif()
Hope its correct to add this as an answer although I will not accept it, rather than adding it to the question as a research result.
Modified answer that works with recent cmake and more platforms:
if(MSVC)
execute_process(
COMMAND ping www.google.com -n 2
ERROR_QUIET
RESULT_VARIABLE NO_CONNECTION
)
else()
execute_process(
COMMAND ping www.google.com -c 2
ERROR_QUIET
RESULT_VARIABLE NO_CONNECTION
)
endif()
if(NOT NO_CONNECTION EQUAL 0)
set(FETCHCONTENT_FULLY_DISCONNECTED ON)
message(WARNING "Fetch offline mode: requires already populated _deps")
else()
set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
endif()

How to define a variable during build with cmake?

I would like to define a CMake variable BUILD_TIME_VAR in CMakeLists.txt:
computed with a python script during build phase
I can then access its content with ${VAR}
In other words, the equivalent during build phase of:
execute_process(COMMAND bash -c "python $SCRIPT $FILE" OUTPUT_VARIABLE GEN_TIME_VAR)
The variable is then used to generate a file which is a dependency to make binaries.
The goal is to make the code more easy to read since otherwise, the computation occur several times.
Rather than calling n times, the python script, to compute BUILD_TIME_VAR, I would like to use the script once, to factor the code in this way:
if(expression_1)
add_custom_command(OUTPUT foo
COMMAND cmd_1(${BUILD_TIME_VAR}))
...
elseif(expression_2)
# elseif section.
add_custom_command(OUTPUT foo
COMMAND cmd_2(${BUILD_TIME_VAR}))
...
else(expression_n)
# else section.
add_custom_command(OUTPUT foo
COMMAND cmd_n(${BUILD_TIME_VAR}))
...
endif(expression)
add_custom_target(${BINARY} ALL
DEPENDS foo)
Thanks you for your help.
If I understand your question correctly, you're effectively trying to create a "build-time variable." That is something that the build tool (actually all the build tools supported by CMake) would have to support. I know of no such functionality in build tools (make, ninja, VS, ...), and hence of no support for such a thing in CMake either.
You could emulate this by writing the results to a file and reading that file in all subsequent build steps using it.
I believe you've misinterpreted the role of CMake. In short, CMake generates build files for the back-end system of your choice (Make, ninja, etc.). This is concisely reviewed here, where the configure/generate step is briefly documented along with how it precedes the actual build step.
It's not clear what you're trying to achieve exactly, but maybe defining custom commands and using their outputs to link them to custom targets for further dependency chaining (see DEPENDS here) might be helpful, e.g.
cmake_minimum_required(VERSION 3.11)
project(foobar)
set(FOO_FILES "foo.txt")
add_custom_command(OUTPUT ${FOO_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
COMMAND echo hello >> ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Creating ${FOO_FILES}"
VERBATIM)
add_custom_target(foo DEPENDS ${FOO_FILES})
set(BAR_FILES "bar_dummy.txt") # this is only use to link the custom command to the corresponding custom target
add_custom_command(OUTPUT ${BAR_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${BAR_FILES}
COMMAND cat ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Displaying ${FOO_FILES}"
VERBATIM)
add_custom_target(bar DEPENDS ${BAR_FILES})
add_dependencies(bar foo)
However, you might need to consider the probability of going against the tool, and thus, it might be clearer to have a required step prior to the configuration of your project.

CMAKE view possible options

The CMake option command allows users to define variable from command line:
option(<option_variable> "help string describing option"
[initial value])
I am wondering how to view all such available options. I.e. I am looking for something like ./configure -h where it typically shows a summary all possible configuration a user can tweak.
There is no such feature for a simple reason - command option is not always evaluated. E.g.:
if(WIN32)
option(WIN32_TESTS "Build windows specific tests" OFF)
endif()
So you need to run cmake anyway, then you can view options in CMakeCache.txt file directly or
using cmake-gui (or ccmake).
Of course you can print the messages manually:
message("Build configuration:")
message(" C++ flags: ${CMAKE_CXX_FLAGS}")
if(WIN32)
message(" WIN32_TESTS: ${WIN32_TESTS}")
endif()

Silence custom command depending on CMAKE_VERBOSE_MAKEFILE

I've a custom command in my CMake script which generates a lot of output. I'd like to take advantage of CMAKE_VERBOSE_MAKEFILE so I can decide if I want to see this output or not.
Is there a common way for doing this?
The one way I see is to redirect output to /dev/null depending on this CMake's flag, but what about Windows and other OSes?
Is there a portable or recommended way? What about default rules for C/C++ compiling commands?
Technically speaking, CMAKE_VERBOSE_MAKEFILE exists for the purpose of hiding and showing command lines, not command output.
If I had to do this, I would use a custom variable.
But on the main topic, here is how you should do:
if (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command")
else (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command" OUTPUT_QUIET)
endif (COMMAND_VERBOSE)
This is the most portable way to do so.
There is also an ERROR_QUIET flag, however it is a bad idea to disable error messages, else the user would be unable to see why the command failed if it failed.
If you are using add_custom_command or add_custom_target instead, such a flag does not exist.
You'll have to provide a manual redirection to /dev/null (Unix), or NUL (Windows).
As SirDarius pointed out, execute_process() has an option to silence tool output, while add_custom_command() / add_custom_target() do not.
But there is a way to work around this: By putting the actual call to your tool in a separate CMake script wrapper, using execute_process() with OUTPUT_QUIET enabled or disabled depending on a switch:
# mycustom_command.cmake
if ( OUTPUT )
execute_process( COMMAND mycustom_command )
else()
execute_process( COMMAND mycustom_command OUTPUT_QUIET )
endif()
Then, use add_custom_command() and the CMake script processing mode (-P) to call that script from your main CMakeLists.txt, with the script switch enabled / disabled by whatever variable you use for that purpose in your CMakeLists.txt file.
add_custom_command( OUTPUT outfile
COMMAND ${CMAKE_COMMAND} -P mycustom_command.cmake -DOUTPUT=${OUTPUT_DESIRED}
)
This is fully portable. If your mycustom_command is build from within your project as a target, just add it as DEPENDENCY to your add_custom_command() to have it build in time for the script call.

cmake: setting default values for arguments

My UNIX Makefile is as follows:
param=0
run:
./foo -r "fun($(param))"
So if I do make run, I get ./foo - r "fun(0)" and
for make run param=10, I get ./foo -r "fun(10)".
Now I want to generate similar Makefile using cmake.
add_custom_target(
run
./foo -r "\"fun($(param))\""
)
How do I set the default value for param within cmake configuration file?
The concept in CMake is a bit different. You can define "cache variables" (basically variables that are remembered for subsequent builds in the same build dir, and can be customized by users) that come with default values and documentation strings and such. These can then be changed either by passing -D name:type=value options to cmake, or using one of the friendlier frontends (e.g. ccmake, the curses UI for CMake).
Example based on your question:
SET(param 0 CACHE STRING "Test variable defaulting to '0'")
# ...
add_custom_target(run ./foo -r "\"fun(${param})\"")
You'll find more details in the exhaustive docs for CMake.
PS. this is for variables inside CMake and specifically CMakeLists.txt itself; the possibility to change the value is not carried over into the generated Makefile as far as I can tell. I'm not sure that's possible in the first place because it probably wouldn't be compatiable with all of the targets supported by CMake (e.g. Visual Studio projects and what not). In any case, CMake doesn't seem to have been designed for generating build files used independently of CMake.
Use
set (projectname_param 0)
to set it.