1

I have a template cpp file that will contain several placeholders. Excerpt:

// WARNING! this file is autogenerated, do not edit manually
QString appName()
{
  return "APP_NAME_VALUE";
}

Cmake will read this file in, fill in the placeholders and write it back out to the shadow build directory for compilation

set(APP_NAME "real application name")

file(READ ${CMAKE_SOURCE_DIR}/templates/app-info.cpp APP_INFO)
string(REPLACE "APP_NAME_VALUE" ${APP_NAME} APP_INFO ${APP_INFO})
# other tag replacements
file(WRITE "${CMAKE_BINARY_DIR}/src/app-info.cpp" ${APP_INFO})

But every time I run cmake, it seems to strip the semi-colon from the file contents.

// WARNING! this file is autogenerated, do not edit manually
QString appName()
{
  return "real application name"
}

Is this expected behaviour? What can I do to counter this?

iwarv
  • 335
  • 4
  • 13
  • The change from `//` to `/` reminds me of CMake interpreting `/` as a control character; countering that needed you to submit four slashes e.g. `////` Personally I'd write a utility to replace the string and invoke that as a pre-build step – Den-Jason May 03 '22 at 10:55
  • 2
    Why don't you use the [`configure_file`](https://cmake.org/cmake/help/latest/command/configure_file.html) command? – Some programmer dude May 03 '22 at 10:56
  • Also see https://stackoverflow.com/a/48295436/1607937 – Den-Jason May 03 '22 at 10:58
  • @Someprogrammerdude Quite new to CMake (in process of migrating). I never knew this existed. Thanks for the pointer. Will look into this. – iwarv May 03 '22 at 10:59
  • You will find your answer in https://discourse.cmake.org/t/what-is-the-best-way-to-search-and-replace-strings-in-a-file/1879 – Den-Jason May 03 '22 at 10:59
  • 1
    @Den-Jason the `/` vs '//' was a typo of mine. There's no problem there. Sorry for the confusion. Re your link: Yup, that works. Your search skills are better than mine. – iwarv May 03 '22 at 11:04
  • 1
    @Den-Jason I think that link is the correct answer to my question. Fancy turning it into a real answer here and I will accept? (putting aside for a moment that I possibly should use `configure_file()` instead) – iwarv May 03 '22 at 11:06
  • Already done; SO does not like "link to external websites" as answers – Den-Jason May 03 '22 at 11:07

1 Answers1

2

From https://discourse.cmake.org/t/what-is-the-best-way-to-search-and-replace-strings-in-a-file/1879

In my CMake script, I need to modify other source files by searching and replacing specified strings. In my case, the configure_file 2 command is not a solution because I have no control over the input file. Previously I used the file and string commands in the following way -

file(READ header.h FILE_CONTENTS)
string(REPLACE "old text" "new text" FILE_CONTENTS ${FILE_CONTENTS})
file(WRITE header.h ${FILE_CONTENTS})

However this technique appears to strip out semi-colons from the input file.

Answer: put quotes around ${FILE_CONTENTS} in both commands

Explanation:

It comes from a CMake’s list syntax, which is ;-separated, the fact that arguments passed to CMake commands are basically mashed together into a list, and that those commands take unbounded number of inputs. So you end up with one longer list.

Quoting prevents the semicolons in the expansion from being treated as list-element-separators.

Consider:

WRITE;header.h;x;y;z

vs

WRITE;header.h;"x;y;z"

So in your case, it will appear as such:

set(APP_NAME "real application name")

file(READ ${CMAKE_SOURCE_DIR}/templates/app-info.cpp APP_INFO)
string(REPLACE "APP_NAME_VALUE" ${APP_NAME} APP_INFO "${APP_INFO}")
# other tag replacements
file(WRITE "${CMAKE_BINARY_DIR}/src/app-info.cpp" "${APP_INFO}")
Den-Jason
  • 2,395
  • 1
  • 22
  • 17