# CODE: math(OUTPUT\_FORMAT HEXADECIMAL) workaround for CMake \< 3.13

**URL:** https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924
**Category:** Code
**Created:** [April 2, 2020, 1:25pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924 "2020-04-02T13:25:02Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [April 2, 2020, 1:25pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924/1 "2020-04-02T13:25:02Z")

</div>

One of our CMake projects includes a `GENERATED` config file that needs to include the project version converted into hexadecimal form. With CMake 3.13+, easy-peasy:

```cmake
  math(EXPR PROJECT_VERSION_HEX
    "(${PROJECT_VERSION_MAJOR} << 16) + \
     (${PROJECT_VERSION_MINOR} << 8) + \
     (${PROJECT_VERSION_PATCH})" OUTPUT_FORMAT HEXADECIMAL )

```

But we also need to support CMake versions all the way down to 3.2 (I _knoooow_), where that won’t work. For the longest time we were just hardcoding “`0x0m0n0p`” in a variable that we tried (and failed) to remember to update whenever` ${PROJECT_VERSION}` changed.

Since that was tedious even when we did remember (and we usually didn’t), I eventually hit on a workaround that I wanted to share in case it’s useful to others.

The trick is to leverage the CMake `try_run()` functionality, which can be used to execute a C or C++ program during the _build generation_ phase — much like `execute_process()`, but for source code instead. (You could certainly also do this with a shell command and `execute_process()`.)

I chose to write my `hex_version.cpp` generically, in case it ever has other uses. So, the inputs are passed as `COMPILE_DEFINITIONS` on the `try_run()` command line, and it could theoretically be used multiple times with different arguments. Source:

```auto
#include <iostream>
#include <ios>

// The following values must be defined at compile time:
// VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH

#if !defined(VERSION_MAJOR) || !defined(VERSION_MINOR) || !defined(VERSION_PATCH)
    #pragma error "Define version components on compiler command line!"
#endif

int main()
{

    int hex_version = (VERSION_MAJOR << 16) +
                      (VERSION_MINOR << 8) +
                      (VERSION_PATCH);

    std::cout << std::hex << "0x" << hex_version;
}

```

Then, when older CMake versions process `CMakeLists.txt`, that’s called to retrieve the `PROJECT_VERSION_HEX` value instead of using `math()`:

```cmake
# Compile and run a C++ program to generate the hex version
set(HEX_COMPILE_DEFINITIONS
  -DVERSION_MAJOR=${PROJECT_VERSION_MAJOR}
  -DVERSION_MINOR=${PROJECT_VERSION_MINOR}
  -DVERSION_PATCH=${PROJECT_VERSION_PATCH}
)
try_run(HEX_VERSION_RUN HEX_VERSION_BUILD
  ${CMAKE_CURRENT_BINARY_DIR}/hex_version
  ${PROJECT_SOURCE_DIR}/src/hex_version.cpp
  COMPILE_DEFINITIONS ${HEX_COMPILE_DEFINITIONS}
  RUN_OUTPUT_VARIABLE HEX_VERSION_OUTPUT
)
if (NOT HEX_VERSION_BUILD)
  message(ERROR "Failed to compile hex-version utility!")
elseif(HEX_VERSION_RUN STREQUAL FAILED_TO_RUN)
  message(ERROR "Could not execute hex-version utility!")
else()
  set(PROJECT_VERSION_HEX ${HEX_VERSION_OUTPUT})
endif()

```

---

<div class="post-metadata">

### Author: ![hsattler](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/h/59ef9b/32.png) [@hsattler](https://discourse.cmake.org/u/hsattler)
#### Post date: [April 2, 2020, 6:14pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924/2 "2020-04-02T18:14:45Z")

</div>

You could divide the number by 16 and use if and elseif to check for and convert the 6 possibilities greater 10 and simply assemble the string this way.

---

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [April 2, 2020, 6:39pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924/3 "2020-04-02T18:39:22Z")

</div>

![](https://discourse.cmake.org/uploads/default/original/1X/987ff1fc518ea00de5191bb9da3e52a7adbc9c99.gif)

---

<div class="post-metadata">

### Author: ![McMartin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mcmartin/32/150_2.png) [@McMartin](https://discourse.cmake.org/u/McMartin)
#### Post date: [April 2, 2020, 7:31pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924/4 "2020-04-02T19:31:47Z")

</div>

> [@hsattler](#):
>
> You could divide the number by 16 and use if and elseif to check for and convert the 6 possibilities greater 10 and simply assemble the string this way.

I’ve done something similar in a project of mine:

```cmake
function(_FRUT_dec_to_hex dec_value out_hex_value)

  if(dec_value EQUAL 0)
    set(${out_hex_value} "0x0" PARENT_SCOPE)
    return()
  endif()

  if(dec_value LESS 0)
    math(EXPR dec_value "2147483647 ${dec_value} + 1")
  endif()

  while(dec_value GREATER 0)
    math(EXPR hex_unit "${dec_value} & 15")
    if(hex_unit LESS 10)
      set(hex_char "${hex_unit}")
    else()
      math(EXPR hex_unit "${hex_unit} + 87")
      string(ASCII ${hex_unit} hex_char)
    endif()
    set(hex_value "${hex_char}${hex_value}")
    math(EXPR dec_value "${dec_value} >> 4")
  endwhile()

  set(${out_hex_value} "0x${hex_value}" PARENT_SCOPE)

endfunction()

```

(from [FRUT/cmake/Reprojucer.cmake at f89e16465abc4a7eb141459e48e718f2c866b4bb · McMartin/FRUT · GitHub](https://github.com/McMartin/FRUT/blob/f89e16465abc4a7eb141459e48e718f2c866b4bb/cmake/Reprojucer.cmake#L3448-L3473))

---

<div class="post-metadata">

### Author: ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)
#### Post date: [April 2, 2020, 9:58pm UTC](https://discourse.cmake.org/t/code-math-output-format-hexadecimal-workaround-for-cmake-3-13/924/5 "2020-04-02T21:58:51Z")

</div>

OK, the use of `string(ASCII)` to convert decimal to hexadecimal is legitimately inspired.
