1
1
#! /usr/bin/env bash
2
+ VERSION=" 1.0.0"
3
+
4
+ # Logging
5
+ LOG_LEVEL=" INFO"
6
+
7
+ timestamp () {
8
+ date " +%Y-%m-%d %H:%M:%S"
9
+ }
10
+
11
+ log () {
12
+ # Simple logger function
13
+ declare -A levels=([DEBUG]=0 [INFO]=1 [WARN]=2 [ERROR]=3)
14
+ msg_type=" ${1:- INFO} "
15
+ msg_body=" ${2:- ' null' } "
16
+
17
+ [ ${levels[$msg_type]} ] || log " ERROR" " Unknown log level $msg_type "
18
+
19
+ # ignore messages below log level
20
+ [ ${levels[$msg_type]} -lt ${levels[$LOG_LEVEL]} ] && return 0
21
+ # print log message to standard error
22
+ echo " $( timestamp) [$msg_type ] $msg_body " >&2
23
+ # exit after any error message
24
+ [ $msg_type == " ERROR" ] && exit 1
25
+ }
2
26
3
27
# Supported CPU specifications
4
28
update_arch_specs (){
5
29
# Add contents of given spec file into an array
6
- # 1: array with CPU arch specs
30
+ # 1: name of array with CPU arch specs
7
31
# 2: spec file with the additional specs
8
32
9
33
[ -z " $1 " ] && echo " [ERROR] update_arch_specs: missing array in argument list" >&2 && exit 1
@@ -20,74 +44,100 @@ update_arch_specs(){
20
44
21
45
# CPU specification of host system
22
46
get_cpuinfo (){
23
- cpuinfo_pattern=" ^${1} \s*:"
24
- # grep -i "$cpuinfo_pattern" /proc/cpuinfo | tail -n 1 | sed "s/$cpuinfo_pattern//"
25
- grep -i " $cpuinfo_pattern " ${EESSI_PROC_CPUINFO:-/ proc/ cpuinfo} | tail -n 1 | sed " s/$cpuinfo_pattern //"
47
+ # Return the value from cpuinfo for the matching key
48
+ # 1: string with key pattern
49
+
50
+ [ -z " $1 " ] && log " ERROR" " get_cpuinfo: missing key pattern in argument list"
51
+ cpuinfo_pattern=" ^${1} \s*:\s*"
52
+
53
+ # case insensitive match of key pattern and delete key pattern from result
54
+ grep -i " $cpuinfo_pattern " ${EESSI_PROC_CPUINFO:-/ proc/ cpuinfo} | tail -n 1 | sed " s/$cpuinfo_pattern //i"
26
55
}
27
56
28
- # Find best match
29
- check_flags (){
30
- for flag in " $@ " ; do
31
- [[ " ${CPU_FLAGS[*]} " == * " $flag " * ]] || return 1
57
+ check_allinfirst (){
58
+ # Return true if all given arguments after the first are found in the first one
59
+ # 1: reference string of space separated values
60
+ # 2,3..: each additional argument is a single value to be found in the reference string
61
+
62
+ [ -z " $1 " ] && log " ERROR" " check_allinfirst: missing argument with reference string"
63
+ reference=" $1 "
64
+ shift
65
+
66
+ for candidate in " $@ " ; do
67
+ [[ " $reference " == * " $candidate " * ]] || return 1
32
68
done
33
69
return 0
34
70
}
35
71
36
- ARGUMENT=${1:- none}
37
-
38
72
cpupath (){
39
- # Return the best matching CPU architecture from a list of supported specifications for the host CPU
40
- local CPU_ARCH_SPEC=()
41
-
42
- # Identify the host CPU architecture
43
- local MACHINE_TYPE=${EESSI_MACHINE_TYPE:- $(uname -m)}
44
- echo " [INFO] cpupath: Host CPU architecture identified as $MACHINE_TYPE " >&2
45
-
46
- # Populate list of supported specs for this architecture
47
- case $MACHINE_TYPE in
48
- " x86_64" ) local spec_file=" eessi_arch_x86.spec" ;;
49
- " aarch64" ) local spec_file=" eessi_arch_arm.spec" ;;
50
- " ppc64le" ) local spec_file=" eessi_arch_ppc.spec" ;;
51
- * ) echo " [ERROR] cpupath: Unsupported CPU architecture $MACHINE_TYPE " >&2 && exit 1
52
- esac
53
- # spec files are located in a subfolder with this script
54
- local base_dir=$( dirname $( realpath $0 ) )
55
- update_arch_specs CPU_ARCH_SPEC " $base_dir /arch_specs/${spec_file} "
56
-
57
- # CPU_VENDOR_TAG="vendor_id"
58
- CPU_VENDOR_TAG=" vendor[ _]id"
59
- CPU_VENDOR=$( get_cpuinfo " $CPU_VENDOR_TAG " )
60
- CPU_VENDOR=$( echo ${CPU_VENDOR#*: } | xargs echo -n)
61
- echo " == CPU vendor of host system: $CPU_VENDOR " >&2
62
-
63
- CPU_FLAG_TAG=' flags'
64
- # cpuinfo systems print different line identifiers, eg features, instead of flags
65
- [ " ${CPU_VENDOR} " == " ARM" ] && CPU_FLAG_TAG=' flags'
66
- [ " ${MACHINE_TYPE} " == " aarch64" ] && [ " ${CPU_VENDOR} x" == " x" ] && CPU_FLAG_TAG=' features'
67
- [ " ${MACHINE_TYPE} " == " ppc64le" ] && CPU_FLAG_TAG=' cpu'
68
-
69
- CPU_FLAGS=$( get_cpuinfo " $CPU_FLAG_TAG " )
70
- echo " == CPU flags of host system: $CPU_FLAGS " >&2
71
-
72
- # Default to generic CPU
73
- BEST_MATCH=" generic"
74
-
75
- for arch in " ${CPU_ARCH_SPEC[@]} " ; do
76
- eval " arch_spec=$arch "
77
- if [ " ${CPU_VENDOR} x" == " ${arch_spec[1]} x" ]; then
78
- check_flags ${arch_spec[2]} && BEST_MATCH=${arch_spec[0]}
79
- echo " == got a match with $BEST_MATCH " >&2
80
- fi
81
- done
82
-
83
- echo " Best match is $BEST_MATCH " >&2
84
- echo " $BEST_MATCH "
73
+ # Identify the best matching CPU architecture from a list of supported specifications for the host CPU
74
+ # Return the path to the installation files in EESSI of the best matching architecture
75
+ local cpu_arch_spec=()
76
+
77
+ # Identify the host CPU architecture
78
+ local machine_type=${EESSI_MACHINE_TYPE:- $(uname -m)}
79
+ log " DEBUG" " cpupath: Host CPU architecture identified as '$machine_type '"
80
+
81
+ # Populate list of supported specs for this architecture
82
+ case $machine_type in
83
+ " x86_64" ) local spec_file=" eessi_arch_x86.spec" ;;
84
+ " aarch64" ) local spec_file=" eessi_arch_arm.spec" ;;
85
+ " ppc64le" ) local spec_file=" eessi_arch_ppc.spec" ;;
86
+ * ) log " ERROR" " cpupath: Unsupported CPU architecture $machine_type "
87
+ esac
88
+ # spec files are located in a subfolder with this script
89
+ local base_dir=$( dirname $( realpath $0 ) )
90
+ update_arch_specs cpu_arch_spec " $base_dir /arch_specs/${spec_file} "
91
+
92
+ # Identify the host CPU vendor
93
+ local cpu_vendor_tag=" vendor[ _]id"
94
+ local cpu_vendor=$( get_cpuinfo " $cpu_vendor_tag " )
95
+ log " DEBUG" " cpupath: CPU vendor of host system: '$cpu_vendor '"
96
+
97
+ # Identify the host CPU flags or features
98
+ local cpu_flag_tag=' flags'
99
+ # cpuinfo systems print different line identifiers, eg features, instead of flags
100
+ [ " ${cpu_vendor} " == " ARM" ] && cpu_flag_tag=' flags'
101
+ [ " ${machine_type} " == " aarch64" ] && [ " ${cpu_vendor} x" == " x" ] && cpu_flag_tag=' features'
102
+ [ " ${machine_type} " == " ppc64le" ] && cpu_flag_tag=' cpu'
103
+
104
+ local cpu_flags=$( get_cpuinfo " $cpu_flag_tag " )
105
+ log " DEBUG" " cpupath: CPU flags of host system: '$cpu_flags '"
106
+
107
+ # Default to generic CPU
108
+ local best_arch_match=" generic"
109
+
110
+ # Iterate over the supported CPU specifications to find the best match for host CPU
111
+ # Order of the specifications matters, the last one to match will be selected
112
+ for arch in " ${cpu_arch_spec[@]} " ; do
113
+ eval " arch_spec=$arch "
114
+ if [ " ${cpu_vendor} x" == " ${arch_spec[1]} x" ]; then
115
+ # each flag in this CPU specification must be found in the list of flags of the host
116
+ check_allinfirst " ${cpu_flags[*]} " ${arch_spec[2]} && best_arch_match=${arch_spec[0]} && \
117
+ log " DEBUG" " cpupath: host CPU best match updated to $best_arch_match "
118
+ fi
119
+ done
120
+
121
+ log " INFO" " cpupath: best match for host CPU: $best_arch_match "
122
+ echo " $best_arch_match "
85
123
}
86
124
87
- if [ ${ARGUMENT} == " none" ]; then
88
- echo usage: $0 cpupath
89
- exit
90
- elif [ ${ARGUMENT} == " cpupath" ]; then
91
- cpupath
92
- exit
93
- fi
125
+ # Parse command line arguments
126
+ USAGE=" Usage: eessi_archdetect.sh [-h][-d] <action>"
127
+
128
+ while getopts ' hdv' OPTION; do
129
+ case " $OPTION " in
130
+ h) echo " $USAGE " ; exit 0;;
131
+ d) LOG_LEVEL=" DEBUG" ;;
132
+ v) echo " eessi_archdetect.sh v$VERSION " ; exit 0;;
133
+ ? ) echo " $USAGE " ; exit 1;;
134
+ esac
135
+ done
136
+ shift " $(( $OPTIND - 1 )) "
137
+
138
+ ARGUMENT=${1:- none}
139
+
140
+ case " $ARGUMENT " in
141
+ " cpupath" ) cpupath; exit ;;
142
+ * ) echo " $USAGE " ; log " ERROR" " Missing <action> argument" ;;
143
+ esac
0 commit comments