165 make_clean_first=True,
166 throw_away_data_after_build=False,
167 number_of_parallel_builds=-1):
169 Invokes the underlying make build mechanism on the project.
171 number_of_parallel_builds: int
172 This is mapped onto make -jnumber_of_parallel_builds, i.e., it
173 determines how many parallel make instances the code spawns.
174 Usually, a lot of the generated code is quite lengthy. Therefore
175 compile time can be high. If you pass something smaller or equal
176 to zero, it will use the core count as guideline how to compile.
178 throw_away_data_after_build: Bool
181 if number_of_parallel_builds <= 0:
182 number_of_parallel_builds = multiprocessing.cpu_count()
189 print(
"clean up project ... in {}".format(self.
directory))
192 subprocess.check_call([
"make",
"clean"], cwd=self.
directory)
194 print(
"clean complete")
195 except Exception
as e:
196 print(
"clean failed (" + str(e) +
") - continue anyway")
199 print(
"start to compile with concurrency level of " + str(number_of_parallel_builds) +
" ...")
201 process = subprocess.run([
"make",
"-j"+str(number_of_parallel_builds)], cwd=self.
directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
203 error_message = process.stderr.decode().strip()
204 warnings = re.findall(
r"(?i)warning:.*", error_message)
205 errors = re.findall(
r"(?i)error:.*", error_message)
208 print(
"\nWarnings ({}):".format(len(warnings)))
209 print(
"\n".join(warnings))
211 print(
"\nErrors ({}):".format(len(errors)))
212 error_message =
"\n".join(errors)
215 if process.returncode != 0:
216 linker_error_message = process.stderr.decode().strip() +
"\n" + error_message
217 raise Exception(linker_error_message)
218 print(
"compile completed successfully")
221 except Exception
as e:
225 print(
"compile was not successful")
228 print(
"cannot build as code generation has not been successful")
230 if throw_away_data_after_build:
236 print(
"threw away all data and ran garbage collection")
238 def run(self, executable, args=[], prefix=None, pipefile=None, rebuild_if_required=True):
240 Runs the code. args should be a list of strings or the empty list.
241 prefix is an array, too. A typical invocation looks alike
242 project.run( ["16.0", "32.0"], ["/opt/mpi/mpirun", "-n", "1"] )
243 The operation returns True if the run had been successful
245 pipefile: string or None
252 print(
"run executable " + str(executable))
257 invocation += [
"./" + executable]
263 result = subprocess.run( invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
265 result = subprocess.run( invocation, stdout=open( pipefile,
"w" ), stderr=subprocess.PIPE )
266 if result.returncode==0:
268 print( result.stdout.decode(
"utf-8") )
269 if result.stderr!=
None:
270 print( result.stderr.decode(
"utf-8") )
271 print(
"run completed without error code, but check for warnings and numerical assertions/errors" )
273 print( result.stderr.decode(
"utf-8") )
274 print(
"run failed" )
276 except Exception
as e:
277 print(
"run of application was not successful: " + str(e) )
278 print(
"invocation: " + str(invocation) )
280 print(
"cannot run as code compilation has not been successful" )
285 subproject:
'Project',
288 Adds a new Peano4 project into this Peano 4 project
292 lhs.namespace == rhs.namespace
293 ), "namespaces of the projects being merged don't match"
296 lhs.directory == rhs.directory
297 ), "directories of the projects being merged don't match"
300 lhs.output.makefile.d["CXX"] == lhs.output.makefile.d["CXX"]
301 ), "CXX compilers of the projects being merged don't match"
304 lhs.output.makefile.d["FC"] == lhs.output.makefile.d["FC"]
305 ), "FC compilers of the projects being merged don't match"
308 lhs.output.makefile.d["DIM"] == lhs.output.makefile.d["DIM"]
309 ), "dimensions of the projects being merged don't match"
312 lhs.output.makefile.d["MODE"] == lhs.output.makefile.d["MODE"]
313 ), "compile modes of the projects being merged don't match"
332 assert(subproject._subdirectory !=
""),
"subdirectory of a subproject mustn't be empty"
336 self.
datamodel.namespace = subproject.datamodel.namespace
337 self.
datamodel._subdirectory = subproject.datamodel._subdirectory
349 for data
in subproject.datamodel.cell_data:
351 for data
in subproject.datamodel.face_data:
353 for particle
in subproject.datamodel.vertex_data:
355 for particle
in subproject.datamodel.global_data:
364 added_step = subproject.solversteps._steps[0]
365 step.cell_data.extend(added_step.cell_data)
366 step.face_data.extend(added_step.face_data)
367 step.vertex_data.extend(added_step.vertex_data)
371 for added_step
in subproject.solversteps._steps:
373 added_step.cell_data.clear()
374 added_step.cell_data.extend(step.cell_data)
375 added_step.face_data.clear()
376 added_step.face_data.extend(step.face_data)
377 added_step.vertex_data.clear()
378 added_step.vertex_data.extend(step.vertex_data)
381 for step
in subproject.solversteps._steps:
389 if (self.
output.makefile.d[
"CXX"]):
391 self.
output.makefile.d[
"CXX"] == subproject.output.makefile.d[
"CXX"]
392 ),
"the CXX compiler of the subproject being added doesn't match the one of the main project"
394 self.
output.makefile.d[
"CXX"] = subproject.output.makefile.d[
"CXX"]
396 if (self.
output.makefile.d[
"FC"]):
398 self.
output.makefile.d[
"FC"] == subproject.output.makefile.d[
"FC"]
399 ),
"the FC compiler of the subproject being added doesn't match the one of the main project"
401 self.
output.makefile.d[
"FC"] = subproject.output.makefile.d[
"FC"]
403 for flag
in subproject.output.makefile.d[
"CXXFLAGS"].split():
404 self.
output.makefile.add_CXX_flag(flag)
406 for flag
in subproject.output.makefile.d[
"FCFLAGS"].split():
407 self.
output.makefile.add_Fortran_flag(flag)
409 for flag
in subproject.output.makefile.d[
"LDFLAGS"].split():
410 self.
output.makefile.add_linker_flag(flag)
412 self.
output.makefile.d[
"LIBS"] += subproject.output.makefile.d[
"LIBS"]
413 self.
output.makefile.d[
"GENERATED_INCLUDE_DIRS"] |= subproject.output.makefile.d[
"GENERATED_INCLUDE_DIRS"]
414 self.
output.makefile.d[
"MODE"] = subproject.output.makefile.d[
"MODE"]
416 for module
in subproject.output.makefile.d[
"FORTRAN_MODULES"]:
417 self.
output.makefile.add_Fortran_module(module)
420 self.
output.makefile.d[
"EXECUTABLENAME"]
421 ),
"the name of the main project is empty"
422 if not self.
output.makefile.d[
"DIM"]:
423 self.
output.makefile.set_dimension(subproject.output.makefile.d[
"DIM"])
426 self.
output.makefile.d[
"DIM"] == subproject.output.makefile.d[
"DIM"]
427 ),
"the dimensions of the added subproject doesn't match the current one of the main project"
430 for filename
in subproject.output.makefile.hfiles:
431 self.
output.makefile.add_h_file(filename,
False)
432 for filename
in subproject.output.makefile.cppfiles:
433 self.
output.makefile.add_cpp_file(filename,
False)
434 for filename
in subproject.output.makefile.fortranfiles:
435 self.
output.makefile.add_Fortran_file(filename,
False)
437 for filename
in subproject.output.makefile.generated_hfiles:
438 self.
output.makefile.add_h_file(filename,
True)
439 for filename
in subproject.output.makefile.generated_cppfiles:
440 self.
output.makefile.add_cpp_file(filename,
True)
441 for filename
in subproject.output.makefile.generated_fortranfiles:
442 self.
output.makefile.add_Fortran_file(filename,
True)
447 for i
in subproject.output.readme._entries:
448 self.
output.readme.add_entry(i)
450 for i
in subproject.output.readme._package_descriptions:
451 self.
output.readme.add_package_description(i)
453 for i
in subproject.output.readme._entries:
454 self.
output.readme.add_entry(i)
456 for i
in subproject.output.artefacts:
463 self.
main = subproject.main
467 self.
main.merge(subproject.main)