From 7a3f1ff75e8d93ee47c23b5b022726c3a943a340 Mon Sep 17 00:00:00 2001 From: Joshua Hursey Date: Tue, 22 Aug 2017 14:59:57 -0400 Subject: [PATCH] contrib: Script to automate LIBADD changes for components * This script will search for all of the `Makefile.am` files in each of the project-level components. Then it adds the project-level library to `mca_FRAMEWORK_COMPONENT_la_LIBADD`. - If the library is already in the LIBADD list then it's skipped. So it is safe to run multiple times on the same codebase. Signed-off-by: Joshua Hursey --- contrib/libadd_mca_comp_update.py | 230 ++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100755 contrib/libadd_mca_comp_update.py diff --git a/contrib/libadd_mca_comp_update.py b/contrib/libadd_mca_comp_update.py new file mode 100755 index 0000000000..2388cadaf4 --- /dev/null +++ b/contrib/libadd_mca_comp_update.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python + +# Copyright (c) 2017 IBM Corporation. All rights reserved. +# $COPYRIGHT$ +# + +import glob, os, re, shutil + +projects= {'opal' : ["$(top_builddir)/opal/lib@OPAL_LIB_PREFIX@open-pal.la"], + 'orte' : ["$(top_builddir)/orte/lib@ORTE_LIB_PREFIX@open-rte.la"], + 'ompi' : ["$(top_builddir)/ompi/lib@OMPI_LIBMPI_NAME@.la"], + 'oshmem' : ["$(top_builddir)/oshmem/liboshmem.la"], + } + +no_anchor_file = [] +missing_files = [] +skipped_files = [] +partly_files = [] +updated_files = [] + +# +# Check of all of the libadd fields are accounted for in the LIBADD +# Return a list indicating which are missing (positional) +# +def check_libadd(content, libadd_field, project): + global projects + + libadd_list = projects[project] + libadd_missing = [True] * len(libadd_list) + + on_libadd = False + for line in content: + # First libadd line + if re.search( r"^\s*"+libadd_field, line): + # If line continuation, then keep searching after this point + if line[-2] == '\\': + on_libadd = True + + for idx, lib in enumerate(libadd_list): + if True == libadd_missing[idx]: + if 0 <= line.find(lib): + libadd_missing[idx] = False + + # Line continuation + elif True == on_libadd: + for idx, lib in enumerate(libadd_list): + if True == libadd_missing[idx]: + if 0 <= line.find(lib): + libadd_missing[idx] = False + + # No more line continuations, so stop processing + if line[-2] != '\\': + on_libadd = False + break + + return libadd_missing + +# +# Update all of the Makefile.am's with the proper LIBADD additions +# +def update_makefile_ams(): + global projects + global no_anchor_file + global missing_files + global skipped_files + global partly_files + global updated_files + + for project, libadd_list in projects.items(): + libadd_str = " \\\n\t".join(libadd_list) + + print("="*40) + print("Project: "+project) + print("LIBADD:\n"+libadd_str) + print("="*40) + + # + # Walk the directory structure + # + for root, dirs, files in os.walk(project+"/mca"): + parts = root.split("/") + if len(parts) != 4: + continue + if parts[-1] == ".libs" or parts[-1] == ".deps" or parts[-1] == "base": + continue + if parts[2] == "common": + continue + + print("Processing: "+root) + + # + # Find Makefile.am + # + make_filename = os.path.join(root, "Makefile.am") + if False == os.path.isfile( make_filename ): + missing_files.append("Missing: "+make_filename) + print(" ---> Error: "+make_filename+" is not present in this directory") + continue + + # + # Stearching for: mca_FRAMEWORK_COMPONENT_la_{LIBADD|LDFLAGS} + # First scan file to see if it has an LIBADD / LDFLAGS + # + libadd_field = "mca_"+parts[2]+"_"+parts[3]+"_la_LIBADD" + ldflags_field = "mca_"+parts[2]+"_"+parts[3]+"_la_LDFLAGS" + has_ldflags = False + has_libadd = False + + r_fd = open(make_filename, 'r') + orig_content = r_fd.readlines() + r_fd.close() + libadd_missing = [] + + for line in orig_content: + if re.search( r"^\s*"+ldflags_field, line): + has_ldflags = True + elif re.search( r"^\s*"+libadd_field, line): + has_libadd = True + + if True == has_libadd: + libadd_missing = check_libadd(orig_content, libadd_field, project) + + # + # Sanity Check: Was there an anchor field. + # If not skip, we might need to manually update or it might be a + # static component. + # + if False == has_ldflags and False == has_libadd: + no_anchor_file.append("No anchor ("+ldflags_field+"): "+make_filename) + print(" ---> Error: Makefile.am does not contain necessary anchor") + continue + + # + # Sanity Check: This file does not need to be updated. + # + if True == has_libadd and all(False == v for v in libadd_missing): + skipped_files.append("Skip: "+make_filename) + print(" Skip: Already updated Makefile.am") + continue + + # + # Now go though and create a new version of the Makefile.am + # + r_fd = open(make_filename, 'r') + w_fd = open(make_filename+".mod", 'w') + + num_libadds=0 + for line in r_fd: + # LDFLAGS anchor + if re.search( r"^\s*"+ldflags_field, line): + w_fd.write(line) + # If there is no LIBADD, then put it after the LDFLAGS + if False == has_libadd: + w_fd.write(libadd_field+" = "+libadd_str+"\n") + # Existing LIBADD field to extend + elif 0 == num_libadds and re.search( r"^\s*"+libadd_field, line): + parts = line.partition("=") + num_libadds += 1 + + if parts[0][-1] == '+': + w_fd.write(libadd_field+" += ") + else: + w_fd.write(libadd_field+" = ") + + # If all libs are missing, then add the full string + # Otherwise only add the missing items + if all(True == v for v in libadd_missing): + w_fd.write(libadd_str) + # Only add a continuation if there is something to continue + if 0 != len(parts[2].strip()): + w_fd.write(" \\") + w_fd.write("\n") + else: + partly_files.append("Partly updated: "+make_filename) + for idx, lib in enumerate(libadd_list): + if True == libadd_missing[idx]: + w_fd.write(lib+" \\\n") + + # Original content (unless it's just a line continuation) + if 0 != len(parts[2].strip()) and parts[2].strip() != "\\": + w_fd.write("\t"+parts[2].lstrip()) + + # Non matching line, just echo + else: + w_fd.write(line) + + r_fd.close() + w_fd.close() + + # + # Replace the original with the updated version + # + shutil.move(make_filename+".mod", make_filename) + updated_files.append(make_filename) + + +if __name__ == "__main__": + + update_makefile_ams() + + print("") + + print("="*40); + print("{:>3} : Files skipped".format(len(skipped_files))) + print("="*40); + + print("="*40); + print("{:>3} : Files updated, but had some libs already in place.".format(len(partly_files))) + print("="*40); + for fn in partly_files: + print(fn) + + print("="*40); + print("{:>3} : Files fully updated".format(len(updated_files))) + print("="*40); + for fn in updated_files: + print(fn) + + print("="*40); + print("{:>3} : Missing Makefile.am".format(len(missing_files))) + print("="*40); + for err in missing_files: + print(err) + + print("="*40); + print("{:>3} : Missing Anchor for parsing (might be static-only components)".format(len(no_anchor_file))) + print("="*40); + for err in no_anchor_file: + print(err) +