Getting CMAKE variables from C++

I don’t know if anyone else already has a way to do this, but I thought I’d share mine in case it is of use to anyone.

I wanted to be able to define the extension version and build date from a single place only in my source, in this case the CMakeLists.txt file. This means finding a way to pass values from CMake into C++.

Here’s how I did it:

Create the variables you want to pass through in your CMakeLists.txt file:

set (PROJECT_VERSION "1.2.0")
set (PROJECT_NAME "AdvancedSongChooser")
set (PROJECT_TITLE "Advanced Song Chooser")
string(TIMESTAMP TODAY "%d/%m/%Y")
set (PROJECT_BUILD_DATE ${TODAY})

Create a new file in your source folder called version.h.in:

#ifndef VERSION_H_IN
#define VERSION_H_IN

const std::string PROJECT_NAME = "@PROJECT_NAME@";
const std::string PROJECT_TITLE = "@PROJECT_TITLE@";
const std::string PROJECT_VERSION = "@PROJECT_VERSION@";
const std::string PROJECT_BUILD_DATE = "@PROJECT_BUILD_DATE@";

#endif // VERSION_H_IN

Then, in your CMakeLists.txt file again, just before creating your library target (NOTE: it’s this line: add_library(${PROJECT_NAME} SHARED))

add this line:

configure_file (version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h @ONLY) 

then each time CMake runs, it will produce a file called version.h in your source folder that will look something like this:

#ifndef VERSION_H_IN
#define VERSION_H_IN

const std::string PROJECT_NAME = "AdvancedSongChooser";
const std::string PROJECT_TITLE = "Advanced Song Chooser";
const std::string PROJECT_VERSION = "1.2.0";
const std::string PROJECT_BUILD_DATE = "26/04/2024";

#endif // VERSION_H_IN

You can now simply #include that file into your source as required to make use of the variables within.

3 Likes

It sure is, thanks! I was just thinking about this the other day.

1 Like

@DaveBoulden shouldn’t the header guards in version.h.in be without the “_IN”, as this is just part of the cmake template/input file, rather than the output version.h ?
e.g.

#ifndef VERSION_H
#define VERSION_H

I also wanted to use these variables in the required XMLProductDescription in LibMain.h.
So I added another cmake variable for the description. Oddly I had no success with defining the cmake variable as PROJECT_DESCRIPTION (it ended up blank in the output version.h). So I used PROJECT_DESCR instead. But in the version.h.in I could obviously specify the string variable as I wanted:

const std::string PROJECT_DESCRIPTION = "@PROJECT_DESCR@";

This was the result:

const std::string XMLProductDescription =
    "<Library>"
    "<Product Name=\"" + PROJECT_TITLE + "\" Version=\"" + PROJECT_VERSION + "\" BuildDate=\"" + PROJECT_BUILD_DATE + "\"></Product>"
    "<Description>" + PROJECT_DESCRIPTION + "</Description>"
    "<ImagePath></ImagePath>"
    "</Library>";

I may be wrong, but I thought the naming of header guards simply follow a convention rather than needing a specific syntax, so as long as they are unique, they can be anything. However, since one wants them to match the output file, the convention would be better suited in they were indeed VERSION_H.

That is pretty much the specific reason I did this. Mine was:

     // Replace with your information            
    "<Library>" 
    "<Product Name=\"" + PROJECT_NAME + "\" Version=\"" + PROJECT_VERSION + "\" BuildDate=\"" + PROJECT_BUILD_DATE + "\"></Product> "
    "<Description>Advanced song chooser extension that uses a web based UI</Description>"
    "<ImagePath>/Path/To/ImageFile/foo.jpg</ImagePath>"
    "</Library>"; 

I’ll probably do the description field myself. PROJECT_DESCRIPTION is a pre-defined variable in CMake, so if you wanted to use that specific variable name, you would need to supply it as a parameter to the project() command:

project(${PROJECT_NAME} VERSION ${PROJECT_VERSION} DESCRIPTION ${PROJECT_DESCRIPTION})

otherwise, that field will be given an empty value if it is not supplied as a parameter in the project() call, thus overwriting your previously assigned value.

1 Like

Thanks @DaveBoulden for sharing all of this. It’s definitely something I’ll be using on everything moving forward.

1 Like