def main(): for top in find_src_dirs(): assert os.path.exists(top) retval = 0 for root, dirs, files in os.walk(top): # Sort dirs dirs.sort() for item in files: # Skip some dirs ignored = 0 for dd in IGNORED_DIRS: if root.find(dd) != -1: ignored = 1 if ignored == 0: if re_srcfile.search(item): path = os.path.join(root, item) with open(path, "rt") as fh: src_data = fh.read() src_count = len(re.findall(re_config, src_data)) if src_count == 0: sys.stderr.write( "%s/%s: missing include of config.h\n" % (root, item)) retval = 1 elif src_count > 1: sys.stdout.write( "%s/%s: %d includes of config.h\n" % (root, item, src_count)) return retval
def main(): print("-------------------------------------------------------") print(" Searching for inlined CPP macros in ABINIT src files ") print("-------------------------------------------------------") exit_status = 0 for top in find_src_dirs(): assert os.path.isdir(top) for dirpath, dirnames, files in os.walk(top): for src in files: if not is_srcfile(dirpath, src): continue fpath = os.path.join(dirpath,src) with open(fpath, "rt") as fh: for lno, line in enumerate(fh): s = wrong_string(line) if s: print("(INLINED MACRO at %s:%d): %s " % (src, lno+1, line)) exit_status += 1 if exit_status > 0: err_msg = """ Please, avoid instructions like: if (allocated(arr)) ABI_DEALLOCATE(arr) When the code is compiled in profile mode, indeed, ABI_DEALLOCATE expands to the set of Fortran instructions: deallocate(arr) call memocc_abi() These instructions MUST be placed inside an "if then" "end if" block. This limitation can be lifted, but we need support at the level of the build system. For the time being, one has to use the more verbose form: if (allocated(arr)) then ABI_DEALLOCATE(arr) end if This is the list of macros that cannot be inlined: %(MACRO_NAMES)s """ % globals() print(err_msg) return exit_status
def main(): print("--------------------------------------------------------") print(" Searching for non-ASCII characters in ABINIT src files ") print("--------------------------------------------------------") exit_status = 0 for top in find_src_dirs(): for dirpath, dirnames, files in os.walk(top): for src in files: if is_srcfile(dirpath, src): fpath = os.path.join(dirpath, src) with open(fpath, "rt") as fh: lines = fh.readlines() for lno, line in enumerate(lines): if not isascii(line): exit_status += 1 print(">>> Non-ASCII character at: ", fpath, ":", lno + 1) print(line) return exit_status
def main(): retval = 0 for top in find_src_dirs(): for root, dirs, files in os.walk(top): # Check line lengths in Fortran source files for item in files: if re_srcfile.search(item) and item != "m_build_info.F90": lineno = 1 path = os.path.join(root, item) with open(path, "rt") as fh: for line in fh: line = re.sub("!.*", "", line) line = re.sub("\n", "", line) if len(line) > len_limit: sys.stderr.write( "%s: line %d has more than %d characters\n" % (path, lineno, len_limit)) sys.stdout.write( "%s: line %d has more than %d characters\n" % (path, lineno, len_limit)) retval = 1 lineno += 1 return retval
def main(): top = find_abinit_toplevel_directory() verbose = 0 # Extract CPP options from the libPAW header files #libpaw_dir = os.path.join(top, "src", "39_libpaw") libpaw_dir = os.path.join(top, "shared", "libpaw") assert os.path.isdir(libpaw_dir) cpp_libpaw = list() for root,dirs,files in os.walk(libpaw_dir): for src in files: if ( re_hdrfile.search(src) ): with open(os.path.join(root,src), "rt") as fh: for line in fh: if ( re_cppdef.search(line) ): tmp_def = re.sub("^[# ]*define[ ]*([0-9A-Z_]*).*","\\1",line).strip() if ( not tmp_def in cpp_libpaw ): cpp_libpaw.append(tmp_def) # Extract CPP options from the libTetra header files libtetra_dir = os.path.join(top, "shared", "common", "src", "17_libtetra_ext") assert os.path.isdir(libtetra_dir) cpp_libtetra = list() for root,dirs,files in os.walk(libtetra_dir): for src in files: if ( re_hdrfile.search(src) ): with open(os.path.join(root,src), "rt") as fh: for line in fh: if ( re_cppdef.search(line) ): tmp_def = re.sub("^[# ]*define[ ]*([0-9A-Z_]*).*","\\1",line).strip() if ( not tmp_def in cpp_libtetra ): cpp_libtetra.append(tmp_def) # Extract CPP options from the build system cpp_buildsys = list() m4_path = os.path.join(top, "config", "m4") assert os.path.isdir(m4_path) for root,dirs,files in os.walk(m4_path): for src in files: if ( src.endswith(".m4") ): with open(os.path.join(root, src), "rt") as fh: for line in fh: if re_acdef.search(line): tmp_def = re.sub(".*AC_DEFINE\\([\\[]?([^\\],]*).*","\\1",line).strip() if not tmp_def in cpp_buildsys: cpp_buildsys.append(tmp_def) with open(os.path.join(top, "configure.ac"), "rt") as fh: for line in fh: if ( re_acdef.search(line) ): tmp_def = re.sub(".*AC_DEFINE\\([\\[]?([^\\],]*).*","\\1",line).strip() if ( not tmp_def in cpp_buildsys ): cpp_buildsys.append(tmp_def) cpp_buildsys = cpp_buildsys + cpp_libpaw + cpp_libtetra cpp_buildsys.sort() # Create CPP naming blocks for opt in cpp_buildsys: tmp = opt.split("_") for i in range(len(tmp)): if ( i >= len(cpp_blocks) ): cpp_blocks.append(list()) if ( not tmp[i] in cpp_blocks[i] ): cpp_blocks[i].append(tmp[i]) # Extract CPP options from the includes incs_dir = os.path.join(top, "src", "incs") assert os.path.isdir(incs_dir) cpp_includes = list() for root,dirs,files in os.walk(incs_dir): for src in files: if not re_hdrfile.search(src): continue with open(os.path.join(root,src), "rt") as fh: for line in fh: if re_cppdef.search(line): tmp_def = re.sub("^[# ]*define[ ]*([0-9A-Z_]*).*","\\1",line).strip() if not tmp_def in cpp_includes: cpp_includes.append(tmp_def) cpp_includes.sort() # Merge CPP information cpp_allowed = cpp_explicit + cpp_buildsys cpp_allowed.sort() # Explore the source files cpp_source = dict() #src_dir = os.path.join(top, "src") #assert os.path.isdir(src_dir) for src_dir in find_src_dirs(): for root,dirs,files in os.walk(src_dir): files.sort() for src in files: if re_f90file.search(src): with open(os.path.join(root, src), "rt") as fh: f90_buffer = fh.readlines() cpp_load = False for i in range(len(f90_buffer)): line = f90_buffer[i] # Record CPP lines if ( re_cppline.search(line) ): if ( cpp_load ): sys.stderr.write("%s: %s:%d: Error: unterminated CPP directive\n" % \ (my_name,src,i+1)) sys.exit(1) cpp_load = True cpp_buffer = "" # Process CPP lines if ( cpp_load ): cpp_buffer += line if ( not re_cppcont.search(line) ): if ( not re_cppskip.search(line) ): # Extract CPP options for kwd in cpp_keywords: cpp_buffer = re.sub(kwd,"",cpp_buffer) cpp_buffer = re.sub("[\n\t ]+"," ",cpp_buffer) cpp_buffer = cpp_buffer.strip() cpp_buffer = cpp_buffer.split() # Register CPP options for opt in cpp_buffer: if ( not opt in cpp_ignored ): if ( not opt in cpp_source ): cpp_source[opt] = list() cpp_source[opt].append("%s/%s:%d" % (root,src,i+1)) # Reset cpp_load = False # Process CPP option information cpp_keys = list(cpp_source.keys()) cpp_keys.sort() cpp_devel = [opt for opt in cpp_keys \ if ( opt in cpp_explicit or re_cppdev.match(opt) )] cpp_undefined = [opt for opt in cpp_keys \ if not ( (opt in cpp_allowed) or (opt in cpp_devel) )] cpp_misnamed = [opt for opt in cpp_keys \ if not ( check_name(opt,cpp_blocks) or (opt in cpp_undefined) or (opt in cpp_devel) ) ] cpp_misnamed += [opt for opt in cpp_includes \ if ( opt in cpp_source and not (check_name(opt,cpp_blocks) or opt in cpp_devel))] cpp_misnamed.sort() # Display forbidden CPP options if ( (verbose and (len(cpp_devel) > 0)) or (len(cpp_undefined) > 0) ): sys.stderr.write("%s: reporting preprocessing option discrepancies\n\n" % \ (os.path.basename(sys.argv[0]))) sys.stderr.write("X: N=Wrong Naming / U=Undefined\n\n") if ( verbose and (len(cpp_devel) > 0) ): sys.stderr.write("%s %-24s %-44s\n" % ("X","Developer option","Location")) sys.stderr.write("%s %-24s %-44s\n" % ("-","-" *24,"-" * 48)) for opt in cpp_devel: if ( len(cpp_source[opt]) <= 50 ): for src in cpp_source[opt]: sys.stderr.write("* %-24s %-48s\n" % (opt,src)) else: sys.stderr.write("* %-24s Not shown (referenced %d times)\n" % \ (opt,len(cpp_source[opt]))) sys.stderr.write("\n") retval = len(cpp_undefined) + len(cpp_misnamed) if retval != 0: sys.stderr.write("%s %-24s %-44s\n" % ("X","Forbidden option","Location")) sys.stderr.write("%s %-24s %-44s\n" % ("-","-" *24,"-" * 48)) for opt in cpp_undefined: if ( len(cpp_source[opt]) <= 50 ): for src in cpp_source[opt]: sys.stderr.write("U %-24s %-48s\n" % (opt,src)) else: sys.stderr.write("U %-24s Not shown (referenced %d times)\n" % \ (opt,len(cpp_source[opt]))) for opt in cpp_misnamed: sys.stderr.write("N %-24s N/A\n" % (opt)) sys.stderr.write("\n") return retval
def main(): print() print( '---------------------------------------------------------------------' ) print( ' Looking for forbidden statements in ABINIT src files: ' ) if ACTIVATE_TEST1 or ACTIVATE_TEST2: print( ' - forbidden access to standard output/standard error ' ) if ACTIVATE_TEST3: print( ' - forbidden allocate/deallocate statements ' ) if ACTIVATE_TEST4: print( ' - forbidden explicit MPI_COMM_WORLD communicator ' ) if ACTIVATE_TEST5: print( ' - forbidden call statements not placed at the start of the line ' ) print( '---------------------------------------------------------------------' ) re_srcfile = re.compile("\.([Ff]|[Ff]90|finc|h)$") #Initialize counters file_total_count = 0 stat_forbidden_write_count = 0 file_forbidden_write_count = 0 stat_notrecommended_write_count = 0 file_notrecommended_write_count = 0 stat_forbidden_commworld_count = 0 file_forbidden_commworld_count = 0 stat_forbidden_allocate_count = 0 file_forbidden_allocate_count = 0 stat_forbidden_call_count = 0 file_forbidden_call_count = 0 # Loop over files in src folder for top in find_src_dirs(): for root, dirs, files in os.walk(top): for src in files: if re_srcfile.search(src): file_total_count += 1 filename = os.path.join(root, src) with open(filename, "rt") as fh: src_data = fh.readlines() #Loop over lines in the file lineno = 0 icount_forbidden_write = 0 icount_notrecommended_write = 0 icount_forbidden_commworld = 0 icount_forbidden_allocate = 0 icount_forbidden_call = 0 for line_orig in src_data: lineno += 1 #Transform line to lower case + eliminate whitespaces line_lower = line_orig.lower() line = re.sub(" ", "", line_lower) #Skip lines beginning with an authorized character ignored = 0 for strg in NO_ERROR_LIST: if line.find(strg) == 0: ignored = 1 if ignored == 0: #Look for forbidden write statements if ACTIVATE_TEST1 and (not src in IGNORED_WRITE_FILES): for strg in WRITE_FORBIDDEN_LIST: if line.find(strg) != -1: print( ' Error: %s, line %d: found \"%s\" !' % (filename, lineno, strg)) icount_forbidden_write += 1 #Look for not recommended write statements if ACTIVATE_TEST2 and (not src in IGNORED_WRITE_FILES): for strg in WRITE_NOTRECOMMENDED_LIST: if line.find(strg) != -1 and src not in [ "m_specialmsg.F90" ]: print( '- Warning: %s, line %d: found \"%s\" !' % (filename, lineno, strg)) icount_notrecommended_write += 1 #Look for forbidden MPI_COMM_WORLD statements if ACTIVATE_TEST3 and (not src in IGNORED_COMMWORLD_FILES): for strg in COMMWORLD_FORBIDDEN_LIST: if line.find(strg) != -1: print( ' Error: %s, line %d: found \"%s\" !' % (filename, lineno, strg)) icount_forbidden_commworld += 1 #Look for forbidden allocate/deallocate statements if ACTIVATE_TEST4 and (not src in IGNORED_ALLOCATE_FILES): ifound = 0 for strg in ALLOCATE_FORBIDDEN_LIST: ialloc = line.find(strg) if ifound == 0 and ialloc != -1: ifound = 1 if not '_' + strg in line: if ialloc + len(strg) < len(line): if line[ialloc - 4: ialloc] != "abi_" and line[ ialloc + len(strg)] == "(": print( ' Error: %s, line %d: found \"%s\" !' % (filename, lineno, strg)) icount_forbidden_allocate += 1 #Look for forbidden call statements (not placed at the start of the line) if ACTIVATE_TEST5 and (not src in IGNORED_CALL_FILES): for strg in CALL_STATEMENT_LIST: icall = line_lower.find(" " + strg + " ") if icall > 0: line_before = re.sub( " ", "", line_lower[:icall]) line_after = re.sub( " ", "", line_lower[icall + 3:len(line_lower) - 1]) nothing_before = ( len(line_before) == 0) comment_before = (line_before.find("!") != -1) label_before = (not (re.match( '[0-9]+', line_before) == None)) quote_before = ( (line_before.find("'") != -1) or (line_before.find('"') != -1)) problem_before = ((not nothing_before) and (not label_before) and (not quote_before)) problem_after = (re.match( '[^\;\:\>\<\=\+\-\*\/\!\,]*(\(.*[\)\&]+|)', line_after) == None) if (not comment_before) and ( problem_before or problem_after): print(' Error: %s, line %d: found \"%s\" not placed at the start of the line !' \ % (filename,lineno,strg)) icount_forbidden_call += 1 #Update counters stat_forbidden_write_count += icount_forbidden_write stat_notrecommended_write_count += icount_notrecommended_write stat_forbidden_commworld_count += icount_forbidden_commworld stat_forbidden_allocate_count += icount_forbidden_allocate stat_forbidden_call_count += icount_forbidden_call if icount_forbidden_write > 0: file_forbidden_write_count += 1 if icount_notrecommended_write > 0: file_notrecommended_write_count += 1 if icount_forbidden_commworld > 0: file_forbidden_commworld_count += 1 if icount_forbidden_allocate > 0: file_forbidden_allocate_count += 1 if icount_forbidden_call > 0: file_forbidden_call_count += 1 # Print final message print('----------->') print('- There are %d F90 or header files in the complete set.' % file_total_count) assert file_total_count exit_status = (stat_forbidden_write_count + stat_notrecommended_write_count + stat_forbidden_commworld_count + stat_forbidden_allocate_count + stat_forbidden_call_count) if stat_forbidden_write_count==0 and stat_notrecommended_write_count==0 and \ stat_forbidden_commworld_count==0 and stat_forbidden_allocate_count==0 and \ stat_forbidden_call_count==0: print('- No Error or Warning !') else: if stat_forbidden_write_count > 0: print() print( '>>> %d error(s) (forbidden write statement(s)), appearing in %d different file(s)!' % \ (stat_forbidden_write_count,file_forbidden_write_count)) print() print(' Replace the forbidden statement(s) by allowed ones:\n') print( ' "write(std_out,", "write(std_err," or "write(ab_out,".\n' ) print(' Note that std_out redirects to the ABINIT log file') print(' while ab_out redirects to the ABINIT output file') print(' while std_err redirects to number 0 unit.') if stat_notrecommended_write_count > 0: print() print( '>>> %d WARNINGS (not recommended write statement(s)), appearing in %d different file(s) !' % \ (stat_notrecommended_write_count,file_notrecommended_write_count)) print() print( ' Writing to the standard error is allowed in the following cases:\n' ) print( ' - Within debugging sections of ABINIT, not activated in the production version;' ) print( ' - In case an error has been detected, causing stop to ABINIT.\n' ) print( ' In other cases, writing to std_err is not recommended, and should be avoided.' ) if stat_forbidden_commworld_count > 0: print() print( '>>> %d ERRORS(s) (forbidden MPI_COMM_WORLD statement(s)), appearing in %d different file(s)!' % \ (stat_forbidden_commworld_count,file_forbidden_commworld_count)) print() print( ' Replace the MPI_COMM_WORLD forbidden statement(s) by allowed ones:\n' ) print(' - "xmpi_world" or "mpi_enreg%world_comm".') print( ' - MPI_COMM_WORLD is not allowed because it may be redefined in some cases\n' ) if stat_forbidden_allocate_count > 0: print() print( '>>> %d ERROR(s) (forbidden allocate/deallocate statement(s)), appearing in %d different file(s)!\n' % \ (stat_forbidden_allocate_count,file_forbidden_allocate_count)) print() print( ' Replace the forbidden allocate statement(s) by the ABI_ALLOCATE macro defined in abi_common.h' ) print( ' Replace the forbidden deallocate statement(s) by the ABI_DEALLOCATE macro defined in abi_common.h' ) print( ' You need to add `#include "abi_common.h"` and `use m_errors` to have access to these macros.' ) print( ' Note that the syntax of the ABI_ALLOCATE macro is not exactly the same as the allocate statement:\n' ) print( ' - only one array to be allocated in each ABI_ALLOCATE') print( ' - separate the array from the parenthesis and size with a comma' ) print( ' - example: instead of allocate(arr1(3,N), arr2(20)), you should write the allocations separately using:\n' ) print(' ABI_ALLOCATE(arr1,(3,N))') print(' ABI_ALLOCATE(arr2,(20))\n') print( ' Note that the syntax of the ABI_DEALLOCATE macro is not exactly the same as the deallocate statement:\n' ) print( ' - only one array to be deallocated in each ABI_DEALLOCATE' ) print( ' - example: instead of deallocate(arr1,arr2), you should write the deallocations separately using:\n' ) print(' ABI_DEALLOCATE(arr1)') print(' ABI_DEALLOCATE(arr2)\n') print( ' Finally, use ABI_MALLOC_SCALAR and ABI_FREE_SCALAR to allocate/free scalar entities.' ) print(' and ABI_MOVE_ALLOC instead of Fortran move_alloc.') if stat_forbidden_call_count > 0: # MG: Why? Besides there are several macros doing this... print() print( '>> %d ERROR(s) (badly placed call statement(s)), appearing in %d different file(s) !' % \ (stat_forbidden_call_count,file_forbidden_call_count)) print() print( ' Please place the CALL statement at the start of the line.') print(' Avoid: "statement 1 ; call subroutine()"') print(' Avoid: "if (condition) call subroutine()"') return exit_status