├── CompileCommands.py ├── cactus.py └── CactusCmake.py /CompileCommands.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from cactus import Cactus, ThornInfo, make_argument_parser 4 | import json 5 | 6 | argp, cactus_dir, config = make_argument_parser("CompileCommands") 7 | cactus = Cactus(cactus_dir=cactus_dir, config=config) 8 | 9 | jdata = list() 10 | for thorn_info in cactus.thorns.values(): 11 | if thorn_info.name == "Cactus": 12 | print(thorn_info) 13 | for src_file in thorn_info.src_files: 14 | inc_files = list() 15 | full_src_file = f"{thorn_info.dir}/src/{src_file}" 16 | assert os.path.exists(full_src_file) 17 | full_output = f"{cactus.config_dir}/build/{thorn_info.name}/{src_file}.o" 18 | for inc_file in cactus.find_includes(thorn_info.name): 19 | inc_files += [f"-I{inc_file}"] 20 | inc_files += [f"-I{cactus.cactus_dir}/arrangements/{thorn_info.arr}/{thorn_info.name}/src"] 21 | inc_files += [f"-I{cactus.cactus_dir}/arrangements/{thorn_info.arr}/{thorn_info.name}/src/include"] 22 | inc_files += [f"-I{cactus.cactus_dir}/src/include"] 23 | inc_files += [f"-I{cactus.cactus_dir}/arrangements"] 24 | inc_files += [f"-I{cactus.cactus_dir}/configs/{config}/bindings/Configuration/Thorns"] 25 | inc_files += [f"-I{cactus.cactus_dir}/configs/{config}/config-data"] 26 | inc_files += [f"-I{cactus.cactus_dir}/configs/{config}/bindings/include"] 27 | inc_files += [f"-I{cactus.cactus_dir}/configs/{config}/bindings/include/{thorn_info.name}"] 28 | item = { 29 | "arguments": [ 30 | "g++", 31 | "-fopenmp", 32 | "-Wall", 33 | "-g", 34 | "-O2", 35 | "-c", 36 | "-DCCODE" 37 | ] + inc_files, 38 | "directory": f"{cactus.config_dir}/scratch", 39 | "file": full_src_file, 40 | "output": full_output 41 | } 42 | jdata.append(item) 43 | if os.path.islink(thorn_info.dir): 44 | rl = os.readlink(thorn_info.dir) 45 | alt_dir = os.path.realpath(f"{thorn_info.dir}/../{rl}") 46 | alt_path = f"{alt_dir}/src/{src_file}" 47 | alt_output = f"{cactus.config_dir}/build/{thorn_info.name}/{src_file}_2.o" 48 | if os.path.exists(alt_path): 49 | item = { 50 | "arguments": [ 51 | "g++", 52 | "-fopenmp", 53 | "-Wall", 54 | "-g", 55 | "-O2", 56 | "-c", 57 | "-DCCODE" 58 | ] + inc_files, 59 | "directory": f"{cactus.config_dir}/scratch", 60 | "file": alt_path, 61 | "output": alt_output 62 | } 63 | jdata.append(item) 64 | 65 | with open("compile_commands.json", "w") as fd: 66 | json.dump(jdata, fd, indent=2) 67 | 68 | print("Working Directory:", os.getcwd()) 69 | -------------------------------------------------------------------------------- /cactus.py: -------------------------------------------------------------------------------- 1 | import argparse as ap 2 | import os 3 | import re 4 | import sys 5 | from typing import List, Dict, Set, Optional 6 | 7 | import piraha 8 | 9 | def die(s:str): 10 | print(s) 11 | print("Failed") 12 | exit(1) 13 | 14 | class ThornInfo: 15 | def __init__(self, name: str, arr: str, dir: str, requires: List[str], provides: List[str], src_files: List[str])->None: 16 | self.name = name 17 | self.arr = arr 18 | self.dir = dir 19 | self.requires = requires 20 | self.provides = provides 21 | self.src_files = src_files 22 | 23 | def __str__(self): 24 | return f"{self.name} ( arr='{self.arr}', requires={self.requires}, provides={self.provides} )" 25 | 26 | def __repr__(self): 27 | return self.__str__() 28 | 29 | 30 | def find_src_files(thorn_dir:str)->List[str]: 31 | src_files: List[str] = list() 32 | 33 | # TODO: The parsing of make.code.defn leaves much to be desired at the moment 34 | with open(f"{thorn_dir}/src/make.code.defn", "r") as fd: 35 | for line in fd.readlines(): 36 | if line.startswith("#"): 37 | continue 38 | for s in re.findall(r'[\w/-]+\.\w+', line): 39 | if os.path.exists(f"{thorn_dir}/src/{s}"): 40 | src_files.append(s) 41 | 42 | return src_files 43 | 44 | 45 | class Cactus: 46 | def __init__(self, cactus_dir:str=f"{os.environ.get('HOME','')}/Cactus", config:str="sim"): 47 | self.cactus_dir = cactus_dir 48 | self.config = config 49 | self.config_dir = f"{self.cactus_dir}/configs/{config}" 50 | self.thorns : Dict[str,ThornInfo] = dict() 51 | self.providers : Dict[str,ThornInfo] = dict() 52 | self.capabilities : Dict[str,ThornInfo] = dict() 53 | self.link_options: Set[str] = set() 54 | self.link_libraries: Set[str] = set() 55 | self.link_options.add("-L.") 56 | 57 | if not os.path.exists(self.config_dir): 58 | raise Exception(f"Cactus config '{config}' does not exist.") 59 | self.config_grammar, self.config_rule = piraha.parse_peg_file(f"{self.cactus_dir}/src/piraha/pegs/config.peg") 60 | self.interface_grammar, self.interface_rule = piraha.parse_peg_file(f"{self.cactus_dir}/src/piraha/pegs/interface.peg") 61 | self._identify_thorns() 62 | 63 | reqs, provides = self._requires_and_provides(f"{self.cactus_dir}/src") 64 | src_files = find_src_files(self.cactus_dir) 65 | self.thorns["Cactus"] = ThornInfo("Cactus", "flesh", f"{self.cactus_dir}/src", reqs, provides, src_files) 66 | 67 | self._find_link_options() 68 | self.link_libraries.add("gfortran") 69 | 70 | def _find_link_options(self) -> None: 71 | for thorn_info in self.thorns.values(): 72 | for capability in thorn_info.provides: 73 | self.capabilities[capability] = thorn_info 74 | for capability, thorn_info in self.capabilities.items(): 75 | # TODO: Hack 76 | capability_name : str 77 | if capability == "OPENPMD_API": 78 | capability_name = "OPENPMD" 79 | else: 80 | capability_name = capability 81 | file = f"{self.cactus_dir}/configs/{self.config}/bindings/Configuration/Capabilities/make.{capability}.defn" 82 | assert os.path.exists(file), f"{file} does not exist" 83 | with open(file, "r") as fd: 84 | for line in fd.readlines(): 85 | if g := re.match(fr"{capability_name}_LIBS\s*=\s*(.*\S)", line): 86 | for lib in re.split(r'\s+', g.group(1)): 87 | self.link_libraries.add(lib) 88 | elif g := re.match(fr"{capability_name}_LIB_DIRS\s*=\s*(.*\S)", line): 89 | for lib_dir in re.split(r'\s+', g.group(1)): 90 | self.link_options.add("-L" + lib_dir) 91 | 92 | def _identify_thorns(self) -> None: 93 | thorn_list_file = f"{self.cactus_dir}/configs/{self.config}/ThornList" 94 | assert os.path.exists(thorn_list_file), f"No such file: '{thorn_list_file}'" 95 | with open(thorn_list_file, "r") as fth: 96 | for line in fth.readlines(): 97 | if g := re.match(r'^(\w+)/(\w+)', line): 98 | arr = g.group(1) 99 | thorn_name = g.group(2) 100 | thorn_dir = f"{self.cactus_dir}/arrangements/{arr}/{thorn_name}" 101 | assert os.path.exists(f"{thorn_dir}/param.ccl") 102 | r, p = self._requires_and_provides(thorn_dir) 103 | sf = find_src_files(thorn_dir) 104 | self.thorns[thorn_name] = ThornInfo(thorn_name, arr, thorn_dir, r, p, sf) 105 | for capability in p: 106 | self.providers[capability] = self.thorns[thorn_name] 107 | 108 | def provides_functions(self, thorn_name: str) -> bool: 109 | thorn_dir = self.thorns[thorn_name].dir 110 | interface_file = f"{thorn_dir}/interface.ccl" 111 | matcher = piraha.parse_src(self.interface_grammar, self.interface_rule, interface_file) 112 | r = matcher.matches() 113 | assert r 114 | for group in matcher.gr.children: 115 | if group.getPatternName() == "FUNC_GROUP": 116 | if group.has(0, "FUNCTION"): 117 | if group.group(0).has(0, "PROVIDES_FUN"): 118 | return True 119 | return False 120 | 121 | def _requires_and_provides(self, thorn_dir: str): 122 | requires = [] 123 | provides = [] 124 | config_file = f"{thorn_dir}/configuration.ccl" 125 | if not os.path.exists(config_file): 126 | return requires, provides 127 | matcher = piraha.parse_src(self.config_grammar, self.config_rule, config_file) 128 | r = matcher.matches() 129 | assert r 130 | gr = matcher.gr 131 | for child in gr.children: 132 | if child.getPatternName() == "provopt": 133 | key = child.group(0).substring().upper() 134 | val = child.group(1).substring().upper() 135 | if key in ["OPTIONAL", "REQUIRES"]: 136 | requires.append(val) 137 | elif key == "PROVIDES": 138 | provides.append(val) 139 | else: 140 | assert f"Not handled: {key}" 141 | elif child.getPatternName() == "requires": 142 | for req in child.children: 143 | if req.getPatternName() == "name_with_ver": 144 | requires.append(req.group(0, "name").substring().upper()) 145 | elif req.getPatternName() == "thorns": 146 | for th in req.children: 147 | requires.append(th.substring().upper()) 148 | else: 149 | assert False, child.dump() 150 | else: 151 | assert f"Not handled: {child.dump()}" 152 | return requires, provides 153 | 154 | def find_includes(self, thorn_name: str) -> Set[str]: 155 | assert thorn_name in self.thorns, f"Cannot find thorn: {thorn_name}" 156 | thorn_info = self.thorns[thorn_name] 157 | check_reqs = thorn_info.requires 158 | old_reqs = set() 159 | done = False 160 | while not done: 161 | new_reqs = set() 162 | for capability in check_reqs: 163 | th = self.providers.get(capability, None) 164 | if th is None: 165 | continue 166 | req_thorn_info = self.thorns[th.name] 167 | for cap in req_thorn_info.requires: 168 | new_reqs.add(cap) 169 | old_reqs.add(capability) 170 | check_reqs = set() 171 | done = True 172 | for new_req in new_reqs: 173 | if new_req not in old_reqs: 174 | check_reqs.add(new_req) 175 | done = False 176 | incs : Set[str] = set() 177 | for capability in old_reqs: 178 | for inc in self._find_includes(capability): 179 | incs.add(inc) 180 | return incs 181 | 182 | def _find_includes(self, capability:str)->Set[str]: 183 | inc_dirs : Set[str] = set() 184 | file = f"{self.cactus_dir}/configs/{self.config}/bindings/Configuration/Capabilities/make.{capability}.defn" 185 | if not os.path.exists(file): 186 | print("capabilities file does not exist:", file) 187 | return set() 188 | with open(file, "r") as fd: 189 | for line in fd.readlines(): 190 | g = re.search(fr'{capability}_INC_DIRS\s*=\s*(.*\S)', line) 191 | if g: 192 | for path in re.split(r'\s+', g.group(1)): 193 | inc_dirs.add(path) 194 | return inc_dirs 195 | 196 | def nice_path(self, path:str)->str: 197 | if path.startswith(self.config_dir): 198 | return "${CONFIG}" + path[len(self.config_dir):] 199 | elif path.startswith(self.cactus_dir): 200 | return "${CCTK_HOME}" + path[len(self.cactus_dir):] 201 | else: 202 | return path 203 | 204 | 205 | if __name__ == "__main__": 206 | cactus = Cactus() 207 | for thorn in cactus.thorns.values(): 208 | #print(thorn) 209 | #print(thorn.src_files) 210 | print(cactus.find_includes(thorn.name)) 211 | pass 212 | # print(cactus.providers) 213 | # print(cactus.capabilities) 214 | # print(cactus.link_libraries) 215 | # print(cactus.link_options) 216 | 217 | 218 | def make_argument_parser(name:str): 219 | argp = ap.ArgumentParser(prog="CactusCmake", description="Cmake file generator for Cactus") 220 | argp.add_argument("--config", type=str, default=None, help="Cactus config name, e.g. 'sim'") 221 | argp.add_argument("--cactus-root",type=str, default=f"{os.environ['HOME']}/Cactus", help="Cactus root directory") 222 | parsed_args = argp.parse_args(sys.argv[1:]) 223 | cactus_dir:str = parsed_args.cactus_root 224 | config:Optional[str] = parsed_args.config 225 | print(f"Using Cactus root dir: '{cactus_dir}'...") 226 | if config is not None: 227 | print(f"Using config '{config}'...") 228 | 229 | if not os.path.exists(f"{cactus_dir}"): 230 | die("Cactus root directory, '{cactus_dir}', does not exist") 231 | 232 | if config is None: 233 | if os.path.exists(f"{cactus_dir}/configs"): 234 | configs_dir = f"{cactus_dir}/configs" 235 | configs_list = os.listdir(configs_dir) 236 | if len(configs_list) == 1: 237 | config = configs_list[0] 238 | else: 239 | print("Configs that exist:") 240 | for cfg in configs_list: 241 | print(" ",cfg) 242 | die("Please choose a config") 243 | return argp, cactus_dir, config 244 | -------------------------------------------------------------------------------- /CactusCmake.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from typing import List, Dict, Optional 4 | 5 | from cactus import Cactus, make_argument_parser 6 | 7 | providers: Dict[str, str] = dict() 8 | 9 | f_line_directives_setting : Optional[bool] = None 10 | 11 | def find_f_line_directives(config)->bool: 12 | global f_line_directives_setting 13 | if f_line_directives_setting is not None: 14 | return f_line_directives_setting 15 | fname = f"{config}/config-data/make.config.defn" 16 | ret = False 17 | with open(fname) as fd: 18 | for line in fd.readlines(): 19 | if g := re.match("export\\s+F_LINE_DIRECTIVES\\s+=\\s+(yes|no)"): 20 | print(f"F_LINE_DIRECTIVES={g.group(1)}") 21 | ret = g.group(1) == "yes" 22 | f_line_directives_setting = ret 23 | return ret 24 | 25 | file_counter = 0 26 | file_transform_counter = 0 27 | 28 | file_contents = """ 29 | project(thorn_) 30 | 31 | 32 | 33 | # Add the library 34 | add_library( 35 | thorn_ 36 | STATIC 37 | ${CONFIG}/bindings/build//cctk_ThornBindings.c 38 | #${CONFIG}/build//cctk_Bindings/cctk_ThornBindings.c 39 | #${BUILD}/CactusBindings/Parameters/_Parameters.c 40 | ${CONFIG}/bindings/Parameters/_Parameters.c 41 | #${BUILD}/CactusBindings/Schedule/Schedule.c 42 | ${CONFIG}/bindings/Schedule/Schedule.c 43 | ${BINDINGS}/Variables/.c 44 | 45 | ) 46 | 47 | target_compile_options( 48 | thorn_ 49 | PRIVATE 50 | -DCCODE 51 | -fopenmp 52 | -rdynamic 53 | ${MPI_C_COMPILE_OPTIONS} 54 | ) 55 | 56 | target_include_directories( 57 | thorn_ 58 | PUBLIC 59 | ${ARRANGEMENTS}///src 60 | ${CONFIG}/config-data 61 | ${CONFIG}/bindings/include 62 | ${CCTK_HOME}/src/include 63 | ${ARRANGEMENTS} 64 | ${CONFIG}/bindings/Configuration/Thorns 65 | ${CONFIG}/bindings/include/ 66 | ${ARRANGEMENTS}///src 67 | ${ARRANGEMENTS}///src/include 68 | ${MPI_C_INCLUDE_DIRS} 69 | 70 | )""" 71 | 72 | flesh_file_contents = """ 73 | project(thorn_Cactus) 74 | 75 | 76 | 77 | # Add the library 78 | add_library( 79 | thorn_Cactus 80 | STATIC 81 | ${CONFIG}/build/Cactus/cctk_Bindings/cctk_ThornBindings.c 82 | ${CONFIG}/build/CactusBindings/Parameters/Cactus_Parameters.c 83 | ${CONFIG}/build/CactusBindings/Schedule/ScheduleCactus.c 84 | ${BINDINGS}/Variables/Cactus.c 85 | ${BINDINGS}/Functions/RegisterThornFunctions.c 86 | ${BINDINGS}/Schedule/BindingsSchedule.c 87 | ${BUILD}/CactusBindings/Functions/AliasedFunctions.c 88 | ${BINDINGS}/Schedule/BindingsParameterRecovery.c 89 | ${BUILD}/CactusBindings/Functions/IsFunctionAliased.c 90 | ${BINDINGS}/Implementations/ImplementationBindings.c 91 | ${BINDINGS}/Parameters/BindingsParameters.c 92 | #${CCTK_HOME}/src/datestamp.c 93 | ${BINDINGS}/Variables/BindingsVariables.c 94 | 95 | ) 96 | 97 | target_compile_options( 98 | thorn_Cactus 99 | PRIVATE 100 | -DCCODE 101 | -fopenmp 102 | -g 103 | ${MPI_C_COMPILE_OPTIONS} 104 | ) 105 | 106 | target_include_directories( 107 | thorn_Cactus 108 | PUBLIC 109 | 110 | ${CONFIG}/config-data 111 | ${CONFIG}/bindings/include 112 | ${CCTK_HOME}/src/include 113 | ${CONFIG}/bindings/Configuration/Thorns 114 | ${CONFIG}/bindings/include/Cactus 115 | ${CONFIG}/bindings/include 116 | ${CCTK_HOME}/src/schedule 117 | ${CCTK_HOME}/src/piraha 118 | #${MPI_C_INCLUDE_DIRS} 119 | )""" 120 | 121 | # if test no = 'yes'; then echo '#line 1 "'/home/sbrandt/Cactus/arrangements/CactusNumerical/SummationByParts/src/All_Coeffs_mod.F90'"'; fi; 122 | # cat /home/sbrandt/Cactus/arrangements/CactusNumerical/SummationByParts/src/All_Coeffs_mod.F90; } | 123 | # perl -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' | 124 | # cpp -traditional -D_OPENMP -I"/home/sbrandt/Cactus/arrangements/CactusNumerical/SummationByParts/src" 125 | # -I"/home/sbrandt/Cactus/configs/sim/config-data" -I"/home/sbrandt/Cactus/configs/sim/bindings/include" 126 | # -I"/home/sbrandt/Cactus/src/include" -I"/home/sbrandt/Cactus/arrangements" -I"/home/sbrandt/Cactus/configs/sim/bindings/Configuration/Thorns" 127 | # -I"/home/sbrandt/Cactus/configs/sim/bindings/include/SummationByParts" -I"/home/sbrandt/Cactus/arrangements/CactusNumerical/SummationByParts/src" 128 | # -I"/home/sbrandt/Cactus/configs/sim/bindings/include/SummationByParts" -DFCODE -DF90CODE | 129 | # perl -p -e 's.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.//.g' | 130 | # perl -p -e 's/__FORTRANFILE__/\"All_Coeffs_mod.F90\"/g' | 131 | # perl -s /home/sbrandt/Cactus/lib/sbin/f_file_processor.pl -free_format -line_directives=no 132 | # -source_file_name=/home/sbrandt/Cactus/arrangements/CactusNumerical/SummationByParts/src/All_Coeffs_mod.F90 > All_Coeffs_mod.f90 133 | 134 | special_custom_command = """ 135 | add_custom_command( 136 | OUTPUT ${BUILD}/mkfort.sh 137 | COMMAND echo "perl -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g'" > 138 | DEPENDS ${ARRANGEMENTS}///src/ 139 | ) 140 | """ 141 | 142 | f90_file_proc = """ 143 | add_custom_command( 144 | OUTPUT ${BUILD}// 145 | COMMAND mkdir -p ${BUILD}/ 146 | COMMAND perl -p -e 's.//.CCTK_AUTOMATICALLY_GENERATED_CONCATENATION_PROTECTION.g' < ${ARRANGEMENTS}///src/ > ${BUILD}//.tmp1 147 | COMMAND cpp -traditional -D_OPENMP -I"/${ARRANGEMENTS}///src" \ 148 | # -I"${CONFIG}/config-data" -I"${CONFIG}/bindings/include" \ 149 | # -I"${CACTUS}/src/include" -I"${ARRANGEMENTS}" -I"${CONFIG}/bindings/Configuration/Thorns" \ 150 | # -I"${CONFIG}/bindings/include/" -I"${ARRANGEMENTS}///src" \ 151 | # -I"${CONFIG}/bindings/include/" -DFCODE -DF90CODE < ${BUILD}//.tmp1 > ${BUILD}//.tmp2 152 | COMMAND mkFort.sh ${ARRANGEMENTS}///src/ ${BUILD}// 153 | DEPENDS ${ARRANGEMENTS}///src/ 154 | ) 155 | """ 156 | 157 | c_file_proc = """ 158 | add_custom_command( 159 | OUTPUT ${BUILD}// 160 | COMMAND mkdir -p ${BUILD}/ && ${PERL} -s ${C_FILE_PROCESSOR} -line_directives=yes -source_file_name=${ARRANGEMENTS}///src/ ${CONFIG}/config-data < ${ARRANGEMENTS}///src/ > ${BUILD}// 161 | DEPENDS ${ARRANGEMENTS}///src/ 162 | ) 163 | """ 164 | 165 | c_file_proc2 = """ 166 | add_custom_command( 167 | OUTPUT ${BUILD}/Cactus/ 168 | COMMAND mkdir -p ${BUILD}/Cactus && ${PERL} -s ${C_FILE_PROCESSOR} -line_directives=yes -source_file_name=${CCTK_HOME}/src/ ${CONFIG}/config-data < ${CCTK_HOME}/src/ > ${BUILD}/Cactus/ 169 | DEPENDS ${CCTK_HOME}/src/ 170 | ) 171 | """ 172 | 173 | c_piraha = """ 174 | 175 | add_custom_command( 176 | OUTPUT ${BINDINGS}/include/ParGrammar.hh 177 | COMMAND mkdir -p ${BINDINGS}/include 178 | COMMAND ${PERL} ${CCTK_HOME}/src/piraha/make.hh.pl ${CCTK_HOME}/src/piraha/pegs/par.peg ${BINDINGS}/include/ParGrammar.hh 179 | DEPENDS ${CCTK_HOME}/src/piraha/pegs/par.peg 180 | ) 181 | 182 | add_custom_target(generate_grammar 183 | DEPENDS ${BINDINGS}/include/ParGrammar.hh 184 | ) 185 | 186 | add_dependencies( 187 | thorn_Cactus 188 | generate_grammar 189 | ) 190 | """ 191 | 192 | 193 | def has_fname(fname): 194 | with open(fname, "r") as fd: 195 | for line in fd.readlines(): 196 | if "CCTK_FNAME" in line: 197 | return True 198 | return False 199 | 200 | 201 | def trimlist(oldlist): 202 | used = set() 203 | newlist = list() 204 | for item in oldlist: 205 | if item in used: 206 | continue 207 | used.add(item) 208 | newlist.append(item) 209 | return newlist 210 | 211 | searched_for_deps = dict() 212 | 213 | def do_thorn(cactus:Cactus, thorn_name:str): 214 | global file_counter, file_transform_counter 215 | 216 | if thorn_name not in cactus.thorns: 217 | return 218 | thorn_info = cactus.thorns[thorn_name] 219 | arr, thorn_dir = thorn_info.arr, thorn_info.dir 220 | #print("do_thorn:", thorn) 221 | c_file_procs = "" 222 | buf2 = "" 223 | thorn_info = cactus.thorns[thorn_name] 224 | 225 | for src_file in thorn_info.src_files: 226 | if re.match(r'^.*\.(cxx|cpp|cc|c|C|F|F90)$', src_file): 227 | buf = c_file_proc 228 | buf = re.sub(r'', thorn_name, buf) 229 | buf = re.sub(r'', arr, buf) 230 | buf = re.sub(r'', src_file, buf) 231 | #buf = re.sub(r'',"\n".join(incs),buf) 232 | real_file = f"{thorn_dir}/src/{src_file}" 233 | if has_fname(real_file): 234 | buf2 += " ${BUILD}/" + thorn_name + "/" + src_file + "\n" 235 | file_transform_counter += 1 236 | else: 237 | buf2 += " ${CCTK_HOME}/" + real_file[len(cactus_dir) + 1:] 238 | file_counter += 1 239 | c_file_procs += buf 240 | 241 | includes:List[str] = list() 242 | for include in cactus.find_includes(thorn_name): 243 | includes.append(cactus.nice_path(include)) 244 | 245 | if cactus.provides_functions(thorn_name): 246 | buf2 += f" ${{BUILD}}/CactusBindings/Functions/{thorn_name}_Functions.c\n" 247 | 248 | buf = file_contents 249 | buf = re.sub(r'', thorn_name, buf) 250 | buf = re.sub(r'', c_file_procs, buf) 251 | buf = re.sub(r'', buf2, buf) 252 | buf = re.sub(r'', arr, buf) 253 | buf = re.sub(r'', '\n '.join(includes), buf) 254 | 255 | with open(f"{config_dir}/CMake_{thorn_name}.txt", "w") as fd: 256 | print(buf, file=fd) 257 | 258 | 259 | def do_flesh(): 260 | c_file_procs = "" 261 | buf2 = "" 262 | thorn = "src" 263 | arr = "Cactus" 264 | #for src_file in os.listdir(f"{cactus}/src"): 265 | search = f"{cactus_dir}/src" 266 | print("Walking:",search) 267 | for dirpath, dirnames, filenames in os.walk(search): 268 | for src_file_top in filenames: 269 | if src_file_top in ["datestamp.c", "Generic.cc", "RecordImplementation.c", "regex.c"]: 270 | continue 271 | src_file = f"{dirpath}/{src_file_top}"[len(search) + 1:] 272 | #if re.match(r'^.*\.(cxx|cpp|cc|c|C|hxx|hh|hpp|h)$', src_file): 273 | if re.match(r'^.*\.(cxx|cpp|cc|c|C)$', src_file): 274 | buf = c_file_proc2 275 | buf = re.sub(r'', "Cactus", buf) 276 | buf = re.sub(r'', arr, buf) 277 | buf = re.sub(r'', src_file, buf) 278 | buf2 += " ${BUILD}/Cactus/" + src_file + "\n" 279 | print(">> SRC_FILE:", src_file) 280 | c_file_procs += buf 281 | else: 282 | print("SKIP>>", src_file) 283 | 284 | 285 | incs = cactus.find_includes( "Cactus") 286 | 287 | has_provides = False 288 | piraha_file = f"{config_dir}/piraha/{arr}/{thorn}/interface.cache" 289 | with open(piraha_file, "r") as fd: 290 | for line in fd.readlines(): 291 | if ",PROVIDES_FUN" in line: 292 | has_provides = True 293 | buf2 += f" ${{BUILD}}/CactusBindings/Functions/{thorn}_Functions.c\n" 294 | break 295 | 296 | buf = flesh_file_contents 297 | buf = re.sub(r'', thorn, buf) 298 | buf = re.sub(r'', c_file_procs, buf) 299 | buf = re.sub(r'', buf2, buf) 300 | buf = re.sub(r'', arr, buf) 301 | buf = re.sub(r'', '\n '.join(incs), buf) 302 | buf += c_piraha 303 | 304 | with open(f"{config_dir}/CMake_Cactus.txt", "w") as fd: 305 | print("# FLESH GENERATION", file=fd) 306 | print(buf, file=fd) 307 | 308 | ########### START ############## 309 | 310 | argp, cactus_dir, config = make_argument_parser("CactusCmake") 311 | cactus = Cactus(cactus_dir=cactus_dir, config=config) 312 | config_dir = cactus.config_dir 313 | print(f"Creating '{cactus.cactus_dir}/CMakeLists.txt' based on '{config_dir}' ...") 314 | 315 | with open(f"{cactus_dir}/CMakeLists.txt", "w") as fd: 316 | print("cmake_minimum_required(VERSION 3.10)", file=fd) 317 | print("project(cactus_sim)", file=fd) 318 | print(""" 319 | set(MPI_HOME "/home/sbrandt/spack/var/spack/environments/cactus/.spack-env/view") 320 | set(MPI_C_COMPILER "${MPI_HOME}/bin/mpicc") 321 | set(MPI_CXX_COMPILER "${MPI_HOME}/bin/mpicxx") 322 | 323 | find_package(MPI REQUIRED) 324 | set(CONFIG_NAME "") 325 | set(CCTK_HOME "") 326 | set(CONFIGS "${CCTK_HOME}/configs") 327 | set(CONFIG "${CONFIGS}/${CONFIG_NAME}") 328 | set(PERL "/usr/bin/perl") 329 | set(ARRANGEMENTS "${CCTK_HOME}/arrangements") 330 | set(BUILD "${CONFIG}/build") 331 | set(BINDINGS "${CONFIG}/bindings") 332 | set(C_FILE_PROCESSOR "${CCTK_HOME}/lib/sbin/c_file_processor.pl") 333 | 334 | set(CMAKE_CXX_LINK_GROUP_USING_cross_refs_SUPPORTED TRUE) 335 | set(CMAKE_CXX_LINK_GROUP_USING_cross_refs 336 | "LINKER:--start-group" 337 | "LINKER:--end-group" 338 | ) 339 | 340 | add_executable(cactus_ 341 | ${CCTK_HOME}/src/datestamp.c 342 | #${BINDINGS}/Variables/BindingsVariables.c 343 | ) 344 | set_target_properties(cactus_ PROPERTIES LINKER_LANGUAGE CXX) 345 | 346 | target_compile_options(cactus_ PUBLIC $<$:-std=gnu99>) 347 | 348 | target_compile_options( 349 | cactus_ 350 | PRIVATE 351 | -DCCODE 352 | -fopenmp 353 | -rdynamic 354 | #${MPI_C_COMPILE_OPTIONS} 355 | ) 356 | 357 | target_link_options( 358 | cactus_ 359 | PRIVATE 360 | -fopenmp 361 | -rdynamic 362 | 363 | ) 364 | 365 | target_include_directories( 366 | cactus_ 367 | PUBLIC 368 | ${CONFIG}/bindings/include/Cactus 369 | ${CONFIG}/config-data 370 | ${CONFIG}/bindings/include 371 | ${CONFIG}/build/Cactus/main 372 | ${CCTK_HOME}/src/include 373 | #${MPI_C_INCLUDE_DIRS} 374 | ) 375 | """.replace("", cactus_dir) \ 376 | .replace("", config) \ 377 | .replace("", "\n".join(cactus.link_options)), file=fd) 378 | do_flesh() 379 | thorn_list:List[str] = list() 380 | with open(f"{cactus_dir}/configs/{config}/ThornList", "r") as fth: 381 | for line in fth.readlines(): 382 | if g := re.match(r'^(\w+)/(\w+)', line): 383 | thorn = g.group(2) 384 | thorn_list.append(thorn) 385 | for thorn in thorn_list: 386 | do_thorn(cactus, thorn) 387 | print(f"include(configs/{config}/CMake_{thorn}.txt)", file=fd) 388 | print(f"include(configs/{config}/CMake_Cactus.txt)", file=fd) 389 | print(f"target_link_libraries(cactus_{config}", file=fd) 390 | for thorn in thorn_list: 391 | pass #print(f' thorn_{thorn}', file=fd) 392 | #print(f" thorn_Cactus", file=fd) 393 | thorn_list += ["Cactus"] 394 | #print(" ${MPI_C_LIBRARIES}",file=fd) 395 | #print(" adios2_fortran_mpi adios2_cxx11_mpi adios2_core_mpi adios2_fortran adios2_cxx11 adios2_c adios2_core",file=fd) 396 | #print(" /home/sbrandt/Cactus/configs/waveeqn/scratch/external/AMReX/lib/libamrex.a",file=fd) 397 | for lib in cactus.link_libraries: 398 | pass #print(" ", lib, file=fd) 399 | print(" \"$\"", file=fd) 400 | print(")", file=fd) 401 | #print("file_counter:", file_counter) 402 | #print("file_transform_counter:", file_transform_counter) 403 | #print("percent transformed: %.2f" % (100 * file_transform_counter / file_counter)) 404 | print("Done") 405 | --------------------------------------------------------------------------------