1find_package(Zephyr REQUIRED COMPONENTS extensions HINTS ${CMAKE_CURRENT_LIST_DIR}/../../)
2
3#
4# Create functions - start
5#
6function(create_system)
7  cmake_parse_arguments(OBJECT "" "ENTRY;FORMAT;NAME;OBJECT" "" ${ARGN})
8
9  set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}          TRUE)
10  set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_OBJ_TYPE SYSTEM)
11  set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_NAME     ${OBJECT_NAME})
12  set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_FORMAT   ${OBJECT_FORMAT})
13  set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_ENTRY    ${OBJECT_ENTRY})
14
15  set(${OBJECT_OBJECT} SYSTEM_${OBJECT_NAME} PARENT_SCOPE)
16endfunction()
17
18function(create_region)
19  cmake_parse_arguments(OBJECT "" "NAME;OBJECT;SIZE;START;FLAGS" "" ${ARGN})
20
21  if(DEFINED OBJECT_SIZE)
22    if(${OBJECT_SIZE} MATCHES "^([0-9]*)[kK]$")
23      math(EXPR OBJECT_SIZE "1024 * ${CMAKE_MATCH_1}" OUTPUT_FORMAT HEXADECIMAL)
24    elseif(${OBJECT_SIZE} MATCHES "^([0-9]*)[mM]$")
25      math(EXPR OBJECT_SIZE "1024 * 1024 * ${CMAKE_MATCH_1}" OUTPUT_FORMAT HEXADECIMAL)
26    elseif(NOT (${OBJECT_SIZE} MATCHES "^([0-9]*)$" OR ${OBJECT_SIZE} MATCHES "^0x([0-9a-fA-F]*)$"))
27      message(FATAL_ERROR "SIZE format is unknown.")
28    endif()
29  endif()
30
31  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}          TRUE)
32  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_OBJ_TYPE REGION)
33  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_NAME     ${OBJECT_NAME})
34  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_ADDRESS  ${OBJECT_START})
35  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_FLAGS    ${OBJECT_FLAGS})
36  set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_SIZE     ${OBJECT_SIZE})
37
38  set(${OBJECT_OBJECT} REGION_${OBJECT_NAME} PARENT_SCOPE)
39endfunction()
40
41function(get_parent)
42  cmake_parse_arguments(GET_PARENT "" "OBJECT;PARENT;TYPE" "" ${ARGN})
43
44  get_property(type GLOBAL PROPERTY ${GET_PARENT_OBJECT}_OBJ_TYPE)
45  if(${type} STREQUAL ${GET_PARENT_TYPE})
46    # Already the right type, so just set and return.
47    set(${GET_PARENT_PARENT} ${GET_PARENT_OBJECT} PARENT_SCOPE)
48    return()
49  endif()
50
51  # Follow parent pointers until a GET_PARENT_TYPE is reached
52  get_property(parent GLOBAL PROPERTY ${GET_PARENT_OBJECT}_PARENT)
53  get_property(type   GLOBAL PROPERTY ${parent}_OBJ_TYPE)
54  while(NOT ${type} STREQUAL ${GET_PARENT_TYPE})
55    get_property(parent GLOBAL PROPERTY ${parent}_PARENT)
56    get_property(type   GLOBAL PROPERTY ${parent}_OBJ_TYPE)
57  endwhile()
58
59  set(${GET_PARENT_PARENT} ${parent} PARENT_SCOPE)
60endfunction()
61
62function(create_group)
63  cmake_parse_arguments(OBJECT "" "GROUP;LMA;NAME;OBJECT;SYMBOL;VMA" "" ${ARGN})
64
65  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}          TRUE)
66  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_OBJ_TYPE GROUP)
67  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_NAME     ${OBJECT_NAME})
68  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_SYMBOL   ${OBJECT_SYMBOL})
69
70  if(DEFINED OBJECT_GROUP)
71    find_object(OBJECT parent NAME ${OBJECT_GROUP})
72  else()
73    if(DEFINED OBJECT_VMA)
74      find_object(OBJECT obj NAME ${OBJECT_VMA})
75      get_parent(OBJECT ${obj} PARENT parent TYPE REGION)
76
77      get_property(vma GLOBAL PROPERTY ${parent}_NAME)
78      set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_VMA ${vma})
79    endif()
80
81    if(DEFINED OBJECT_LMA)
82      find_object(OBJECT obj NAME ${OBJECT_LMA})
83      get_parent(OBJECT ${obj} PARENT parent TYPE REGION)
84
85      get_property(lma GLOBAL PROPERTY ${parent}_NAME)
86      set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_LMA ${lma})
87    endif()
88  endif()
89
90  get_property(GROUP_FLAGS_INHERITED GLOBAL PROPERTY ${parent}_FLAGS)
91  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_FLAGS  ${GROUP_FLAGS_INHERITED})
92  set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_PARENT ${parent})
93
94  add_group(OBJECT ${parent} GROUP GROUP_${OBJECT_NAME})
95
96  set(${OBJECT_OBJECT} GROUP_${OBJECT_NAME} PARENT_SCOPE)
97endfunction()
98
99function(is_active_in_pass ret_ptr current_pass pass_rules)
100  # by validation in zephyr_linker_* we know that if there is a NOT,
101  # it is the first, and the other entries are pass names
102  if(NOT pass_rules)
103    set(result 1)
104  elseif("NOT" IN_LIST pass_rules)
105    set(result 1)
106    if(current_pass IN_LIST pass_rules)
107      set(result 0)
108    endif()
109  else()
110    set(result 0)
111    if(current_pass IN_LIST pass_rules)
112      set(result 1)
113    endif()
114  endif()
115  set(${ret_ptr} ${result} PARENT_SCOPE)
116endfunction()
117
118function(create_section)
119  set(single_args "NAME;ADDRESS;ALIGN_WITH_INPUT;TYPE;ALIGN;ENDALIGN;SUBALIGN;VMA;LMA;NOINPUT;NOINIT;NOSYMBOLS;GROUP;SYSTEM;MIN_SIZE;MAX_SIZE")
120  set(multi_args  "PASS")
121
122  cmake_parse_arguments(SECTION "" "${single_args}" "${multi_args}" ${ARGN})
123
124  if(DEFINED SECTION_PASS)
125    is_active_in_pass(active ${PASS} "${SECTION_PASS}")
126    if(NOT active)
127      return()
128    endif()
129  endif()
130
131  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME} TRUE)
132  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_OBJ_TYPE         SECTION)
133  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NAME             ${SECTION_NAME})
134  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ADDRESS          ${SECTION_ADDRESS})
135  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_TYPE             ${SECTION_TYPE})
136  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ALIGN            ${SECTION_ALIGN})
137  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ALIGN_WITH_INPUT ${SECTION_ALIGN_WITH_INPUT})
138  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_SUBALIGN         ${SECTION_SUBALIGN})
139  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ENDALIGN         ${SECTION_ENDALIGN})
140  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOINPUT          ${SECTION_NOINPUT})
141  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOINIT           ${SECTION_NOINIT})
142  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOSYMBOLS        ${SECTION_NOSYMBOLS})
143  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_MIN_SIZE         ${SECTION_MIN_SIZE})
144  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_MAX_SIZE         ${SECTION_MAX_SIZE})
145
146  string(REGEX REPLACE "^[\.]" "" name_clean "${SECTION_NAME}")
147  string(REPLACE "." "_" name_clean "${name_clean}")
148  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NAME_CLEAN ${name_clean})
149
150  set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_start      ${name_clean})
151  set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_size       ${name_clean})
152  set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_load_start ${name_clean})
153  set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end        ${name_clean})
154
155  set(INDEX 100)
156  set(settings_single "ALIGN;ANY;FIRST;KEEP;OFFSET;PRIO;SECTION;SORT;MIN_SIZE;MAX_SIZE")
157  set(settings_multi  "FLAGS;INPUT;PASS;SYMBOLS")
158  foreach(settings ${SECTION_SETTINGS} ${DEVICE_API_SECTION_SETTINGS})
159    if("${settings}" MATCHES "^{(.*)}$")
160      cmake_parse_arguments(SETTINGS "" "${settings_single}" "${settings_multi}" ${CMAKE_MATCH_1})
161
162      if(NOT ("${SETTINGS_SECTION}" STREQUAL "${SECTION_NAME}"))
163        continue()
164      endif()
165
166      if(DEFINED SETTINGS_PASS)
167        is_active_in_pass(active ${PASS} "${SETTINGS_PASS}")
168        if(NOT active)
169          continue()
170        endif()
171      endif()
172
173      if(DEFINED SETTINGS_PRIO)
174        set(idx ${SETTINGS_PRIO})
175      else()
176        set(idx ${INDEX})
177        math(EXPR INDEX "${INDEX} + 1")
178      endif()
179
180      foreach(setting ${settings_single} ${settings_multi})
181        set_property(GLOBAL PROPERTY
182          SECTION_${SECTION_NAME}_SETTING_${idx}_${setting}
183          ${SETTINGS_${setting}}
184        )
185        if(DEFINED SETTINGS_SORT)
186          set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end ${name_clean}_end)
187        endif()
188      endforeach()
189
190      set_property(GLOBAL APPEND PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES ${idx})
191
192    endif()
193  endforeach()
194
195  get_property(indicies GLOBAL PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES)
196  if(DEFINED indicies)
197    list(SORT indicies COMPARE NATURAL)
198    set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES ${indicies})
199  endif()
200
201  if(DEFINED SECTION_GROUP)
202    find_object(OBJECT parent NAME ${SECTION_GROUP})
203  elseif(DEFINED SECTION_VMA OR DEFINED SECTION_LMA)
204    if(DEFINED SECTION_VMA)
205      find_object(OBJECT object NAME ${SECTION_VMA})
206      get_parent(OBJECT ${object} PARENT parent TYPE REGION)
207
208      get_property(vma GLOBAL PROPERTY ${parent}_NAME)
209      set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_VMA ${vma})
210      set(SECTION_VMA ${vma})
211    endif()
212
213    if(DEFINED SECTION_LMA)
214      find_object(OBJECT object NAME ${SECTION_LMA})
215      get_parent(OBJECT ${object} PARENT parent TYPE REGION)
216
217      get_property(lma GLOBAL PROPERTY ${parent}_NAME)
218      set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_LMA ${lma})
219      set(SECTION_LMA ${lma})
220    endif()
221  else()
222    set(parent ${SECTION_SYSTEM})
223  endif()
224  if(SECTION_TYPE STREQUAL "LINKER_SCRIPT_FOOTER")
225    set(SECTION_VMA) # pretend that we have no VMA, so the section ends up in
226                     # the general heap of sections directly below the system
227    set(parent ${SECTION_SYSTEM})
228  endif()
229
230  set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_PARENT ${parent})
231  add_section(OBJECT ${parent} SECTION ${SECTION_NAME} ADDRESS ${SECTION_ADDRESS} VMA ${SECTION_VMA})
232endfunction()
233
234function(create_symbol)
235  cmake_parse_arguments(SYM "" "OBJECT;EXPR;SIZE;SUBALIGN;SYMBOL" "" ${ARGN})
236
237  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL} TRUE)
238  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_OBJ_TYPE SYMBOL)
239  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_NAME     ${SYM_SYMBOL})
240  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_EXPR     ${SYM_EXPR})
241  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_SIZE     ${SYM_SIZE})
242  set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_SYMBOL   ${SYM_SYMBOL})
243
244  set_property(GLOBAL PROPERTY SYMBOL_TABLE_${SYM_SYMBOL} ${SYM_SYMBOL})
245
246  add_symbol(OBJECT ${SYM_OBJECT} SYMBOL SYMBOL_${SYM_SYMBOL})
247endfunction()
248
249#
250# Create functions - end
251#
252
253#
254# Add functions - start
255#
256function(add_region)
257  cmake_parse_arguments(ADD_REGION "" "OBJECT;REGION" "" ${ARGN})
258
259  get_property(exists GLOBAL PROPERTY ${ADD_REGION_OBJECT})
260  if(NOT exists)
261    message(FATAL_ERROR
262      "Adding region ${ADD_REGION_REGION} to none-existing object: "
263      "${ADD_REGION_OBJECT}"
264    )
265  endif()
266
267  set_property(GLOBAL PROPERTY ${ADD_REGION_REGION}_PARENT ${ADD_REGION_OBJECT})
268  set_property(GLOBAL APPEND PROPERTY ${ADD_REGION_OBJECT}_REGIONS ${ADD_REGION_REGION})
269endfunction()
270
271# add_group OBJECT o GROUP g adds group g to object o
272function(add_group)
273  cmake_parse_arguments(ADD_GROUP "" "OBJECT;GROUP" "" ${ARGN})
274
275  get_property(exists GLOBAL PROPERTY ${ADD_GROUP_OBJECT})
276  if(NOT exists)
277    message(FATAL_ERROR
278      "Adding group ${ADD_GROUP_GROUP} to none-existing object: "
279      "${ADD_GROUP_OBJECT}"
280    )
281  endif()
282
283  get_property(vma GLOBAL PROPERTY ${ADD_GROUP_GROUP}_VMA)
284  get_property(object_name GLOBAL PROPERTY ${ADD_GROUP_OBJECT}_NAME)
285
286  if((NOT DEFINED vma) OR ("${vma}" STREQUAL ${object_name}))
287    set_property(GLOBAL APPEND PROPERTY ${ADD_GROUP_OBJECT}_GROUPS ${ADD_GROUP_GROUP})
288  else()
289    set_property(GLOBAL APPEND PROPERTY ${ADD_GROUP_OBJECT}_${vma}_GROUPS ${ADD_GROUP_GROUP})
290  endif()
291endfunction()
292
293function(add_section)
294  cmake_parse_arguments(ADD_SECTION "" "OBJECT;SECTION;ADDRESS;VMA" "" ${ARGN})
295
296  if(DEFINED ADD_SECTION_OBJECT)
297    get_property(type GLOBAL PROPERTY ${ADD_SECTION_OBJECT}_OBJ_TYPE)
298    get_property(object_name GLOBAL PROPERTY ${ADD_SECTION_OBJECT}_NAME)
299
300    if(NOT DEFINED type)
301      message(FATAL_ERROR
302              "Adding section ${ADD_SECTION_SECTION} to "
303              "none-existing object: ${ADD_SECTION_OBJECT}"
304      )
305    endif()
306  else()
307    set(ADD_SECTION_OBJECT RELOCATEABLE)
308  endif()
309
310  if("${ADD_SECTION_VMA}" STREQUAL "${object_name}" AND DEFINED ADD_SECTION_ADDRESS)
311    set_property(GLOBAL APPEND PROPERTY
312      ${ADD_SECTION_OBJECT}_SECTIONS_FIXED
313      SECTION_${ADD_SECTION_SECTION}
314    )
315  elseif(NOT DEFINED ADD_SECTION_VMA AND DEFINED SECTION_ADDRESS)
316    set_property(GLOBAL APPEND PROPERTY
317      ${ADD_SECTION_OBJECT}_SECTIONS_FIXED
318      SECTION_${ADD_SECTION_SECTION}
319    )
320  elseif("${ADD_SECTION_VMA}" STREQUAL "${object_name}")
321    set_property(GLOBAL APPEND PROPERTY
322      ${ADD_SECTION_OBJECT}_SECTIONS
323      SECTION_${ADD_SECTION_SECTION}
324    )
325  elseif(NOT DEFINED ADD_SECTION_VMA)
326    set_property(GLOBAL APPEND PROPERTY
327      ${ADD_SECTION_OBJECT}_SECTIONS
328      SECTION_${ADD_SECTION_SECTION}
329    )
330  elseif(DEFINED SECTION_ADDRESS)
331    set_property(GLOBAL APPEND PROPERTY
332      ${ADD_SECTION_OBJECT}_${ADD_SECTION_VMA}_SECTIONS_FIXED
333      SECTION_${ADD_SECTION_SECTION}
334    )
335  else()
336    set_property(GLOBAL APPEND PROPERTY
337      ${ADD_SECTION_OBJECT}_${ADD_SECTION_VMA}_SECTIONS
338      SECTION_${ADD_SECTION_SECTION}
339    )
340  endif()
341endfunction()
342
343function(add_symbol)
344  cmake_parse_arguments(ADD_SYMBOL "" "OBJECT;SYMBOL" "" ${ARGN})
345
346  # Section can be fixed address or not, VMA == LMA, .
347  #
348  get_property(exists GLOBAL PROPERTY ${ADD_SYMBOL_OBJECT})
349  if(NOT exists)
350    message(FATAL_ERROR
351      "Adding symbol ${ADD_SYMBOL_SYMBOL} to none-existing object: "
352      "${ADD_SYMBOL_OBJECT}"
353    )
354  endif()
355
356  set_property(GLOBAL APPEND PROPERTY ${ADD_SYMBOL_OBJECT}_SYMBOLS ${ADD_SYMBOL_SYMBOL})
357endfunction()
358
359#
360# Add functions - end
361#
362
363#
364# Retrieval functions - start
365#
366function(find_object)
367  cmake_parse_arguments(FIND "" "OBJECT;NAME" "" ${ARGN})
368
369  get_property(REGION  GLOBAL PROPERTY REGION_${FIND_NAME})
370  get_property(GROUP   GLOBAL PROPERTY GROUP_${FIND_NAME})
371  get_property(SECTION GLOBAL PROPERTY SECTION_${FIND_NAME})
372
373  if(REGION)
374    set(${FIND_OBJECT} REGION_${FIND_NAME} PARENT_SCOPE)
375  elseif(GROUP)
376    set(${FIND_OBJECT} GROUP_${FIND_NAME} PARENT_SCOPE)
377  elseif(SECTION)
378    set(${FIND_OBJECT} SECTION_${FIND_NAME} PARENT_SCOPE)
379  else()
380    message(WARNING "No object with name ${FIND_NAME} could be found.")
381  endif()
382endfunction()
383
384# get_object(LIST l OBJECT o TYPE t)
385# sets l to a list of objects of type t that are children of o
386function(get_objects)
387  cmake_parse_arguments(GET "" "LIST;OBJECT;TYPE" "" ${ARGN})
388
389  # Get what type of object we are starting from
390  get_property(type GLOBAL PROPERTY ${GET_OBJECT}_OBJ_TYPE)
391
392  if(${type} STREQUAL SECTION)
393    # A section doesn't have sub-items.
394    return()
395  endif()
396
397  if(NOT (${GET_TYPE} STREQUAL SECTION
398     OR   ${GET_TYPE} STREQUAL GROUP)
399  )
400    message(WARNING "Only retrieval of SECTION GROUP objects are supported.")
401    return()
402  endif()
403
404  set(out)
405
406  # Find (other) regions in our system
407  get_parent(OBJECT ${GET_OBJECT} PARENT parent TYPE SYSTEM)
408  get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
409  list(REMOVE_ITEM regions ${GET_OBJECT})
410
411  if(${GET_TYPE} STREQUAL SECTION)
412    # If we are retrieving sections, then we need to get _SECTIONS_FIXED,
413    # sections from sub-groups, and immediate setion children
414    get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_SECTIONS_FIXED)
415    list(APPEND out ${sections})
416
417    get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_GROUPS)
418    foreach(group ${groups})
419      get_objects(LIST sections OBJECT ${group} TYPE ${GET_TYPE})
420      list(APPEND out ${sections})
421    endforeach()
422
423    get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_SECTIONS)
424    list(APPEND out ${sections})
425
426    # Now pick up sections from each region via the _vma_ properties.
427    foreach(region ${regions})
428      get_property(vma GLOBAL PROPERTY ${region}_NAME)
429
430      get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_${vma}_SECTIONS_FIXED)
431      list(APPEND out ${sections})
432
433      get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_${vma}_GROUPS)
434      foreach(group ${groups})
435        get_objects(LIST sections OBJECT ${group} TYPE ${GET_TYPE})
436        list(APPEND out ${sections})
437      endforeach()
438
439      get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_${vma}_SECTIONS)
440      list(APPEND out ${sections})
441    endforeach()
442  endif()
443
444  if(${GET_TYPE} STREQUAL GROUP)
445    # For groups we add immediate sub-groups, and all their descendant groups,
446    # and all the _vma_ groups and descendants
447    get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_GROUPS)
448    list(APPEND out ${groups})
449
450    foreach(group ${groups})
451      get_objects(LIST subgroups OBJECT ${group} TYPE ${GET_TYPE})
452      list(APPEND out ${subgroups})
453    endforeach()
454
455    foreach(region ${regions})
456      get_property(vma GLOBAL PROPERTY ${region}_NAME)
457
458      get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_${vma}_GROUPS)
459      list(APPEND out ${groups})
460
461      foreach(group ${groups})
462        get_objects(LIST subgroups OBJECT ${group} TYPE ${GET_TYPE})
463        list(APPEND out ${subgroups})
464      endforeach()
465    endforeach()
466  endif()
467
468  set(${GET_LIST} ${out} PARENT_SCOPE)
469endfunction()
470
471#
472# Retrieval functions - end
473#
474
475function(is_empty)
476  cmake_parse_arguments(IS_EMPTY "" "OBJECT" "" ${ARGN})
477
478  get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_SECTIONS_FIXED)
479  if(DEFINED sections)
480    set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
481    return()
482  endif()
483
484  get_property(groups GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_GROUPS)
485  if(DEFINED groups)
486    set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
487    return()
488  endif()
489
490
491  get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_SECTIONS)
492  if(DEFINED sections)
493    set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
494    return()
495  endif()
496
497  get_parent(OBJECT ${IS_EMPTY_OBJECT} PARENT parent TYPE SYSTEM)
498  get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
499  list(REMOVE_ITEM regions ${IS_EMPTY_OBJECT})
500  foreach(region ${regions})
501    get_property(vma GLOBAL PROPERTY ${region}_NAME)
502    get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_SECTIONS_FIXED)
503    if(DEFINED sections)
504      set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
505      return()
506    endif()
507
508    get_property(groups GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_GROUPS)
509    if(DEFINED groups)
510      set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
511      return()
512    endif()
513
514    get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_SECTIONS)
515    if(DEFINED sections)
516      set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE)
517      return()
518    endif()
519  endforeach()
520  set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY TRUE)
521endfunction()
522
523# This function post process the region for easier use.
524#
525# This is common post processing.
526# If the calling <linker>_script.cmake generator implements its own
527# process_region(), then the process_region_common() must be called explicitly
528# from the process_region() from the <linker>_script.cmake generator.
529#
530# This allows a custom <linker>_script.cmake generator to completely disable
531# the common post processing of regions.
532#
533# Tasks:
534# - Apply missing settings, such as initial address for first section in a region.
535# - Symbol names on sections
536# - Ordered list of all sections for easier retrieval on printing and configuration.
537function(process_region_common)
538  cmake_parse_arguments(REGION_COMMON "" "OBJECT" "" ${ARGN})
539
540  is_empty(OBJECT ${REGION_COMMON_OBJECT})
541
542  set(sections)
543  get_objects(LIST sections OBJECT ${REGION_COMMON_OBJECT} TYPE SECTION)
544  set_property(GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_SECTION_LIST_ORDERED ${sections})
545
546  set(groups)
547  get_objects(LIST groups OBJECT ${REGION_COMMON_OBJECT} TYPE GROUP)
548  set_property(GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_GROUP_LIST_ORDERED ${groups})
549
550  list(LENGTH sections section_count)
551  if(section_count GREATER 0)
552    list(GET sections 0 section)
553    get_property(address GLOBAL PROPERTY ${section}_ADDRESS)
554    if(NOT DEFINED address)
555      get_parent(OBJECT ${REGION_COMMON_OBJECT} PARENT parent TYPE REGION)
556      get_property(address GLOBAL PROPERTY ${parent}_ADDRESS)
557      set_property(GLOBAL PROPERTY ${section}_ADDRESS ${address})
558    endif()
559  endif()
560
561  # Loop over other regions with the same parent
562  get_parent(OBJECT ${REGION_COMMON_OBJECT} PARENT parent TYPE SYSTEM)
563  get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
564  list(REMOVE_ITEM regions ${REGION_COMMON_OBJECT})
565  foreach(region ${regions})
566    get_property(vma GLOBAL PROPERTY ${region}_NAME)
567    set(sections_${vma})
568    get_property(sections GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_SECTIONS_FIXED)
569    list(APPEND sections_${vma} ${sections})
570
571    get_property(groups GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_GROUPS)
572    foreach(group ${groups})
573      get_objects(LIST sections OBJECT ${group} TYPE SECTION)
574      list(APPEND sections_${vma} ${sections})
575    endforeach()
576
577    get_property(sections GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_SECTIONS)
578    list(APPEND sections_${vma} ${sections})
579
580    list(LENGTH sections_${vma} section_count)
581    if(section_count GREATER 0)
582      list(GET sections_${vma} 0 section)
583      get_property(address GLOBAL PROPERTY ${section}_ADDRESS)
584      if(NOT DEFINED address)
585        get_property(address GLOBAL PROPERTY ${region}_ADDRESS)
586        set_property(GLOBAL PROPERTY ${section}_ADDRESS ${address})
587      endif()
588    endif()
589  endforeach()
590endfunction()
591
592if(NOT COMMAND process_region)
593  function(process_region)
594    process_region_common(${ARGN})
595  endfunction()
596endif()
597
598
599#
600# String functions - start
601#
602# Each linker must implement their own <type>_to_string() functions to
603# generate a correct linker script.
604#
605if(NOT COMMAND system_to_string)
606  function(system_to_string)
607    message(WARNING "No linker defined function found. Please implement a "
608                    "system_to_string() function for this linker."
609    )
610  endfunction()
611endif()
612
613if(NOT COMMAND group_to_string)
614  function(group_to_string)
615    message(WARNING "No linker defined function found. Please implement a "
616                    "group_to_string() function for this linker."
617    )
618  endfunction()
619endif()
620
621if(NOT COMMAND section_to_string)
622  function(section_to_string)
623    message(WARNING "No linker defined function found. Please implement a "
624                    "section_to_string() function for this linker."
625    )
626  endfunction()
627endif()
628
629if(NOT COMMAND symbol_to_string)
630  function(symbol_to_string)
631    message(WARNING "No linker defined function found. Please implement a "
632                    "symbol_to_string() function for this linker."
633    )
634  endfunction()
635endif()
636
637function(to_string)
638  cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
639
640  get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE)
641
642  if("${type}" STREQUAL SYSTEM)
643    system_to_string(OBJECT ${STRING_OBJECT} STRING ${STRING_STRING})
644  elseif(("${type}" STREQUAL REGION) OR ("${type}" STREQUAL GROUP))
645    group_to_string(OBJECT ${STRING_OBJECT} STRING ${STRING_STRING})
646  elseif("${type}" STREQUAL SECTION)
647    section_to_string(SECTION ${STRING_OBJECT} STRING ${STRING_STRING})
648  elseif("${type}" STREQUAL SYMBOL)
649    symbol_to_string(SYMBOL ${STRING_OBJECT} STRING ${STRING_STRING})
650  endif()
651
652  set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
653endfunction()
654
655#
656# String functions - end
657#
658
659## Preprocess and gather input
660foreach(VAR ${VARIABLES})
661  if("${VAR}" MATCHES "^{(.*)}$")
662    cmake_parse_arguments(VAR "" "VAR;VALUE" "PASS" ${CMAKE_MATCH_1})
663
664    if(DEFINED VAR_PASS)
665      is_active_in_pass(active ${PASS} "${VAR_PASS}")
666      if(NOT active)
667        continue()
668      endif()
669    endif()
670
671    set(${VAR_VAR} "${VAR_VALUE}" CACHE INTERNAL "")
672  endif()
673endforeach()
674
675# By the input we have INCLUDES defined that contains the files that we need
676# to include depending on linker pass.
677foreach(file ${INCLUDES})
678  if("${file}" MATCHES "^{(.*)}$")
679    cmake_parse_arguments(INC "" "KCONFIG;HEADER;CMAKE" "PASS" ${CMAKE_MATCH_1})
680
681    if(DEFINED INC_PASS)
682      is_active_in_pass(active ${PASS} "${INC_PASS}")
683      if(NOT active)
684        continue()
685      endif()
686    endif()
687
688    if(CMAKE_VERBOSE_MAKEFILE)
689      message("Reading file ${INC_KCONFIG}${INC_HEADER}${INC_CMAKE}")
690    endif()
691
692    if(INC_KCONFIG)
693      import_kconfig(CONFIG ${INC_KCONFIG})
694    elseif(INC_CMAKE)
695      include(${INC_CMAKE})
696    elseif(INC_HEADER)
697      list(APPEND PREPROCESSOR_FILES ${INC_HEADER})
698    endif()
699  endif()
700endforeach()
701
702# For now, lets start with @FOO@ and store each #define FOO value as a global
703# property AT_VAR_FOO (prefix to avoid name clashes).
704# We will do all the replacements in the input lists before giving them to the
705# generator functions.
706set(VAR_DEF_REGEX "#define ([A-Za-z0-9_]+)[ \t\r\n]+(.+)")
707foreach(file IN LISTS PREPROCESSOR_FILES )
708  if(EXISTS ${file})
709    file(STRINGS ${file} defs REGEX ${VAR_DEF_REGEX})
710    foreach(def ${defs})
711      if(${def} MATCHES ${VAR_DEF_REGEX})
712        set("AT_VAR_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}")
713      endif()
714    endforeach()
715  else()
716    message("Missing file ${file}")
717  endif()
718endforeach()
719
720# To pickup information gathered by the scripts from the previous pass, we use
721# the syntax @FOO@ where FOO is a cmake variable name
722function(do_var_replace_in res_ptr src)
723  string(REGEX MATCHALL "@([^@]*)@" match_res "${src}")
724  foreach(match IN LISTS match_res)
725    string(REPLACE "@" "" expr ${match})
726    # the variable expression is as follows:
727    # @NAME[,undef:VALUE]@ Where the VALUE gets picked if we dont find NAME
728    string(REPLACE "," ";" expr ${expr})
729    list(GET expr 0 var)
730    if(DEFINED "AT_VAR_${var}")
731      set(value "${AT_VAR_${var}}")
732    elseif(DEFINED ${var}) # set by zephyr_linker_include_generated files
733      set(value "${${var}}")
734    elseif("${expr}" MATCHES ";undef:([^,]*)")
735      set(value "${CMAKE_MATCH_1}")
736    else()
737      set(value "${match}")
738      # can't warn here because we can't check for what is relevant in this pass
739      # message(WARNING "Missing definition for ${match}")
740    endif()
741
742    if(CMAKE_VERBOSE_MAKEFILE)
743      message("Using variable ${match} with value ${value}")
744    endif()
745    string(REPLACE "${match}" "${value}" src "${src}")
746  endforeach()
747  set(${res_ptr} "${src}" PARENT_SCOPE)
748endfunction()
749
750foreach(input IN ITEMS "MEMORY_REGIONS" "GROUPS" "SECTIONS" "SECTION_SETTINGS")
751  do_var_replace_in(${input} "${${input}}")
752endforeach()
753
754
755create_system(OBJECT new_system NAME ZEPHYR_LINKER_v1 FORMAT ${FORMAT} ENTRY ${ENTRY})
756
757# Sorting the memory sections in ascending order.
758foreach(region ${MEMORY_REGIONS})
759  if("${region}" MATCHES "^{(.*)}$")
760    cmake_parse_arguments(REGION "" "NAME;START" "" ${CMAKE_MATCH_1})
761    math(EXPR start_dec "${REGION_START}" OUTPUT_FORMAT DECIMAL)
762    set(region_id ${start_dec}_${REGION_NAME})
763    set(region_${region_id} ${region})
764    string(REPLACE ";" "\;" region_${region_id} "${region_${region_id}}")
765    list(APPEND region_sort ${region_id})
766  endif()
767endforeach()
768
769list(SORT region_sort COMPARE NATURAL)
770set(MEMORY_REGIONS_SORTED)
771foreach(region_start ${region_sort})
772  list(APPEND MEMORY_REGIONS_SORTED "${region_${region_start}}")
773endforeach()
774# sorting complete.
775
776foreach(region ${MEMORY_REGIONS_SORTED})
777  if("${region}" MATCHES "^{(.*)}$")
778    create_region(OBJECT new_region ${CMAKE_MATCH_1})
779    add_region(OBJECT ${new_system} REGION ${new_region})
780  endif()
781endforeach()
782
783foreach(group ${GROUPS})
784  if("${group}" MATCHES "^{(.*)}$")
785    create_group(OBJECT new_group ${CMAKE_MATCH_1})
786  endif()
787endforeach()
788
789foreach(section ${SECTIONS} ${DEVICE_API_SECTIONS})
790  if("${section}" MATCHES "^{(.*)}$")
791    create_section(${CMAKE_MATCH_1} SYSTEM ${new_system})
792  endif()
793endforeach()
794
795foreach(symbol ${SYMBOLS})
796  if("${symbol}" MATCHES "^{(.*)}$")
797    create_symbol(OBJECT ${new_system} ${CMAKE_MATCH_1})
798  endif()
799endforeach()
800
801get_property(regions GLOBAL PROPERTY ${new_system}_REGIONS)
802foreach(region ${regions})
803  process_region(OBJECT ${region})
804endforeach()
805
806set(OUT)
807to_string(OBJECT ${new_system} STRING OUT)
808
809if(OUT_FILE)
810  file(WRITE ${OUT_FILE} "${OUT}")
811endif()
812