3 |
3 |
4 # This file is part of Beremiz, a Integrated Development Environment for |
4 # This file is part of Beremiz, a Integrated Development Environment for |
5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
6 # |
6 # |
7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
|
8 # Copyright (C) 2017: Paul Beltyukov |
8 # |
9 # |
9 # See COPYING file for copyrights details. |
10 # See COPYING file for copyrights details. |
10 # |
11 # |
11 # This program is free software; you can redistribute it and/or |
12 # This program is free software; you can redistribute it and/or |
12 # modify it under the terms of the GNU General Public License |
13 # modify it under the terms of the GNU General Public License |
50 Returns list of builder specific LDFLAGS |
51 Returns list of builder specific LDFLAGS |
51 """ |
52 """ |
52 return self.CTRInstance.LDFLAGS + \ |
53 return self.CTRInstance.LDFLAGS + \ |
53 [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()] |
54 [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()] |
54 |
55 |
|
56 def getCompiler(self): |
|
57 """ |
|
58 Returns compiler |
|
59 """ |
|
60 return self.CTRInstance.GetTarget().getcontent().getCompiler() |
|
61 |
|
62 def getLinker(self): |
|
63 """ |
|
64 Returns linker |
|
65 """ |
|
66 return self.CTRInstance.GetTarget().getcontent().getLinker() |
|
67 |
55 def GetBinaryCode(self): |
68 def GetBinaryCode(self): |
56 try: |
69 try: |
57 return open(self.exe_path, "rb").read() |
70 return open(self.exe_path, "rb").read() |
58 except Exception, e: |
71 except Exception, e: |
59 return None |
72 return None |
82 self.buildpath = buildpath |
95 self.buildpath = buildpath |
83 self.exe = self.CTRInstance.GetProjectName() + self.extension |
96 self.exe = self.CTRInstance.GetProjectName() + self.extension |
84 self.exe_path = os.path.join(self.buildpath, self.exe) |
97 self.exe_path = os.path.join(self.buildpath, self.exe) |
85 self.md5key = None |
98 self.md5key = None |
86 self.srcmd5 = {} |
99 self.srcmd5 = {} |
87 |
100 |
|
101 def append_cfile_deps(self, src, deps): |
|
102 for l in src.splitlines(): |
|
103 res = includes_re.match(l) |
|
104 if res is not None: |
|
105 depfn = res.groups()[0] |
|
106 if os.path.exists(os.path.join(self.buildpath, depfn)): |
|
107 deps.append(depfn) |
|
108 |
|
109 def concat_deps(self, bn): |
|
110 # read source |
|
111 src = open(os.path.join(self.buildpath, bn),"r").read() |
|
112 # update direct dependencies |
|
113 deps = [] |
|
114 self.append_cfile_deps(src, deps) |
|
115 # recurse through deps |
|
116 # TODO detect cicular deps. |
|
117 return reduce(operator.concat, map(self.concat_deps, deps), src) |
|
118 |
88 def check_and_update_hash_and_deps(self, bn): |
119 def check_and_update_hash_and_deps(self, bn): |
89 # Get latest computed hash and deps |
120 # Get latest computed hash and deps |
90 oldhash, deps = self.srcmd5.get(bn,(None,[])) |
121 oldhash, deps = self.srcmd5.get(bn,(None,[])) |
91 # read source |
122 # read source |
92 src = open(os.path.join(self.buildpath, bn)).read() |
123 src = open(os.path.join(self.buildpath, bn)).read() |
96 match = (oldhash == newhash) |
127 match = (oldhash == newhash) |
97 if not match: |
128 if not match: |
98 # file have changed |
129 # file have changed |
99 # update direct dependencies |
130 # update direct dependencies |
100 deps = [] |
131 deps = [] |
101 for l in src.splitlines(): |
132 self.append_cfile_deps(src, deps) |
102 res = includes_re.match(l) |
|
103 if res is not None: |
|
104 depfn = res.groups()[0] |
|
105 if os.path.exists(os.path.join(self.buildpath, depfn)): |
|
106 #print bn + " depends on "+depfn |
|
107 deps.append(depfn) |
|
108 # store that hashand deps |
133 # store that hashand deps |
109 self.srcmd5[bn] = (newhash, deps) |
134 self.srcmd5[bn] = (newhash, deps) |
110 # recurse through deps |
135 # recurse through deps |
111 # TODO detect cicular deps. |
136 # TODO detect cicular deps. |
112 return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match) |
137 return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match) |
113 |
138 |
|
139 def calc_source_md5(self): |
|
140 wholesrcdata = "" |
|
141 for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: |
|
142 # Get CFiles list to give it to makefile |
|
143 for CFile, CFLAGS in CFilesAndCFLAGS: |
|
144 CFileName = os.path.basename(CFile) |
|
145 wholesrcdata += self.concat_deps(CFileName) |
|
146 return hashlib.md5(wholesrcdata).hexdigest() |
|
147 |
|
148 def calc_md5(self): |
|
149 return hashlib.md5(self.GetBinaryCode()).hexdigest() |
|
150 |
114 def build(self): |
151 def build(self): |
115 # Retrieve toolchain user parameters |
152 # Retrieve compiler and linker |
116 toolchain_params = self.CTRInstance.GetTarget().getcontent() |
153 self.compiler = self.getCompiler() |
117 self.compiler = toolchain_params.getCompiler() |
154 self.linker = self.getLinker() |
118 self.linker = toolchain_params.getLinker() |
|
119 |
155 |
120 Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) |
156 Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) |
121 |
157 |
122 ######### GENERATE OBJECT FILES ######################################## |
158 ######### GENERATE OBJECT FILES ######################################## |
123 obns = [] |
159 obns = [] |
159 objs.append(objectfilename) |
195 objs.append(objectfilename) |
160 elif CFile.endswith(".o"): |
196 elif CFile.endswith(".o"): |
161 obns.append(os.path.basename(CFile)) |
197 obns.append(os.path.basename(CFile)) |
162 objs.append(CFile) |
198 objs.append(CFile) |
163 |
199 |
164 ######### GENERATE library FILE ######################################## |
200 ######### GENERATE OUTPUT FILE ######################################## |
165 # Link all the object files into one binary file |
201 # Link all the object files into one binary file |
166 self.CTRInstance.logger.write(_("Linking :\n")) |
202 self.CTRInstance.logger.write(_("Linking :\n")) |
167 if relink: |
203 if relink: |
168 objstring = [] |
204 objstring = [] |
169 |
205 |
188 |
224 |
189 else: |
225 else: |
190 self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") |
226 self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") |
191 |
227 |
192 # Calculate md5 key and get data for the new created PLC |
228 # Calculate md5 key and get data for the new created PLC |
193 data=self.GetBinaryCode() |
229 self.md5key = self.calc_md5() |
194 self.md5key = hashlib.md5(data).hexdigest() |
|
195 |
230 |
196 # Store new PLC filename based on md5 key |
231 # Store new PLC filename based on md5 key |
197 f = open(self._GetMD5FileName(), "w") |
232 f = open(self._GetMD5FileName(), "w") |
198 f.write(self.md5key) |
233 f.write(self.md5key) |
199 f.close() |
234 f.close() |