summaryrefslogtreecommitdiffstats
path: root/cmake/script/feature_verification.cmake
blob: 2ec1eabd5b293147f4fda3d67f0c4cefa6e9310c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#[[
 # Copyright (c) 2026 Alexey Gavrilov <alexey.gavrilov@mail.com>
 #
 # This file is part of ObjectiveOS.
 #
 # ObjectiveOS is free software: you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
 # Foundation, either version 3 of the License, or (at your option) any later
 # version.
 #
 # ObjectiveOS is distributed in the hope that it will be useful, but WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License along with
 # ObjectiveOS. If not, see <https://www.gnu.org/licenses/>.
 ]]

#[[
 # This cmake script works like passed feature definitions handling.
 # Parameters specify via command line -D option. FEATURE_OUT_FILEPATH is
 # necessary, and means path to the features description file generated by
 # correspondent module.
 ]]

#[[
 # Read the out file created by the feature module, and instance populated
 # variables in current cmake environment. Receive only one argument - path to the
 # feature module file to read variables from
 ]]
function(readCacheFile filepath)
    if(NOT EXISTS ${filepath} OR NOT IS_READABLE ${filepath})
        message(FATAL_ERROR "${filepath} not exists")
    endif()

    file(STRINGS ${filepath} vardefines REGEX "^[^#|//][^:]*(:.*)?=(\".+\")")
    foreach(line IN LISTS vardefines)
        if(line MATCHES "^([^:]+)(:[A-Z]+)?=\"(.+)\"")
            set(${CMAKE_MATCH_1} ${CMAKE_MATCH_3} PARENT_SCOPE)
        endif()
    endforeach()

endfunction()

#[[
 # The feature dependency chain checks. Dependency chain is the sequence of
 # features interconnected between themself by dependency property. Every this
 # check means proper feature definition existence passed through command line.
 # Checks are success when last feature has not features dependencies, and all
 # options are set.
# Loop dependencies are inappropriate this way.
 ]]
function(verify_feature_dependencies feature dependency)
    # Through out the non-target dependency
    if(NOT FEATURE_${dependency}_ID STREQUAL "${dependency}")
        return()
    elseif(dependency IN_LIST FEATURE_${feature}_DEPENDENCIES
        AND NOT DEFINED FEATURE_${dependency}
    )
        message(FATAL_ERROR "${feature} has ${dependency} dependency, "
            "but FEATURE_${dependency} is not set")
    endif()

    # Dive deep into subsequent recursive iteration
    foreach(next_lvl_dep IN LISTS FEATURE_${dependency}_DEPENDENCIES)
        verify_feature_dependencies(${dependency} ${next_lvl_dep})
    endforeach()
endfunction()

#[[
# Verification start point. Parse available features.
# Forward features to further verifications.
 ]]
function(verify_features feature_metadata_filepath)
    readCacheFile("${feature_metadata_filepath}")
    get_directory_property(_cache_vars CACHE_VARIABLES)
    list(FILTER _cache_vars INCLUDE REGEX "FEATURE_[A-Za-z0-9\.]+$")
    foreach(enable_feature_def IN LISTS _cache_vars)
        # Fetch feature name/id
        string(REGEX MATCH "[^_][A-Za-z0-9\.]+$" enable_feature
            "${enable_feature_def}"
        )
        # Dependencies checks
        foreach(dependency IN LISTS FEATURE_${enable_feature}_DEPENDENCIES)
            verify_feature_dependencies("${enable_feature}" "${dependency}")
        endforeach()
        # Put further verifications below
    endforeach()
endfunction()

verify_features("${FEATURE_OUT_FILEPATH}")