Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

makefile

cmake

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.

like image 254
B Faley Avatar asked Jan 11 '23 06:01

B Faley


2 Answers

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.

like image 129
ComicSansMS Avatar answered Jan 23 '23 03:01

ComicSansMS


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
like image 22
IdeaHat Avatar answered Jan 23 '23 04:01

IdeaHat