#--------------------------------------------------------- # # CMT module # # Parsing of a tree of requirements files # - construct CMTPATH from the project graph (starts from CMTPROJECTPATH) # - interprets & follows the use statements to reach used packages # - parses CMT statements in requirements files # - translate 'library' & 'application' statements into 'add_library' & 'add_executable' calls # - translate 'macro' statements into global properties # # Build policy: # - binary files are constructed into the 'installarea' directory of each project # - thus build actions are restricted to packages of a single project # - libraries of used projects are used pre-built from the respective installareas # # System properties to hold the CMT database: # # CMTPROJECTPATH # CMTPATH # # CMT_CURRENT_PROJECT # CMT_CURRENT_PATH # CMT_PROJECTS # _CMT__PROJECT_PROPERTIES # CMT_STRUCTURE_STRATEGY # # CMT_USES # _CMT__USE_PROPERTIES # _CMT__USE_CLIENTS # # CMT_SYMBOLS # CMT_MACROS # CMT_SETS # CMT_ALIAS # CMT_PATHS # CMT_ACTIONS # _CMT_ # _CMT_[] # _CMT__SYMBOL_PROPERTIES # _CMT__TAGGED_VALUES # _CMT__ m=A(append)|P(prepend)|R(remove) # _CMT__[] # _CMT___SYMBOL_PROPERTIES # _CMT___TAGGED_VALUES # # CMT_PATTERNS # CMT_GLOBAL_PATTERNS # CMT_CMTPATH_PATTERNS # _CMT__PATTERN_DEFINITION # # CMT_TAGS # CMT_ACTIVE_TAGS # _CMT__TAG_PARENTS # _CMT__TAG_CLIENTS # # CMT_CMAKE_MODULES # #--------------------------------------------------------- #--------------------------------------------------------- # Utility to print a list # macro(dumplist) foreach(w IN LISTS words) message("DL> ${w}") endforeach() endmacro() macro(getword item var) list(GET words ${item} ${var}) endmacro() macro(nwords var) list(LENGTH words ${var}) math(EXPR ${var} "${${var}} - 1") endmacro() #--------------------------------------------------------- # Utility to print the result of a parsing of a CMT statement # Each word of a line has been stored into a set of variables named w_ k=1..n # Words are either simple words separated by spaces or groups of words enclosed in quotes # macro(show_cmt_line text) if(${n} GREATER 0) foreach(k RANGE 1 ${n}) set(x "w_${k}") message("${text}> w_${k}: [${${x}}]") endforeach() endif() endmacro() #--------------------------------------------------------- function(cmt_append_unique_property property_name value) get_property(property GLOBAL PROPERTY "${property_name}") list(FIND property "${value}" index) #message("cmt_append_unique_property> property_name=${property_name} value=${value} index=${index}") if("${index}" EQUAL "-1") set_property(GLOBAL APPEND PROPERTY "${property_name}" "${value}") endif() endfunction() #--------------------------------------------------------- function(cmt_find_project_from_path path result) string(REGEX REPLACE "/[ ]*$" "" path "${path}") string(REGEX REPLACE "[^/]*[/]" "" project "${path}") set(${result} "${project}" PARENT_SCOPE) endfunction() #--------------------------------------------------------- function(cmt_modify_symbol_value type name value modifier result) get_property(old_value GLOBAL PROPERTY "${name}") string(REGEX REPLACE "^['][']$" "" value "${value}") string(REGEX REPLACE "^[\"][\"]$" "" value "${value}") set(arg "${value}") set(path_mode FALSE) set(separator "") if(("${type}" STREQUAL "${path}") AND (NOT("${value}" STREQUAL ""))) set(path_mode TRUE) set(separator ":") endif() if("${modifier}" STREQUAL "D") elseif("${modifier}" STREQUAL "A") set(value "${old_value}${separator}${value}") elseif("${modifier}" STREQUAL "P") set(value "${value}${separator}${old_value}") elseif("${modifier}" STREQUAL "R") if(${path_mode}) string(REGEX REPLACE "^[^${separator}]*${arg}[^${separator}]*$" "" value "${old_value}") string(REGEX REPLACE "^[^${separator}]*${arg}[^${separator}]*${separator}" "" value "${value}") string(REGEX REPLACE "${separator}[^${separator}]*${arg}[^${separator}]*$" "" value "${value}") string(REGEX REPLACE "${separator}[^${separator}]*${arg}[^${separator}]*${separator}" "${separator}" value "${value}") else() string(REPLACE "${value}" "" value "${old_value}") endif() endif() set_property(GLOBAL PROPERTY "${name}" "${value}") get_property(tab GLOBAL PROPERTY TAB) #message("${tab}cmt_modify_symbol_value> name=${name} [${old_value}] ${modifier} [${arg}] => [${value}]") set(${result} "${value}" PARENT_SCOPE) endfunction() #------------------------------------------- # Interprets any 'symbol' statement # Translate the symbol into a global property # function(cmt_symbol type project path package version prefix line modifier) get_property(tab GLOBAL PROPERTY TAB) message("${tab}cmt_symbol> ${line}") #show_cmt_line("a") nwords(n) if(${n} LESS 2) return() endif() getword(1 name) message("${tab}cmt_symbol> ${type} ${name} ${n}") if(${n} LESS 2) return() endif() getword(2 default_value) cmt_append_unique_property(CMT_SYMBOLS "${name}") if("${type}" STREQUAL "macro") cmt_append_unique_property("CMT_MACROS" "${name}") elseif("${type}" STREQUAL "set") cmt_append_unique_property("CMT_SETS" "${name}") elseif("${type}" STREQUAL "path") cmt_append_unique_property("CMT_PATHS" "${name}") elseif("${type}" STREQUAL "action") cmt_append_unique_property("CMT_ACTIONS" "${name}") elseif("${type}" STREQUAL "alias") cmt_append_unique_property("CMT_ALIAS" "${name}") endif() cmt_modify_symbol_value("${type}" "_CMT_${name}" "${default_value}" "${modifier}" new_value) message("${tab}cmt_symbol> [${modifier}] Default value=[${default_value}] -> [${new_value}]") set_property(GLOBAL PROPERTY "_CMT_${name}_SYMBOL_PROPERTIES" "${path};${package}") if(${n} LESS 5) return() endif() math(EXPR tagged_values "(${n} - 2) / 2") foreach(k RANGE 1 ${tagged_values}) math(EXPR itag "${k}*2 + 1") math(EXPR ivalue "${k}*2 + 2") if(${n} GREATER ${itag}) getword(itag tag) getword(ivalue value) cmt_append_unique_property("_CMT_${name}_TAGGED_VALUES" "${tag}") cmt_modify_symbol_value("${type}" "_CMT_${name}[${tag}]" "${value}" "${modifier}" new_value) #message("${tab}cmt_symbol> [${modifier}] Tagged value for ${tag}=[${value}] -> [${new_value}]") endif() endforeach() endfunction() #------------------------------------------- # Expand a macro by recursively expand macro references # function(cmt_get_macro_value name value) set(v "$ENV{${name}}") #message("cmt_get_macro_value> name=${name} env=${v}") if("${v}" STREQUAL "") # This is not an environment variable cmt_select_macro_value("${name}" v) #get_property(v GLOBAL PROPERTY "_CMT_${name}") #message("cmt_get_macro_value> name=${name} v=${v}") # Loop over occurrences of macro references inside ${v} while(TRUE) if("${v}" MATCHES "[$][(][^]]*[)]") string(REGEX REPLACE "[^$]*[$][(]([^)]*)[)].*" "\\1" ref "${v}") #message("macro=${name} v=${v} has a reference to ${ref}") cmt_get_macro_value(${ref} refvalue) string(REGEX REPLACE "[$][(]${ref}[)]" "${refvalue}" v "${v}") else() break() endif() endwhile() endif() if("${v}" MATCHES "^[\"].*[\"]$") string(REGEX REPLACE "^[\"](.*)[\"]$" "\\1" v "${v}") elseif("${v}" MATCHES "^['].*[']$") string(REGEX REPLACE "^['](.*)[']$" "\\1" v "${v}") endif() set(${value} "${v}" PARENT_SCOPE) endfunction() #------------------------------------------- # Interprets a 'library' statement # Translate the library statement into a 'add_library' statement # differentiate the behaviour whether the project of this package is same as CMT_CURRENT_PROJECT # function(cmt_library project path package version prefix words) #message("cmt_library> cmt(${package})> ${words}") nwords(n) get_property(current_project GLOBAL PROPERTY CMT_CURRENT_PROJECT) message("cmt_library> current_project=${current_project} project=${project} path=${path} package=${package} ${words}") if("${project}" STREQUAL "${current_project}") #message("cmt_library> in current project") include_directories(${path}/${prefix}${package}${version}/src) foreach(k RANGE 2 ${n}) getword(${k} word) #message("cmt_library> sources=[${path}]/${prefix}${package}${version}/src/${word}") unset(fs) file(GLOB fs "${path}/${prefix}${package}${version}/src/${word}") foreach(f IN LISTS fs) message("cmt_library> source=${f}") list(APPEND sources ${f}) endforeach() endforeach() getword(1 name) message(">>>>>add_library(${name} SHARED ${sources})") add_library(${name} SHARED ${sources}) else() #message("cmt_library> out of current project") endif() cmt_has_macro("${name}_linkopts" ok) if(ok) cmt_select_macro_value("${name}_linkopts" value) string(REPLACE " " ";" values "${value}") message(">>>>>target_link_libraries(${name} ${values})") target_link_libraries(${name} ${values}) else() #message("cmt_application> no linkopts") endif() endfunction() #------------------------------------------- # Interprets a 'application' statement # Translate the 'application' statement into a 'add_executable' statement # function(cmt_application project path package version prefix words) message("cmt_application> cmt(${package})> ${words}") nwords(n) message(">>>>>include_directories(${path}/${prefix}${package}${version}/src)") include_directories(${path}/${prefix}${package}${version}/src) unset(sources) foreach(k RANGE 2 ${n}) getword(${k} word) #message("cmt_application> sources=${path}/${prefix}${package}${version}/src/${word}") unset(fs) file(GLOB fs "${path}/${prefix}${package}${version}/src/${word}") foreach(f IN LISTS fs) #message("cmt_application> source=${f}") list(APPEND sources ${f}) endforeach() endforeach() if("${sources}" STREQUAL "") #message("Sources not yet available") return() endif() getword(1 name) message(">>>>>add_executable(${name} ${sources})") add_executable(${name} ${sources}) cmt_has_macro("${name}_linkopts" ok) if(ok) cmt_select_macro_value("${name}_linkopts" value) string(REPLACE " " ";" values "${value}") message(">>>>>target_link_libraries(${name} ${values})") target_link_libraries(${name} ${values}) else() #message("cmt_application> no linkopts") endif() endfunction() #------------------------------------------- # Interprets a 'document' statement # Translate the 'document' statement # function(cmt_document project path package version prefix words) #message("cmt_document> cmt(${package})> ${words}") getword(1 module) getword(2 target) #get_property(command GLOBAL PROPERTY "_CMT_${module}_MODULE_PROPERTIES") list(REMOVE_AT words 0 1 2) cmt_do("${module}" "${target}" ${words}) endfunction() function(cmt_custom_build project path package version prefix words) message("cmt_custom_build> cmt(${package})> ${words}") getword(1 name) message("include ${path}/${prefix}/${package}/${version}/cmt/${name}.cmake") include("${path}/${prefix}/${package}/${version}/cmt/${name}.cmake") cmt_append_unique_property(CMT_MODULES "${name}") #set_property(GLOBAL PROPERTY "_CMT_${name}_MODULE_PROPERTIES" "${command}") endfunction() #------------------------------------------- # Interprets a 'tag' statement # Define a tag and all its parents # # the statement # tag T t1 t2 # tag V t1 t3 # # means that when T is ON, both t1 & t2 are ON, while when V is ON, both t1 & t3 # T & V are parents of t1 # T is parent of t2 # V is parent of t3 # thus, in order to know the state of t1, we interrogate all its parents (recursively) # function(cmt_tag project path package version prefix words) #message("cmt_tag> ${words}") nwords(n) foreach(k RANGE 1 ${n}) getword(${k} p) # first defines the tag #k cmt_append_unique_property(CMT_TAGS "${p}") if(${k} EQUAL 1) set(tag ${p}) else() # the first tag of the line is parent of all others cmt_append_unique_property("_CMT_${p}_TAG_PARENTS" "${tag}") cmt_append_unique_property("_CMT_${tag}_TAG_CLIENTS" "${p}") endif() endforeach() endfunction() #--------------------------------------------------------- function(cmt_apply_tag project path package version prefix words) #message("cmt_apply_tag> ${words}") getword(1 tag) cmt_activate_tag("${tag}") endfunction() #---------------------------------------------- # expected syntax: # # pattern|cmtpath_pattern [-global] [ ; ] # function(cmt_pattern project path package version prefix words type) #message("cmt_pattern> [${words}]") getword(1 pattern) if("${type}" STREQUAL "cmtpath") cmt_append_unique_property(CMT_CMTPATH_PATTERNS "${pattern}") endif() list(REMOVE_AT words 0) if("${pattern}" STREQUAL "-global") list(REMOVE_AT words 0) getword(0 pattern) cmt_append_unique_property(CMT_GLOBAL_PATTERNS "${pattern}") endif() cmt_append_unique_property(CMT_PATTERNS "${pattern}") set_property(GLOBAL PROPERTY "_CMT_${pattern}_PATTERN_DEFINITION" "") list(REMOVE_AT words 0) nwords(n) if(n GREATER 0) set(ws) foreach(k RANGE 0 ${n}) #message("cmt_pattern> n=${n} k=${k}") getword(${k} word) if("${word}" STREQUAL "@eol@") set_property(GLOBAL APPEND PROPERTY "_CMT_${pattern}_PATTERN_DEFINITION" "${ws}") set(ws) else() if(word MATCHES " ") set(ws "${ws} '${word}'") else() set(ws "${ws} ${word}") endif() endif() endforeach() list(LENGTH ws len) if(NOT(len EQUAL 0)) set_property(GLOBAL APPEND PROPERTY "_CMT_${pattern}_PATTERN_DEFINITION" "${ws}") endif() else() set_property(GLOBAL APPEND PROPERTY "_CMT_${pattern}_PATTERN_DEFINITION" "") endif() endfunction() #--------------------------------------------------------- function(cmt_apply_pattern project path package version prefix words) get_property(tab GLOBAL PROPERTY TAB) #message("${tab}cmt_apply_pattern> ${words}") getword(1 pattern) list(REMOVE_AT words 0 1) unset(templates) unset(values) list(APPEND templates "project") list(APPEND values "${project}") list(APPEND templates "path") list(APPEND values "${path}") list(APPEND templates "package") list(APPEND values "${package}") list(APPEND templates "version") list(APPEND values "${version}") list(APPEND templates "prefix") list(APPEND values "${prefix}") nwords(n) if(n GREATER 0) foreach(k RANGE 0 ${n}) #message("${tab}cmt_apply_pattern> n=${n} k=${k}") getword(${k} arg) # all arguments are of the form