173 make_clean_first=True,
174 throw_away_data_after_build=False,
175 number_of_parallel_builds=-1):
177 Invokes the underlying make build mechanism on the project.
179 number_of_parallel_builds: int
180 This is mapped onto make -jnumber_of_parallel_builds, i.e., it
181 determines how many parallel make instances the code spawns.
182 Usually, a lot of the generated code is quite lengthy. Therefore
183 compile time can be high. If you pass something smaller or equal
184 to zero, it will use the core count as guideline how to compile.
186 throw_away_data_after_build: Bool
189 if number_of_parallel_builds <= 0:
190 number_of_parallel_builds = multiprocessing.cpu_count()
197 print(
"clean up project ... in {}".format(self.
directory))
200 subprocess.check_call([
"make",
"clean"], cwd=self.
directory)
202 print(
"clean complete")
203 except Exception
as e:
204 print(
"clean failed (" + str(e) +
") - continue anyway")
207 print(
"start to compile with concurrency level of " + str(number_of_parallel_builds) +
" ...")
209 process = subprocess.run([
"make",
"-j"+str(number_of_parallel_builds)], cwd=self.
directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
211 error_message = process.stderr.decode().strip()
212 warnings = re.findall(
r"(?i)warning:.*", error_message)
213 errors = re.findall(
r"(?i)error:.*", error_message)
216 print(
"\nWarnings ({}):".format(len(warnings)))
217 print(
"\n".join(warnings))
219 print(
"\nErrors ({}):".format(len(errors)))
220 error_message =
"\n".join(errors)
223 if process.returncode != 0:
224 linker_error_message = process.stderr.decode().strip() +
"\n" + error_message
225 raise Exception(linker_error_message)
226 print(
"compile completed successfully")
229 except Exception
as e:
233 print(
"compile was not successful")
236 print(
"cannot build as code generation has not been successful")
238 if throw_away_data_after_build:
244 print(
"threw away all data and ran garbage collection")
246 def run(self, executable, args=[], prefix=None, pipefile=None, rebuild_if_required=True):
248 Runs the code. args should be a list of strings or the empty list.
249 prefix is an array, too. A typical invocation looks alike
250 project.run( ["16.0", "32.0"], ["/opt/mpi/mpirun", "-n", "1"] )
251 The operation returns True if the run had been successful
253 pipefile: string or None
260 print(
"run executable " + str(executable))
265 invocation += [
"./" + executable]
271 result = subprocess.run( invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
273 result = subprocess.run( invocation, stdout=open( pipefile,
"w" ), stderr=subprocess.PIPE )
274 if result.returncode==0:
276 print( result.stdout.decode(
"utf-8") )
277 if result.stderr!=
None:
278 print( result.stderr.decode(
"utf-8") )
279 print(
"run completed without error code, but check for warnings and numerical assertions/errors" )
281 print( result.stderr.decode(
"utf-8") )
282 print(
"run failed" )
284 except Exception
as e:
285 print(
"run of application was not successful: " + str(e) )
286 print(
"invocation: " + str(invocation) )
288 print(
"cannot run as code compilation has not been successful" )
293 subproject:
'Project',
296 Adds a new Peano4 project into this Peano 4 project
300 lhs.namespace == rhs.namespace
301 ), "namespaces of the projects being merged don't match"
304 lhs.directory == rhs.directory
305 ), "directories of the projects being merged don't match"
308 lhs.output.makefile.d["CXX"] == lhs.output.makefile.d["CXX"]
309 ), "CXX compilers of the projects being merged don't match"
312 lhs.output.makefile.d["FC"] == lhs.output.makefile.d["FC"]
313 ), "FC compilers of the projects being merged don't match"
316 lhs.output.makefile.d["DIM"] == lhs.output.makefile.d["DIM"]
317 ), "dimensions of the projects being merged don't match"
320 lhs.output.makefile.d["MODE"] == lhs.output.makefile.d["MODE"]
321 ), "compile modes of the projects being merged don't match"
340 assert(subproject._subdirectory !=
""),
"subdirectory of a subproject mustn't be empty"
344 self.
datamodel.namespace = subproject.datamodel.namespace
345 self.
datamodel._subdirectory = subproject.datamodel._subdirectory
357 for data
in subproject.datamodel.cell_data:
359 for data
in subproject.datamodel.face_data:
361 for particle
in subproject.datamodel.vertex_data:
363 for particle
in subproject.datamodel.global_data:
372 added_step = subproject.solversteps._steps[0]
373 step.cell_data.extend(added_step.cell_data)
374 step.face_data.extend(added_step.face_data)
375 step.vertex_data.extend(added_step.vertex_data)
379 for added_step
in subproject.solversteps._steps:
381 added_step.cell_data.clear()
382 added_step.cell_data.extend(step.cell_data)
383 added_step.face_data.clear()
384 added_step.face_data.extend(step.face_data)
385 added_step.vertex_data.clear()
386 added_step.vertex_data.extend(step.vertex_data)
389 for step
in subproject.solversteps._steps:
397 if (self.
output.makefile.d[
"CXX"]):
399 self.
output.makefile.d[
"CXX"] == subproject.output.makefile.d[
"CXX"]
400 ),
"the CXX compiler of the subproject being added doesn't match the one of the main project"
402 self.
output.makefile.d[
"CXX"] = subproject.output.makefile.d[
"CXX"]
404 if (self.
output.makefile.d[
"FC"]):
406 self.
output.makefile.d[
"FC"] == subproject.output.makefile.d[
"FC"]
407 ),
"the FC compiler of the subproject being added doesn't match the one of the main project"
409 self.
output.makefile.d[
"FC"] = subproject.output.makefile.d[
"FC"]
411 for flag
in subproject.output.makefile.d[
"CXXFLAGS"].split():
412 self.
output.makefile.add_CXX_flag(flag)
414 for flag
in subproject.output.makefile.d[
"FCFLAGS"].split():
415 self.
output.makefile.add_Fortran_flag(flag)
417 for flag
in subproject.output.makefile.d[
"LDFLAGS"].split():
418 self.
output.makefile.add_linker_flag(flag)
420 self.
output.makefile.d[
"LIBS"] += subproject.output.makefile.d[
"LIBS"]
421 self.
output.makefile.d[
"GENERATED_INCLUDE_DIRS"] |= subproject.output.makefile.d[
"GENERATED_INCLUDE_DIRS"]
422 self.
output.makefile.d[
"MODE"] = subproject.output.makefile.d[
"MODE"]
424 for module
in subproject.output.makefile.d[
"FORTRAN_MODULES"]:
425 self.
output.makefile.add_Fortran_module(module)
428 self.
output.makefile.d[
"EXECUTABLENAME"]
429 ),
"the name of the main project is empty"
430 if not self.
output.makefile.d[
"DIM"]:
431 self.
output.makefile.set_dimension(subproject.output.makefile.d[
"DIM"])
434 self.
output.makefile.d[
"DIM"] == subproject.output.makefile.d[
"DIM"]
435 ),
"the dimensions of the added subproject doesn't match the current one of the main project"
438 for filename
in subproject.output.makefile.hfiles:
439 self.
output.makefile.add_h_file(filename,
False)
440 for filename
in subproject.output.makefile.cppfiles:
441 self.
output.makefile.add_cpp_file(filename,
False)
442 for filename
in subproject.output.makefile.fortranfiles:
443 self.
output.makefile.add_Fortran_file(filename,
False)
445 for filename
in subproject.output.makefile.generated_hfiles:
446 self.
output.makefile.add_h_file(filename,
True)
447 for filename
in subproject.output.makefile.generated_cppfiles:
448 self.
output.makefile.add_cpp_file(filename,
True)
449 for filename
in subproject.output.makefile.generated_fortranfiles:
450 self.
output.makefile.add_Fortran_file(filename,
True)
455 for i
in subproject.output.readme._entries:
456 self.
output.readme.add_entry(i)
458 for i
in subproject.output.readme._package_descriptions:
459 self.
output.readme.add_package_description(i)
461 for i
in subproject.output.readme._entries:
462 self.
output.readme.add_entry(i)
464 for i
in subproject.output.artefacts:
471 self.
main = subproject.main
475 self.
main.merge(subproject.main)