integrate C/LDFLAGS into LunaBuild flow
[lunaix-os.git] / lunaix-os / scripts / build-tools / lbuild / contract.py
1 from lib.sandbox import Sandbox
2 from lib.utils import join_path
3 from .common import BuildEnvironment
4
5 import os
6
7 class LunaBuildFile(Sandbox):
8     def __init__(self, env: BuildEnvironment, path) -> None:
9         super().__init__({
10             "_script": 
11                 path,
12             "sources": 
13                 lambda src: self.export_sources(src),
14             "headers":
15                 lambda hdr: self.export_headers(hdr),
16             "configured":
17                 lambda name: self.check_config(name),
18             "config":
19                 lambda name: self.read_config(name),
20             "use":
21                 lambda file: self.import_buildfile(file),
22             **env.external_func_table()
23         })
24         
25         self.__srcs = []
26         self.__hdrs = []
27         self.__env  = env
28
29         self.__path = path
30         self.__dir  = os.path.dirname(path)
31         
32     def resolve(self):
33         self.execute(self.__path)
34         self.__env.add_sources(self.__do_process(self.__srcs))
35         self.__env.add_headers(self.__do_process(self.__hdrs))
36
37     def __do_process(self, list):
38         resolved = []
39         for entry in list:
40             if not entry:
41                 continue
42             resolved.append(self.__resolve_value(entry))
43         return resolved
44
45     def expand_select(self, val):
46         tests = list(val.keys())
47         if len(tests) != 1:
48             raise TypeError(
49                 "select statement must have exactly one conditional")
50         
51         test = tests[0]
52         outcomes = val[test]
53         if test not in outcomes:
54             self.__raise("unbounded select")
55         return outcomes[test]
56
57     def __resolve_value(self, source):
58         resolved = source
59         while not isinstance(resolved, str):
60             if isinstance(resolved, dict):
61                 resolved = self.expand_select(resolved)
62             else:
63                 self.__raise(f"entry with unknown type: {resolved}")
64         
65         resolved = resolved.strip()
66         resolved = join_path(self.__dir, resolved)
67
68         return self.__env.to_wspath(resolved)
69     
70     def import_buildfile(self, path):
71         path = self.__resolve_value(path)
72         path = self.__env.to_wspath(path)
73         
74         if (os.path.isdir(path)):
75             path = os.path.join(path, "LBuild")
76         
77         if not os.path.exists(path):
78             self.__raise("Build file not exist: %s", path)
79
80         if os.path.abspath(path) == os.path.abspath(self.__path):
81             self.__raise("self dependency detected")
82
83         LunaBuildFile(self.__env, path).resolve()
84
85     def export_sources(self, src):
86         if not isinstance(src, list):
87             src = [src]
88         self.__srcs += src
89
90     def export_headers(self, hdr):
91         if not isinstance(hdr, list):
92             hdr = [hdr]
93         self.__hdrs += hdr
94
95     def check_config(self, name):
96         return self.__env.config_provider().has_config(name)
97     
98     def read_config(self, name):
99         return self.__env.config_provider().configured_value(name)
100     
101     def __raise(self, msg, *kargs):
102         raise Exception(msg%kargs)