Meysam
Meysam

Reputation: 18177

CMake: Is it possible to run CONFIGURE_FILE after each make?

I've got the following piece of script in my CMake file:

CONFIGURE_FILE(
    ${CMAKE_CURRENT_SOURCE_DIR}/version.hpp.cmake
    ${CMAKE_CURRENT_SOURCE_DIR}/version.hpp
)

But it's only run after executing cmake, not make. Is it possible to create the version.hpp file after each make?

Here is the content of version.hpp.cmake:

#ifndef _VERSION_HPP_
#define _VERSION_HPP_

#define MAJOR_VERSION "${MAJOR}"
#define MINOR_VERSION "${MINOR}"
#define PATCH_VERSION "${PATCH}"
#define RELEASE_VERSION "${RELEASE}"

#endif //_VERSION_HPP_

The MAJOR, MINOR, PATCH and RELEASE variables have been defined in the CMakeLists.txt file.

P.S. This post is apparently related to my question, but I can't get a grasp of it.

Upvotes: 4

Views: 7997

Answers (3)

IdeaHat
IdeaHat

Reputation: 7881

So I accidentally stumbled across this, I know it is probably too late, but calling configure is possible an exactly how I do this with mercurial versions.

The trick requires a lot of different tools, and I don't have time to formulate into a good answer atm, but ask questions and I'll fill it in when I have time.

tool 1: calling exec_program to extract the revision information (this is really easy with mercurial)

exec_program(hg ${PROJECT_SOURCE_DIR} ARGS "id" "-i" OUTPUT_VARIABLE OUTPUT_VARIABLE ${PROJECT_NAME}_HG_HASH_CODE)

I'm probably doing something more complicated than you care about here, but the essential bit is hg which you'll replace with whatever version control you are using, ${PROJECT_SOURCE_DIR} which you'll set to whatever executing directory you want, and fill in the custom args.

I put all of the version extraction into a single macro (ReadProjectRevisionStatus()).

The next step is to make a an entirely different CMake file that calls ReadProjectRevisionStatus() and then CONFIGURE_FILE. This file will assume that all the correct values are set when you come into it. In my case, I store the location of this file into ${CONFIG_FILE_LOC}.

The final step is to add a custom target that will call this script. For example:

ADD_CUSTOM_TARGET(${PROJECT_NAME}_HG_VERSION_CONFIG
    COMMAND ${CMAKE_COMMAND}
    ARGS -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
    -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}
    -DPROJECT_NAME=${PROJECT_NAME}
    -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
    "-D${PROJECT_NAME}_HG_CONFIG_FILE_IN=\"${${PROJECT_NAME}_HG_CONFIG_FILE_IN}\""
    "-D${PROJECT_NAME}_HG_CONFIG_FILE_OUT=\"${${PROJECT_NAME}_HG_CONFIG_FILE_OUT}\""
    ${ARGN}
    -P ${CONFIG_FILE_LOC})

One of the beauties of doing it this way is that custom target call can still be called outside of a cmake build system, which I've done on a couple of projects, which a bash call similar to:

cmake -D PROJECT_SOURCE_DIR=$sourcedir -DPROJECT_BINARY_DIR=$sourcedir -DPROJECT_NAME=uControl -DCMAKE_MODULE_PATH=$sourcedir -DuControl_HG_CONFIG_FILE_IN=$sourcedir/tsi_software_version.h.in -DuControl_HG_CONFIG_FILE_OUT=$sourcedir/tsi_software_version.h -P $sourcedir/ConfigureHGVersion.cmake

Upvotes: 3

ComicSansMS
ComicSansMS

Reputation: 54737

The problem is that configure_file is supposed to run at configure time, that is when you run cmake, instead of compile time, which is when you run make. There is no easy way around this.

The problem is that the information written by configure_file is dependent on variables from the CMake build environment. Changes to those variables cannot be detected without running CMake again. If you have that information mirrored somewhere else, you can use a custom command to extract it and perform the code generation for you, as Peter's answer suggested.

The approach suggested in the post from the CMake mailing list that you linked in your answer is based on a two-phase CMake run: The outer CMake project (which is run only once) adds a custom build step for building the inner CMake project (which is then run with every make) where the configure_file is performed. The underlying idea is the same as with Peter's answer, only instead of a Python script you use a CMake script for generating the file.

My personal recommendation: For a simple problem as a version header, I would not bother with such a complicated approach. Simply generate the file to your BINARY_DIR (not to your project dir, as you currently do! you want to retain the ability to do several out-of-source builds from the same source) and assume that it will be there for compilation. If a user is brave enough to mess with the generated files there, they can be expected to re-run CMake on their own.

Upvotes: 6

Peter Petrik
Peter Petrik

Reputation: 10185

One possibity is to generate version.hpp from Python and use ADD_CUSTOM_TARGET

... find python ...
ADD_CUSTOM_TARGET(gen_version ALL ${PYTHON_EXECUTABLE} gen_version.py)
SET_SOURCE_FILES_PROPERTIES(version.hpp PROPERTIES GENERATED 1)
... link gen_version to your library/executable ...

Upvotes: 1

Related Questions