1

I want to start reading a file from a specific line. Cmake official docs suggest using file() with offset but I am not sure about its usage. The file that I want to read is test.mak:

# -----------------------------------------------------------------------------
## TEST
# -----------------------------------------------------------------------------
TEST_COMPONENTS      ?= ABC DEF GHI

# SYMBOLS
SYMBOLS_PROJ ?= A002
SYMBOLS_LABEL   ?= TEST_A002_FINAL

I have a cmake file (the function is from internet and it works with my use case) where i want to read the test.mak file starting from "#SYMBOLS" so that the macros defined before this line are ignored/skipped, and then i want to set the macros in my current cmake:

function(Fileread MKFile)
  file(READ "${MKFile}" FileContents [OFFSET "# SYMBOLS"])
  string(REPLACE "?" "" FileContents ${FileContents})
  string(REPLACE "\\\n" "" FileContents ${FileContents})
  string(REPLACE "\n" ";" FileLines ${FileContents})
  list(REMOVE_ITEM FileLines "")
  foreach(line ${FileLines})
    string(REPLACE "=" ";" line_split ${line})
    list(LENGTH line_split count)
    if (count LESS 2)
      message(STATUS "Skipping ${line}")
      continue()
    endif()
    list(GET line_split -1 value)
    string(STRIP "${value}" value)
    separate_arguments(value)
    list(REMOVE_AT line_split -1)
    foreach(var_name ${line_split})
      string(STRIP ${var_name} var_name)
      set(${var_name} ${value} PARENT_SCOPE)
    endforeach()
  endforeach()
endfunction()

Fileread("test.mak")

The offset setting is not working as a result of which i am also getting the macro TEST_COMPONENTS which i don't need. NOTE: TEST_COMPONENTS is just an example, there are multiple lines of macro definitions before "# SYMBOLS" that i would like to skip. Thanks for any suggestions to solve this in advance.

deb
  • 15
  • 7
  • sooo read the whole file into a string, find offset of `# SYMBOLS` and get substring? – KamilCuk Feb 16 '22 at 11:20
  • OFFSET is an offset from the **beginning of the file** in **bytes**, not a *matcher* for some content. As for square brackets (`[` and `]`, they are use in documentation for specify *optional* parameters for a command. These brackets should not be used when actually call a command in your code. – Tsyvarev Feb 16 '22 at 11:38
  • Hi @KamilCuk thanks for the idea, i will try that. – deb Feb 16 '22 at 12:41

1 Answers1

3

Use file(STRINGS) to read the lines of the text file into a list variable. You could then use list(POP_FRONT) until you encounter a matching line.

# Line 1
# Line 2
# Line 3
# Line 4

file(STRINGS ${CMAKE_CURRENT_LIST_FILE} THIS_FILE)

set(REDUCTION_SUCCESS False)

while(THIS_FILE)
    list(POP_FRONT THIS_FILE LINE)
    if (LINE MATCHES "^# SYMBOLS.*")
        set(REDUCED_FILE ${LINE} ${THIS_FILE})
        set(REDUCTION_SUCCESS True)
        break()
    endif()
endwhile()

if (REDUCTION_SUCCESS)
    # use the contents of the REDUCED_FILE variable
    # (print all remaining lines for the purpose of demonstation)
    foreach(_LINE IN LISTS REDUCED_FILE)
        message(STATUS "${_LINE}")
    endforeach()
else()
    message(FATAL_ERROR "No line containing '# SYMBOLS' found")
endif()

Replace one of the # Line 1 comments with # SYMBOLS to get a successful outcome. For simplicity this is just a cmake script that can be run with cmake -P script.cmake. The script file parses itself.


If the number of lines to skip is known, you could simplify the logic after the file(STRINGS) command to a single list(SUBLIST) call.

fabian
  • 80,457
  • 12
  • 86
  • 114