.
1 import os
2 import fnmatch
3 import glob
4 import types
5 import time
6 from os import path
7 from scripts.run import run
8
9 def get_sources_path(directory, pattern):
10 """obtain path of all source files for a matching pattern"""
11 matches = []
12 for root, dirnames, filenames in os.walk(directory):
13 for filename in filenames:
14 full_path = os.path.join(root, filename)
15 if fnmatch.filter([full_path], pattern):
16 matches.append(os.path.join(root, filename))
17 return matches
18
19 class Builder(object):
20 """helper to generate tasks to compile vala code"""
21
22 def __init__(self,
23 source_directory,
24 valac_command,
25 cc_command,
26 linker_command,
27 target_binary,
28 link = None,
29 dependencies = None):
30 self.source_directory = source_directory
31 self.valac_command = valac_command
32 self.cc_command = cc_command
33 self.linker_command = linker_command
34 self.target_binary = target_binary
35 self.link = link
36 self.dependencies = dependencies
37
38 def build(self):
39 source_directory = self.source_directory
40 valac_command = self.valac_command
41 cc_command = self.cc_command
42 linker_command = self.linker_command
43 target_binary = self.target_binary
44
45 if not self.dependencies == None:
46 bindep = [path.join('build', 'bin', f) for f in self.dependencies]
47 else:
48 bindep = []
49
50 copied_csource_paths = get_sources_path(source_directory, '*.c')
51 copied_cheader_paths = get_sources_path(source_directory, '*.h')
52 vala_source_paths = get_sources_path(source_directory, '*.vala')
53 build_directory = path.join('build', source_directory)
54
55 csource_files = [path.basename(f) for f in copied_csource_paths]
56 generated_csource_paths = []
57 for vala_path in vala_source_paths:
58 vala_file = path.basename(vala_path)
59 cfile = vala_file.replace('.vala', '.c')
60 cpath = path.join(build_directory, cfile)
61 generated_csource_paths.append(cpath)
62 csource_files.append(cfile)
63
64 build_file = path.join(build_directory, 'placeholder')
65 yield {
66 'basename': 'mkdir ' + build_directory,
67 'actions': ['mkdir -p ' + path.join('build', 'bin'),
68 'mkdir -p ' + build_directory,
69 '[ -e "' + build_file + '" ] || touch "' + build_file + '"'],
70 'targets': [build_file],
71 }
72
73 copied_csources = []
74 copied_cheader = []
75 for csource in copied_cheader_paths + copied_csource_paths:
76 dest = path.join(build_directory, path.basename(csource))
77
78 if not dest[-2:] == ".h":
79 copied_csources.append(dest)
80 else:
81 copied_cheader.append(dest)
82
83 yield {
84 'basename': 'copy ' + csource,
85 'file_dep': [build_file] + [csource],
86 'actions': ['cp ' + csource + ' ' + build_directory],
87 'targets': [dest]
88 }
89
90 yield {
91 'basename': 'valac ' + source_directory,
92 'file_dep': [build_file] + vala_source_paths + bindep,
93 'actions': [valac_command],
94 'targets': generated_csource_paths
95 }
96
97 csource_paths = generated_csource_paths + copied_csources
98 object_files = []
99
100 for csource in csource_paths:
101 object_file = path.basename (csource.replace('.c', '.o'))
102 object_files.append(object_file);
103
104 command = cc_command.replace('C_SOURCE', csource)
105 object_path = path.join(build_directory, object_file)
106 command = command.replace('OBJECT_FILE', object_path)
107 yield {
108 'basename': 'compile ' + csource,
109 'file_dep': [build_file, csource] + bindep + copied_cheader,
110 'actions': [command],
111 'targets': [path.join(build_directory, object_file)],
112 }
113
114 object_paths = [path.join(build_directory, f) for f in object_files]
115 yield {
116 'basename': source_directory,
117 'file_dep': object_paths + [build_file] + bindep,
118 'actions': [linker_command],
119 'targets': [path.join('build', 'bin', target_binary)]
120 }
121
122 if not self.link == None:
123 createlink = 'cd build/bin/ && ln -s -f ' + target_binary + ' ' + self.link
124 yield {
125 'basename': 'Create link ' + target_binary + ' ' + self.link,
126 'file_dep': [path.join('build', 'bin', target_binary)],
127 'actions': [createlink],
128 'targets': [path.join('build', 'bin', self.link)]
129 }
130
131 def is_up_to_date(task):
132 for target in task['targets']:
133 if not path.isfile(target):
134 return False
135
136 if not 'file_dep' in task.keys():
137 return False
138
139 for dep in task['file_dep']:
140 if not path.isfile(dep):
141 print('Dependency is not created yet: ' + dep + ' needed for ' + task['targets'])
142 exit(1)
143
144 target_times = []
145 for target in task['targets']:
146 target_times.append(path.getmtime(target))
147 target_times.sort()
148
149 dependency_times = []
150 for dependency in task['file_dep']:
151 if not path.basename(dependency) == 'placeholder':
152 dependency_times.append(path.getmtime(dependency))
153 dependency_times.sort()
154
155 if len(dependency_times) == 0 or len(target_times) == 0:
156 return False
157
158 return dependency_times[-1] <= target_times[0]
159
160
161 def get_name(task):
162 try:
163 return task['name']
164 except KeyError:
165 return task['basename']
166
167 def execute_task(task):
168 if is_up_to_date(task):
169 print(get_name(task) + ' - up to date.')
170 else:
171 for action in task['actions']:
172 print(action)
173 run(action)
174
175 def process_tasks(generator):
176 for task in generator:
177 if isinstance(task, types.GeneratorType):
178 process_tasks(task)
179 else:
180 execute_task(task)
181
182