0

I want to achieve the equivalent of C++ #define foo "bar" but I don't want the value "bar" to be part of my code repository, and the value will depend on whether the build is Debug or Release.

How can I do this?

NB: I like the idea of using the following in CMakeLists.txt add_compile_definitions(foo="bar") but I don't know how to supply "bar" from the Qt Creator build settings.

Presumably I'd add a Key/Value pair but what would I put?

Qt Creator build settings

Paul Masri-Stone
  • 2,843
  • 3
  • 29
  • 51
  • Maybe you want: [https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html](https://cmake.org/cmake/help/book/mastering-cmake/chapter/CMake%20Cache.html) – drescherjm Oct 07 '22 at 15:31
  • I don't think CMake options/cache is what I'm after. I suspect it's more about a `-Dxxxxxxx` option that ends up in the command that Qt Creator uses to run CMake, but I don't know how to put that build option together. – Paul Masri-Stone Oct 10 '22 at 11:04
  • After further research, you're right that CMake cache is what I need, but I had to delve deeper to work out how to use that with Qt Creator build settings. – Paul Masri-Stone Oct 13 '22 at 08:55

2 Answers2

1

I would suggest you to set the definition using target_compile_definitions:

target_compile_definitions(myexe PUBLIC foo="bar")

To set it to different things depending if it's release or debug, using generator expressions would make those options portable when using a multi config generator:

target_compile_definitions(myexe PUBLIC
    $<$<CONFIG:Debug>:foo="bar">
    $<$<CONFIG:Release>:baz="bat">
)

If you really don't want the bar option to be present in your repository including the CMake files, there are ways to define that too.

You can send it as part of a command line option. For thst you can define that command line option using the option command, then send the command line argument using a preset:

option(MYPROJECT_MY_OPTION "Activate the definitions" OFF)

if(MYPROJECT_MY_OPTION)
    target_compile_definitions(myexe PUBLIC
        $<$<CONFIG:Debug>:foo=bar">
        $<$<CONFIG:Release>:baz="bat">
    )
endif()

Then create some profiles:

{
    "version": 2,
    "cmakeMinimumRequired": {
        "major": 3,
        "minor": 22,
        "patch": 0
    },
    "configurePresets": [
        {
            "name": "cmake-pedantic",
            "hidden": true,
            "warnings": {
                "dev": false,
                "deprecated": true,
                "uninitialized": true,
                "unusedCli": true,
                "systemVars": false
            },
            "errors": {
                "dev": false,
                "deprecated": true
            }
        },
        {
            "name": "generator-ninja",
            "hidden": true,
            "generator": "Ninja Multi-Config",
            "binaryDir": "${sourceDir}/build",
            "cacheVariables": {
                "CMAKE_DEBUG_POSTFIX": "d",
                "CMAKE_MAKE_PROGRAM": "ninja"
            }
        },
        {
            "name": "dev",
            "displayName": "Development",
            "description": "Development preset",
            "inherits": ["generator-ninja"]
        },
        {
            "name": "dev-with-option",
            "displayName": "Development",
            "description": "Development preset",
            "binaryDir": "${sourceDir}/build-with-option",
            "inherits": ["generator-ninja"],
            "cacheVariables": {
                "MYPROJECT_MY_OPTION": true
            }
        }
    ],
    "buildPresets": [
        {
            "name": "dev-debug",
            "displayName": "Debug",
            "description": "Build with debug informations",
            "configuration": "Debug",
            "configurePreset": "dev"
        },
        {
            "name": "dev-relwithdebinfo",
            "displayName": "RelWithDebInfo",
            "description": "Build with debug informations and optimizations enabled",
            "configuration": "RelWithDebInfo",
            "configurePreset": "dev"
        },
        {
            "name": "dev-release",
            "displayName": "Release",
            "description": "Build with optimizations enabled",
            "configuration": "Release",
            "configurePreset": "dev"
        },
        {
            "name": "dev-with-option-debug",
            "displayName": "Debug",
            "description": "Build with debug informations",
            "configuration": "Debug",
            "configurePreset": "dev-with-option"
        },
        {
            "name": "dev-with-option-relwithdebinfo",
            "displayName": "RelWithDebInfo",
            "description": "Build with debug informations and optimizations enabled",
            "configuration": "RelWithDebInfo",
            "configurePreset": "dev-with-option"
        },
        {
            "name": "dev-with-option-release",
            "displayName": "Release",
            "description": "Build with optimizations enabled",
            "configuration": "Release",
            "configurePreset": "dev-with-option"
        }
    ],
    "testPresets": [
        {
            "name": "base-test",
            "hidden": true,
            "output": {
                "outputOnFailure": true
            },
            "execution": {
                "noTestsAction": "error",
                "stopOnFailure": true
            }
        },
        {
            "name": "dev-debug",
            "displayName": "Debug",
            "configuration": "Debug",
            "configurePreset": "dev",
            "inherits": "base-test"
        },
        {
            "name": "dev-relwithdebinfo",
            "displayName": "RelWithDebInfo",
            "configuration": "RelWithDebInfo",
            "configurePreset": "dev",
            "inherits": "base-test"
        },
        {
            "name": "dev-release",
            "displayName": "Release",
            "configuration": "Release",
            "configurePreset": "dev",
            "inherits": "base-test"
        },
        {
            "name": "dev-with-option-debug",
            "displayName": "Debug",
            "configuration": "Debug",
            "configurePreset": "dev",
            "inherits": "base-test"
        },
        {
            "name": "dev-with-option-relwithdebinfo",
            "displayName": "RelWithDebInfo",
            "configuration": "RelWithDebInfo",
            "configurePreset": "dev",
            "inherits": "base-test"
        },
        {
            "name": "dev-with-option-release",
            "displayName": "Release",
            "configuration": "Release",
            "configurePreset": "dev",
            "inherits": "base-test"
        }
    ]
}

This will allow IDEs to select between dev and dev-with-option, and also allow the IDE to select debug or release configs.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • The key part of my question is "I don't want the value "bar" to be part of my code repository" hence wanting to inject it as a build setting that CMake can pick up. If I'm reading your answer right, "bar" would still be within CMakeLists.txt, is it not? – Paul Masri-Stone Oct 10 '22 at 11:04
  • (It's possible I'm just reading your answer wrong though. I should have been clearer that I was referring to Qt Creator build options, as I'm not familiar with manually creating a configuration file for invoking from the command line.) – Paul Masri-Stone Oct 10 '22 at 11:14
  • @PaulMasri-Stone I don't know much about IDE, I think QtCreator uses CMake in the background. The CMake filles are still part of your repository and part of your code, so I interpreted that as you not wanting the option to fixed in the CMake files either. – Guillaume Racicot Oct 10 '22 at 16:13
  • 1
    The first part of my answer is about setting the option from the CMake files. The second part is about adding a command line option to your project build so users and package maintainers can set that option from the command line. The last part is about adding a preset file to automate the command line arguments. With the preset, IDEs can let you select which command line profile you want. – Guillaume Racicot Oct 10 '22 at 16:15
  • Thanks for explaining. Qt Creator has its own way of storing per-profile build settings, so it sounds like the second part is what I'm after. I'll reread your answer and try it out. – Paul Masri-Stone Oct 11 '22 at 19:10
  • 1
    QtCreator 9 had native support for CMake presets: https://www.qt.io/blog/qt-creator-9-beta-released – Guillaume Racicot Oct 12 '22 at 12:09
0

You need a 2 step process:

  1. Add a Qt Creator build setting to create a CMake cache variable.
  2. In CMakeLists.txt use the cache variable within a command.

For your example:

  1. In Qt Creator build settings,
  • either click Add > String setting Key to MYPROJECT_FOO and Value to bar
  • or click Batch Edit... and add -DMYPROJECT_FOO:STRING=bar
  1. In CMakeLists,

target_compile_definitions(mytarget PUBLIC foo="${MYPROJECT_FOO}")

(As advised by Guillaume Racicot it's better to apply the definition to a single target, as opposed to the entire project, which would be add_compile_definitions(foo="${MYPROJECT_FOO}").)

See also Qt Creator documentation CMake Build Configuration: Modifying Variable Values.

Thanks to Guillaume Racicot for deeper explanation of how CMake cache variables can be used.

Paul Masri-Stone
  • 2,843
  • 3
  • 29
  • 51