From f73c637eb71c69748fb42894e8cfe9c1e5a7bee7 Mon Sep 17 00:00:00 2001 From: Yuan-Ming Hsu <48866415+technic960183@users.noreply.github.com> Date: Thu, 17 Jul 2025 00:15:56 -0700 Subject: [PATCH 1/3] Refactor common variables and functions out --- tool/config/set_settings.sh | 44 ++++++++----------------------------- tool/config/settings.sh | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 35 deletions(-) create mode 100644 tool/config/settings.sh diff --git a/tool/config/set_settings.sh b/tool/config/set_settings.sh index 69387c766b..a094bc27d1 100644 --- a/tool/config/set_settings.sh +++ b/tool/config/set_settings.sh @@ -1,41 +1,17 @@ #!/bin/bash -################### DEFINE KEYS ################### -# The keys can not contain spaces or start with `-` -declare -A KEY_DESCRIPTIONS -KEY_DESCRIPTIONS=( - ["machine"]="Specify the machine name" -) -################################################### - #################### UTILITIES #################### -# List of valid keys -VALID_KEYS=("${!KEY_DESCRIPTIONS[@]}") - -# For padding keys with trailing spaces to format output -MAX_KEY_LENGTH=0 -for key in "${VALID_KEYS[@]}"; do - if [ ${#key} -gt $MAX_KEY_LENGTH ]; then - MAX_KEY_LENGTH=${#key} - fi -done - -# Print keys in a formatted way -print_key() { - # $1 : the key name - # $2 : the key value or additional message - # $3 : indent number (optional, default 0) - printf "%${3}s" "" - printf "%-${MAX_KEY_LENGTH}s %s\n" "$1" "$2" -} +cd "$(dirname "$0")" +source ./settings.sh +# Variables imported from settings.sh: +# KEY_DESCRIPTIONS +# VALID_KEYS +# MAX_KEY_LENGTH -show_valid_keys() { - echo "Valid keys and their functionalities:" - for key in "${!KEY_DESCRIPTIONS[@]}"; do - print_key "$key" "${KEY_DESCRIPTIONS[$key]}" 2 - done -} +# Functions imported from settings.sh: +# print_key() +# show_valid_keys() show_help() { echo "Usage:" @@ -210,8 +186,6 @@ fi ################ LOAD SETTINGS FILE ############### -cd "$(dirname "$0")" - # Load if the settings file exists declare -A EXISTING_SETTINGS if [ -f "$SETTING_FILE" ]; then diff --git a/tool/config/settings.sh b/tool/config/settings.sh new file mode 100644 index 0000000000..b11fd01a7e --- /dev/null +++ b/tool/config/settings.sh @@ -0,0 +1,38 @@ +################### DEFINE KEYS ################### +# The keys can not contain spaces or start with `-` +declare -A KEY_DESCRIPTIONS +KEY_DESCRIPTIONS=( + ["machine"]="Specify the machine name" +) +################################################### + +#################### UTILITIES #################### + +# List of valid keys +VALID_KEYS=("${!KEY_DESCRIPTIONS[@]}") + +# For padding keys with trailing spaces to format output +MAX_KEY_LENGTH=0 +for key in "${VALID_KEYS[@]}"; do + if [ ${#key} -gt $MAX_KEY_LENGTH ]; then + MAX_KEY_LENGTH=${#key} + fi +done + +# Print keys in a formatted way +print_key() { + # $1 : the key name + # $2 : the key value or additional message + # $3 : indent number (optional, default 0) + printf "%${3}s" "" + printf "%-${MAX_KEY_LENGTH}s %s\n" "$1" "$2" +} + +show_valid_keys() { + echo "Valid keys and their functionalities:" + for key in "${!KEY_DESCRIPTIONS[@]}"; do + print_key "$key" "${KEY_DESCRIPTIONS[$key]}" 2 + done +} + +################################################### From 3c413b56c130dc734711c1ae6867bd176aff427d Mon Sep 17 00:00:00 2001 From: Yuan-Ming Hsu <48866415+technic960183@users.noreply.github.com> Date: Thu, 17 Jul 2025 00:18:08 -0700 Subject: [PATCH 2/3] Add script to retrieve settings with only one key --- tool/config/get_settings.sh | 105 ++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100755 tool/config/get_settings.sh diff --git a/tool/config/get_settings.sh b/tool/config/get_settings.sh new file mode 100755 index 0000000000..798773beba --- /dev/null +++ b/tool/config/get_settings.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +#################### UTILITIES #################### + +cd "$(dirname "$0")" +source ./settings.sh +# Variables imported from settings.sh: +# KEY_DESCRIPTIONS +# VALID_KEYS +# MAX_KEY_LENGTH + +# Functions imported from settings.sh: +# print_key() +# show_valid_keys() + +show_help() { + echo "Usage:" + echo " $0 [--local | --global] " + echo " $0 (-h | --help)" + echo "" + echo "Options:" + echo " --local Use local settings" + echo " --global Use global settings" + echo " -h, --help Show this help message" + echo "" + show_valid_keys +} + +##################### PARSER ###################### + +LOCAL=false +GLOBAL=false +KEY="" + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --local) + LOCAL=true + shift ;; + --global) + GLOBAL=true + shift ;; + -h|--help) + show_help + exit 0 ;; + -*) + echo "Error: Unknown option '$1'" >&2 + show_help + exit 1 ;; + *) + if [[ -n "$KEY" ]]; then + echo "Error: Only one key can be specified." >&2 + exit 1 + fi + KEY="$1" + shift ;; + esac +done + +#################### VALIDATION #################### + +if [[ -z "$KEY" ]]; then + echo "Error: You must specify a key to retrieve." >&2 + show_help + exit 1 +fi + +if [[ ! " ${VALID_KEYS[@]} " =~ " $KEY " ]]; then + echo "Error: Invalid key '$KEY'." >&2 + show_valid_keys + exit 1 +fi + +################### GET SETTINGS ################### + +# Helper to extract a setting from output +extract_value() { + local key="$1" + grep -E "^$key[[:space:]]+" | awk '{print $2}' +} + +FOUND=false + +if [ "$LOCAL" = true ] || [ "$GLOBAL" = false ]; then + local_output=$(sh ./set_settings.sh --local --list) + value=$(echo "$local_output" | extract_value "$KEY") + if [[ -n "$value" ]]; then + echo "$value" + FOUND=true + fi +fi + +if [ "$FOUND" = false ] && ([ "$GLOBAL" = true ] || [ "$LOCAL" = false ]); then + global_output=$(sh ./set_settings.sh --global --list) + value=$(echo "$global_output" | extract_value "$KEY") + if [[ -n "$value" ]]; then + echo "$value" + FOUND=true + fi +fi + +if [ "$FOUND" = false ]; then + echo "Key '$KEY' is not set in the requested scope(s)." >&2 + exit 1 +fi From 28bfd643fe008007b309b7143f4f0d9e5202e58b Mon Sep 17 00:00:00 2001 From: Yuan-Ming Hsu <48866415+technic960183@users.noreply.github.com> Date: Thu, 17 Jul 2025 02:29:45 -0700 Subject: [PATCH 3/3] Add `get_setting()` to replace `SystemSetting` The logic of `SystemSetting` is moved to the script `get_settings.sh`. And `get_setting()` is added to call this script and return the result. --- src/configure.py | 101 ++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) diff --git a/src/configure.py b/src/configure.py index 4a8a8e215e..12415f4e17 100755 --- a/src/configure.py +++ b/src/configure.py @@ -15,6 +15,7 @@ import sys import re import ctypes +import subprocess @@ -22,8 +23,8 @@ # Validation #################################################################################################### # Check the Python version -if sys.version_info[0] < 3 or sys.version_info[1] < 5: - raise BaseException("Python 3.5 or later is required.") +if sys.version_info[0] < 3 or sys.version_info[1] < 7: + raise BaseException("Python 3.7 or later is required.") @@ -38,8 +39,6 @@ GAMER_CONFIG_DIR = os.path.join("..", "configs") GAMER_MAKE_BASE = "Makefile_base" GAMER_MAKE_OUT = "Makefile" -GAMER_LOCAL_SETTING = ".local_settings" -GAMER_GLOBAL_SETTING = os.path.expanduser("~/.config/gamer/global_settings") GAMER_DESCRIPTION = "Prepare a customized Makefile for GAMER.\n"\ "Default values are marked by '*'.\n"\ "Use -lh to show a detailed help message.\n" @@ -240,48 +239,6 @@ def print_autocomplete( self, target_option, *args, **kwargs ): return -class SystemSetting( dict ): - """ - Store the system settings from the default setting file. - - Format of the setting file: - 1. Comment starts with `#`. - 2. The line begins with the variable name, followed by one or multiple spaces, and then the value. - 3. Only the fisrt value of the line will be loaded. - 4. If a variable is defined multiple times, only the last occurrence will be used. - """ - def __init__( self, *args, **kwargs ): - super().__init__( *args, **kwargs ) - - def get_default( self, key, default_val ): - return self.get( key, default_val ) - - def load( self, pathname ): - """ - Load the system settings from the default setting file. If a setting exists, - it will be overwritten. Return `False` if the file does not exist. - - Parameters: - pathname : str - The path of the default setting file to be loaded. - - Returns: - bool - Whether the file exists. - """ - if not os.path.isfile(pathname): - return False - with open( pathname, "r" ) as f: - lines = f.readlines() - for line in lines: - tokens = line.strip().split() - if len(tokens) == 0: continue # empty line - if tokens[0][0] == "#": continue # skip comment line - if len(tokens) >= 2: - self[tokens[0]] = tokens[1] - else: # key without value - self[tokens[0]] = None - - return True - #################################################################################################### @@ -387,6 +344,23 @@ def cuda_check_error( result ): compute_capability = cc_major.value*100 + cc_minor.value*10 return compute_capability +def get_setting( key, default_val=None ): + """ + Get the default setting from get_settings.sh. + key : The key to retrieve. + default_val : The value to return if the key is not set. + """ + GET_SCRIPT_PATH = os.path.join("..", "tool", "config", "get_settings.sh") + if not os.path.isfile(GET_SCRIPT_PATH): + raise FileNotFoundError(f"{GET_SCRIPT_PATH} does not exist. Path is relative to {os.getcwd()}") + + result = subprocess.run(["sh", GET_SCRIPT_PATH, key], stdout=subprocess.PIPE, text=True) + if result.returncode == 0: + output = result.stdout.removesuffix("\n") + return output + + return default_val + def string_align( string, indent_str, width, end_char ): """ end_char : The ending character of a word. @@ -415,7 +389,7 @@ def string_align( string, indent_str, width, end_char ): if string[i] == end_char: new_line = True return new_str -def load_arguments( sys_setting : SystemSetting ): +def load_arguments(): parser = ArgumentParser( description = GAMER_DESCRIPTION, formatter_class = argparse.RawTextHelpFormatter, epilog = GAMER_EPILOG, @@ -443,7 +417,7 @@ def load_arguments( sys_setting : SystemSetting ): # machine config setup parser.add_argument( "--machine", type=str, metavar="MACHINE", - default=sys_setting.get_default( "machine", "eureka_intel" ), + default=get_setting( "machine", "eureka_intel" ), help="Select the *.config file from the ../configs directory. "\ "This will overwrite the default machine specified in the default setting file.\n"\ "Choice: [eureka_intel, spock_intel, ...] => " @@ -1132,48 +1106,43 @@ def warning( paths, **kwargs ): # 1. Get the execution command command = " ".join( ["# This makefile is generated by the following command:", "\n#", sys.executable] + sys.argv + ["\n"] ) - # 2. Load system settings - sys_setting = SystemSetting() - sys_setting.load(GAMER_GLOBAL_SETTING) - sys_setting.load(GAMER_LOCAL_SETTING) - - # 3. Load the input arguments - args, name_table, depends, constraints, prefix_table, suffix_table = load_arguments( sys_setting ) + # 2. Load the input arguments + args, name_table, depends, constraints, prefix_table, suffix_table = load_arguments() - # 4. Set the logger + # 3. Set the logger logging.basicConfig( filename=GAMER_MAKE_OUT+'.log', filemode='w', level=logging.INFO, format=LOG_FORMAT ) ch = logging.StreamHandler() ch.setFormatter( CustomFormatter() ) LOGGER.addHandler( ch ) LOGGER.info( " ".join( [sys.executable] + sys.argv ) ) - # 5. Prepare the makefile args - # 5.1 Load the machine setup + # 4. Prepare the makefile args + # 4.1 Load the machine setup paths, compilers, flags, gpus = load_config( os.path.join(GAMER_CONFIG_DIR, args["machine"]+".config") ) - # 5.2 Validate arguments + # 4.2 Validate arguments validation( paths, depends, constraints, **args ) warning( paths, **args ) - # 5.3 Add the SIMU_OPTION + # 4.3 Add the SIMU_OPTION LOGGER.info("========================================") LOGGER.info("GAMER has the following setting.") LOGGER.info("----------------------------------------") sims = set_sims( name_table, prefix_table, suffix_table, depends, **args ) - # 5.4 Set the compiler + # 4.4 Set the compiler compiles = set_compile( paths, compilers, flags, args ) - # 5.5 Set the GPU + # 4.5 Set the GPU gpu_setup = set_gpu( gpus, flags, args ) - # 6. Create Makefile - # 6.1 Read + # 5. Create Makefile + # 5.1 Read with open( GAMER_MAKE_BASE, "r" ) as make_base: makefile = make_base.read() - # 6.2 Replace + # 5.2 Replace verbose_mode = "1" if args["verbose_make"] else "0" makefile, num = re.subn(r"@@@COMPILE_VERBOSE@@@", verbose_mode, makefile) if num == 0: raise BaseException("The string @@@COMPILE_VERBOSE@@@ is not replaced correctly.") @@ -1206,7 +1175,7 @@ def warning( paths, **kwargs ): if num == 0: raise BaseException("The string @@@%s@@@ is not replaced correctly."%key) LOGGER.warning("@@@%s@@@ is replaced to '' since the value is not given or the related option is disabled."%key) - # 6.3 Write + # 5.3 Write with open( GAMER_MAKE_OUT, "w") as make_out: make_out.write( command + makefile )