CMake run command during generation - cmake

I'm trying to have cmake download some files. Is it possible to do this once, when the "Generate" button is pressed? I can only set it up to run each time the configure button is pressed or each time the project is built.

CMakeLists are processed at configure time, so you can't have it do things at generate time. You could, however, set up a cache variable and use it as a flag to determine if the download should happen or not. Something like:
if(NOT DOWNLOAD_HAPPENED)
execute_process( ... do the downloading stuff ... )
set(DOWNLOAD_HAPPENED TRUE CACHE BOOL "Has the download happened?" FORCE)
endif()
This will execute the download on first configure and never again (unless the user manually resets the DOWNLOAD_HAPPENED) variable. However, if you really need the download to happen at the last configure, you're out of luck, AFAIK.

Something like this should help:
add_custom_command(
OUTPUT myfile.txt
COMMAND wget http://myurl.com/myfile.txt
)
EDIT 1
It's require to make it as a dependency of the main command:
add_dependencies(<myprogram> wget)

Related

Cause CMake to force recompile a file, but only if project is otherwise recompiled?

I have generally the same question as in Can CMake always force the compilation/build of a specific file?
I have a C++ file using __DATE__ to display the build date of my app. But if this file is not modified, it will not be rebuilt and the date will not be updated.
Can CMake always rebuild that specific file?
... except I want something slightly different:
In the CMake project I have (for C, transpiles to Makefile which I use), sometimes there are no actual changes to the code when I run make, which is detected nicely, in the sense that there is no recompilation (or relinking) of the program.
Obviously, in this case, I do not want to update the timestamp, and end up with a new executable, which is otherwise identical to the previous one - apart from the build date.
I have seen in the quoted post, that one simply has to ensure a changed timestamp on the file, to force a recompilation. So, assuming my __DATE__ usage is in use_date.c, what I'd want, is that the timestamp of use_date.c is updated (forcing recompilation), only if any other file in the project (say, main.c) has been changed, so it forces project recompilation and linking (obviously, this should also work if I just change use_date.c manually, and no other file).
So, assuming my project just generates an executable (no libraries):
add_executable(my_project use_date.c other_file.c main.c)
... is it possible to add a CMake step, that updates the timestamp of use_date.c (and thus causes its recompilation), only if otherwise the project is getting recompiled and relinked?
OK, found a way: it seems kind of a squeaky solution - hopefully someone more knowledgeable in CMake will post a proper solution eventually. But in the meantime:
I've found that add_custom_command with POST_BUILD runs the custom command only if a new binary (.elf for me) is generate, and otherwise does not run the custom command.
So, basically, we could have a small bash script in the custom command:
If this bash script is called, we can assume that POST_BUILD has called it, meaning that a new .elf (for whatever other reasons) has been built
So we can touch the use_date.c, and while in the bash script still, descend into the build directory, and explicitly run make again - which should recompile only use_date.c, and then link with the rest from the previous build.
This essentially works - except, it causes an infinite loop.
This can get solved with creating a temp file:
If this bash script is called, we can assume that POST_BUILD has called it, meaning that a new .elf (for whatever other reasons) has been built
check for a temp file:
if it does not exist, create it - and then we can touch the use_date.c, and while in the bash script still, descend into the build directory, and explicitly run make again - which should ...
if it does exist, then we've been called from the second .elf. build (for the touched use_date.c), so we want to remove the temp file, and just exit - stopping the infinite loop
This seems to work fine:
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
DEPENDS ALL
#COMMAND bash ARGS -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/use_date.c && cd build && make" ## infinite loop!
COMMAND bash ARGS -c "if [ ! -f .refresh ]; then echo '.refresh' | tee .refresh && touch ${CMAKE_CURRENT_SOURCE_DIR}/use_date.c && cd build && make; else rm -v .refresh; fi" # OK!
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "remake with refreshed __DATE__ in use_date.c (${CMAKE_CURRENT_SOURCE_DIR})"
VERBATIM
)

What's the proper way to regenerate cmake files after modifying a cache variable?

e.g.
$ cmake -G Ninja -DSOME_OPTS ..
$ ninja
$ vim CMakeCache.txt
(... edit a cache variable)
what now is the proper command to use to regenerate the build files? I've been using cmake .. but I just did so and it produced considerably more steps to rebuild than I had anticipated.
You are doing it wrongly. In brief, never ever edit CMakeCache.txt manually!
If necessary, edit CMakeLists.txt and cmake will take care of changes during build step automatically.
Also, if you need to make changes to already configured build, without changing CMakeLists.txt, you might use cmake-gui from build directory:
cmake-gui .
note one dot as a parameter to cmake-gui; this will allow you to edit/change configuration very comfortably, and cmake will take care of applying the changes. Take care, you must initiate (i.e. press button) configre, followed by generate within cmake-gui, in order to save changes you made.

How to trigger update of ExternalProject when UPDATE_DISCONNECTED set to ON

I have following CMakeLists.txt file in external directory in my project root. It is supposed fetch Catch (header only unit test library) for me.
include(ExternalProject)
ExternalProject_Add(
Catch
# I want to have it downloaded only once,
# therefore CMAKE_CURRENT_SOURCE_DIR which is projectRoot/external
PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/Catch
GIT_REPOSITORY https://github.com/philsquared/Catch.git
# disables auto update on every build
UPDATE_DISCONNECTED 1
# disable following, since it is not needed
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_DIR ""
INSTALL_COMMAND ""
)
It works well for me, except one thing.
I have set UPDATE_DISCONNECTED to 1 since I do not want to check for updates in every build I make (checking for updates takes some time).
But I would still like to have the opportunity to update external project from CMake itself. Eg. by doing make Catch_update or make external_update_all or whatever.
Is there better way to do that than writing custom target calling git pull in external project directory? If yes, then how? Thanks!
The ExternalProject module has a Target Option, STEP_TARGETS, to which you can add, for instance, "update". In your call to ExternalProject_Add, simply add a line, STEP_TARGETS update. That will automatically create a target (in your case, Catch-update), which calls a pretty sophisticated CMake script (in your case, probably projectRoot/external/Catch/tmp/Catch-gitupdate.cmake). The ExternalProject module itself creates this gitupdate script. The script does a lot more than a simple pull; it will stash local changes, as needed, and pop them back, for instance. I just used this about a week ago and was pretty happy with it.
From the CMake documentation for the UPDATE_DISCONNECTED option (boldface added by me):
When enabled, this option causes the update step to be skipped. It does not, however, prevent the download step. The update step can still be added as a step target (see ExternalProject_Add_StepTargets()) and called manually. This is useful if you want to allow developers to build the project when disconnected from the network (the network may still be needed for the download step though).
When you call ExternalProject_Add with a STEP_TARGETS option, however, ExternalProject_Add_StepTargets is called for you automatically.
One final thing: You don't need to call find_package(Git REQUIRED), as you did in the first answer. By virtue of setting GIT_REPOSITORY in your call to ExternalProject_Add, the module itself will attempt to find git (and will issue a FATAL_ERROR message if it can't).
OK, so after additional searching, this seems to be the only way to do this. Add custom target with an update. It is not pretty, but it is working.
#we need git executable
find_package(Git REQUIRED)
# update Catch target
add_custom_target(external-Catch-update
COMMENT "Updated Catch"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Catch/src/Catch
COMMAND ${GIT_EXECUTABLE} pull
DEPENDS Catch)

How to configure external cmake libraries?

What I wanted to do is call
add_subdirectory(ext/oglplus)
and be done with it. Unfortunately it is not that simple. There is a huge buildscript which detects various opengl settings. So I tried the following
ExternalProject_Add(liboglplus
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus/configure.py --use-glew
BUILD_COMMAND ${MAKE})
The problem that I have is don't really want to build it like that. It also doesn't build correctly because for some reason it wants to install the library and because there is no install target it will abort the compilation.
But the build script is calling cmake under the hood.
So what I want to do is to tell cmake to use "cofigure.py" instead of "cmake .." and then use it like any other cmake library.
Is this possible?
I used to call Linux Kernel KBuild from CMake using
ADD_CUSTOM_COMMAND() and ADD_CUSTOM_TARGET()
This way you can run arbitrary commands (like your config.py) and use the output.
First setup the command with all command-line options as CMake-variables, in tou case this would be calling the config.py script ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus/.
Instead of encoding the Path to your script in the command (adding ext/oglplus) I think it may be better adding WORKING_DIRECTORY to the custom command:
add_custom_command
SET(KBUILD_CMD ${CMAKE_MAKE_PROGRAM}
-C ${KERNEL_BUILD_DIR}
CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH}
EXTRA_CFLAGS=${KBUILD_EXTRA_CFLAGS}
INSTALL_MOD_PATH=${INSTALL_MOD_PATH}
M=${CMAKE_CURRENT_SOURCE_DIR}
KBUILD_EXTRA_SYMBOLS=${depends_module_ksyms}
)
Add a custom command that calls your build-script and creates a file in the CMAKE_CURRENT_BINARY_DIRECTORY (note the second COMMAND to touch a file)
ADD_CUSTOM_COMMAND(
OUTPUT ${module_name}.built
COMMAND ${KBUILD_CMD} modules
COMMAND cmake -E touch ${module_name}.built
COMMENT "Kernel make modules ${module_name}"
VERBATIM
)
Add a custom target, its always out of date, but if you want it to be called automatically add ALL otherwise you have to explicityly call make module_build, I guess this is what you want.
ADD_CUSTOM_TARGET("${module_name}_build" ALL
DEPENDS ${depends_module_ksyms}
${CMAKE_CURRENT_BINARY_DIR}/${module_name}.built
COMMENT "Building Kernel Module ${module_name}"
)

How can I get cmake command from cmake-gui?

I use cmake-gui to configure OpenCV, and I want to use same configure on some other computer.
Cause I use ssh without X forwarding, so I can't use cmake-gui to configure again.
I don't kown how to use cmake to complete my configure, so I wonder that cmake-gui can generate the command use for cmake?
Is there anyway to do this?
There is an option called: Tools-> Show my Changes which displays exactly what you have configured relating to the original configuration. One version are the copy&paste command line parameters and the other version is nicely human readable.
By default you cannot do what you want because that path is stored in CMAKE_COMMAND which is an INTERNAL variable so it is not visible in the GUI. You can manually read it from the cache using a command like grep CMAKE_COMMAND CMakeCache.txt | cut -d = -f 2. Alternatively you can update your CMakeLists.txt to put the value of CMAKE_COMMAND in the cache so that you can read it using the GUI. For example:
set(USED_CMAKE_PATH ${CMAKE_COMMAND} CACHE FILEPATH
"The path to the CMake executable used to configure this project" FORCE)
Additionally if you are using the "Unix Makefiles" generator there are two targets provided for this:
rebuild_cace which is equivalent to cmake .
edit_cache which is equivalent to ccmake . or cmake-gui . depending upon your install.
Note: I used CMake version 2.8.10.2 to test this, but I expect it to work with any version.