|
| 1 | +program main |
| 2 | + use iso_fortran_env, only: compiler_options |
| 3 | + implicit none |
| 4 | + |
| 5 | + character(len=:), allocatable :: options_str |
| 6 | + character(len=20) :: detected_compiler |
| 7 | + logical :: debug_active, release_active, verbose_active, fast_active, strict_active |
| 8 | + logical :: all_checks_passed |
| 9 | + integer :: failed_checks |
| 10 | + |
| 11 | + ! Get compiler flags used to build this file |
| 12 | + options_str = compiler_options() |
| 13 | + |
| 14 | + ! Display compiler information |
| 15 | + print '(a)', '=================================' |
| 16 | + print '(a)', 'Features Per Compiler Demo' |
| 17 | + print '(a)', '=================================' |
| 18 | + print '(a)', '' |
| 19 | + |
| 20 | + ! Detect compiler type using the function |
| 21 | + detected_compiler = compiled_with() |
| 22 | + |
| 23 | + print '(2a)', 'Detected compiler: ', detected_compiler |
| 24 | + print '(a)', '' |
| 25 | + print '(2a)', 'Compiler options: ', trim(options_str) |
| 26 | + print '(a)', '' |
| 27 | + |
| 28 | + ! Check for feature flags |
| 29 | + debug_active = index(options_str, '-g') > 0 |
| 30 | + release_active = index(options_str, '-O') > 0 |
| 31 | + verbose_active = index(options_str, ' -v') > 0 .or. index(options_str, ' -v ') > 0 |
| 32 | + fast_active = index(options_str, '-Ofast') > 0 .or. index(options_str, '-fast') > 0 |
| 33 | + strict_active = index(options_str, '-std=f2018') > 0 .or. index(options_str, '-stand f18') > 0 |
| 34 | + |
| 35 | + ! Display active features |
| 36 | + print '(a)', 'Active features detected:' |
| 37 | + if (debug_active) print '(a)', ' ✓ DEBUG: -g flag found' |
| 38 | + if (release_active) print '(a)', ' ✓ RELEASE: -O flags found' |
| 39 | + if (verbose_active) print '(a)', ' ✓ VERBOSE: -v flag found' |
| 40 | + if (fast_active) print '(a)', ' ✓ FAST: fast optimization flags found' |
| 41 | + if (strict_active) print '(a)', ' ✓ STRICT: standard compliance flags found' |
| 42 | + |
| 43 | + print '(a)', '' |
| 44 | + |
| 45 | + ! Check compiler-specific flags and validate |
| 46 | + failed_checks = check_compiler_flags(detected_compiler, options_str, debug_active, release_active, fast_active, strict_active) |
| 47 | + |
| 48 | + print '(a)', '' |
| 49 | + |
| 50 | + ! Determine overall result |
| 51 | + all_checks_passed = (failed_checks == 0) |
| 52 | + |
| 53 | + if (all_checks_passed) then |
| 54 | + print '(a)', '✓ All compiler flag checks PASSED' |
| 55 | + print '(a)', '' |
| 56 | + else |
| 57 | + print '(a,i0,a)', '✗ ', failed_checks, ' compiler flag checks FAILED' |
| 58 | + print '(a)', '' |
| 59 | + end if |
| 60 | + |
| 61 | + ! Exit with appropriate code |
| 62 | + stop merge(0,1,all_checks_passed) |
| 63 | + |
| 64 | +contains |
| 65 | + |
| 66 | + function check_compiler_flags(compiler, options, debug_on, release_on, fast_on, strict_on) result(failed_count) |
| 67 | + character(len=*), intent(in) :: compiler, options |
| 68 | + logical, intent(in) :: debug_on, release_on, fast_on, strict_on |
| 69 | + integer :: failed_count |
| 70 | + |
| 71 | + failed_count = 0 |
| 72 | + select case (compiler) |
| 73 | + case ('gfortran') |
| 74 | + failed_count = check_gfortran_flags(options, debug_on, release_on, fast_on, strict_on) |
| 75 | + case ('ifort') |
| 76 | + failed_count = check_ifort_flags(options, debug_on, release_on, fast_on, strict_on) |
| 77 | + case ('ifx') |
| 78 | + failed_count = check_ifx_flags(options, debug_on, release_on, fast_on, strict_on) |
| 79 | + case default |
| 80 | + print '(a)', 'Compiler-specific checks: Unknown compiler - only base flags checked' |
| 81 | + end select |
| 82 | + end function |
| 83 | + |
| 84 | + function check_flag(options, flag_name, feature_name, description) result(found) |
| 85 | + character(len=*), intent(in) :: options, flag_name, feature_name, description |
| 86 | + logical :: found |
| 87 | + |
| 88 | + found = index(options, flag_name) > 0 |
| 89 | + if (found) then |
| 90 | + print '(a,a,a,a,a)', ' ✓ ', feature_name, ': ', description, ' found' |
| 91 | + else |
| 92 | + print '(a,a,a,a,a)', ' ✗ ', feature_name, ': ', description, ' NOT found' |
| 93 | + end if |
| 94 | + end function |
| 95 | + |
| 96 | + function compiled_with() result(msg) |
| 97 | + use iso_fortran_env, only: compiler_version |
| 98 | + character(len=:), allocatable :: msg |
| 99 | + character(len=:), allocatable :: version_str |
| 100 | + |
| 101 | + version_str = compiler_version() |
| 102 | + |
| 103 | + if (index(version_str, 'GCC') > 0) then |
| 104 | + msg = 'gfortran' |
| 105 | + else if (index(version_str, 'Classic') > 0) then |
| 106 | + msg = 'ifort' |
| 107 | + else if (index(version_str, 'Intel') > 0) then |
| 108 | + msg = 'ifx' |
| 109 | + else |
| 110 | + msg = 'any' |
| 111 | + end if |
| 112 | + end function |
| 113 | + |
| 114 | + function check_gfortran_flags(options, debug_on, release_on, fast_on, strict_on) result(failed_count) |
| 115 | + character(len=*), intent(in) :: options |
| 116 | + logical, intent(in) :: debug_on, release_on, fast_on, strict_on |
| 117 | + integer :: failed_count |
| 118 | + |
| 119 | + failed_count = 0 |
| 120 | + print '(a)', 'Compiler-specific flag checks (gfortran):' |
| 121 | + |
| 122 | + if (debug_on) then |
| 123 | + if (.not. check_flag(options, '-Wall', 'Debug', '-Wall')) failed_count = failed_count + 1 |
| 124 | + if (.not. check_flag(options, '-Wextra', 'Debug', '-Wextra')) failed_count = failed_count + 1 |
| 125 | + if (.not. check_flag(options, '-fcheck=bounds', 'Debug', '-fcheck=bounds')) failed_count = failed_count + 1 |
| 126 | + if (.not. check_flag(options, '-fbacktrace', 'Debug', '-fbacktrace')) failed_count = failed_count + 1 |
| 127 | + end if |
| 128 | + |
| 129 | + if (release_on) then |
| 130 | + ! Check for either -march=native or -mcpu (Apple Silicon uses -mcpu) |
| 131 | + if (.not. (index(options, '-march=native') > 0 .or. index(options, '-mcpu') > 0)) then |
| 132 | + print '(a)', ' ✗ Release: neither -march=native nor -mcpu found' |
| 133 | + failed_count = failed_count + 1 |
| 134 | + else |
| 135 | + if (index(options, '-march=native') > 0) then |
| 136 | + print '(a)', ' ✓ Release: -march=native found' |
| 137 | + else |
| 138 | + print '(a)', ' ✓ Release: -mcpu found' |
| 139 | + end if |
| 140 | + end if |
| 141 | + if (.not. check_flag(options, '-funroll-loops', 'Release', '-funroll-loops')) failed_count = failed_count + 1 |
| 142 | + end if |
| 143 | + |
| 144 | + if (fast_on) then |
| 145 | + if (.not. check_flag(options, '-Ofast', 'Fast', '-Ofast')) failed_count = failed_count + 1 |
| 146 | + if (.not. check_flag(options, '-ffast-math', 'Fast', '-ffast-math')) failed_count = failed_count + 1 |
| 147 | + end if |
| 148 | + |
| 149 | + if (strict_on) then |
| 150 | + if (.not. check_flag(options, '-Wpedantic', 'Strict', '-Wpedantic')) failed_count = failed_count + 1 |
| 151 | + if (.not. check_flag(options, '-Werror', 'Strict', '-Werror')) failed_count = failed_count + 1 |
| 152 | + end if |
| 153 | + end function |
| 154 | + |
| 155 | + function check_ifort_flags(options, debug_on, release_on, fast_on, strict_on) result(failed_count) |
| 156 | + character(len=*), intent(in) :: options |
| 157 | + logical, intent(in) :: debug_on, release_on, fast_on, strict_on |
| 158 | + integer :: failed_count |
| 159 | + |
| 160 | + failed_count = 0 |
| 161 | + print '(a)', 'Compiler-specific flag checks (ifort):' |
| 162 | + |
| 163 | + if (debug_on) then |
| 164 | + if (.not. check_flag(options, '-warn all', 'Debug', '-warn all')) failed_count = failed_count + 1 |
| 165 | + if (.not. check_flag(options, '-check bounds', 'Debug', '-check bounds')) failed_count = failed_count + 1 |
| 166 | + if (.not. check_flag(options, '-traceback', 'Debug', '-traceback')) failed_count = failed_count + 1 |
| 167 | + end if |
| 168 | + |
| 169 | + if (release_on) then |
| 170 | + if (.not. check_flag(options, '-xHost', 'Release', '-xHost')) failed_count = failed_count + 1 |
| 171 | + if (.not. check_flag(options, '-unroll', 'Release', '-unroll')) failed_count = failed_count + 1 |
| 172 | + end if |
| 173 | + |
| 174 | + if (fast_on) then |
| 175 | + if (.not. check_flag(options, '-fast', 'Fast', '-fast')) failed_count = failed_count + 1 |
| 176 | + end if |
| 177 | + |
| 178 | + if (strict_on) then |
| 179 | + if (.not. check_flag(options, '-stand f18', 'Strict', '-stand f18')) failed_count = failed_count + 1 |
| 180 | + if (.not. check_flag(options, '-warn errors', 'Strict', '-warn errors')) failed_count = failed_count + 1 |
| 181 | + end if |
| 182 | + end function |
| 183 | + |
| 184 | + function check_ifx_flags(options, debug_on, release_on, fast_on, strict_on) result(failed_count) |
| 185 | + character(len=*), intent(in) :: options |
| 186 | + logical, intent(in) :: debug_on, release_on, fast_on, strict_on |
| 187 | + integer :: failed_count |
| 188 | + |
| 189 | + failed_count = 0 |
| 190 | + print '(a)', 'Compiler-specific flag checks (ifx):' |
| 191 | + |
| 192 | + if (debug_on) then |
| 193 | + if (.not. check_flag(options, '-warn all', 'Debug', '-warn all')) failed_count = failed_count + 1 |
| 194 | + if (.not. check_flag(options, '-check bounds', 'Debug', '-check bounds')) failed_count = failed_count + 1 |
| 195 | + if (.not. check_flag(options, '-traceback', 'Debug', '-traceback')) failed_count = failed_count + 1 |
| 196 | + end if |
| 197 | + |
| 198 | + if (release_on) then |
| 199 | + if (.not. check_flag(options, '-xHost', 'Release', '-xHost')) failed_count = failed_count + 1 |
| 200 | + if (.not. check_flag(options, '-unroll', 'Release', '-unroll')) failed_count = failed_count + 1 |
| 201 | + end if |
| 202 | + |
| 203 | + if (fast_on) then |
| 204 | + if (.not. check_flag(options, '-fast', 'Fast', '-fast')) failed_count = failed_count + 1 |
| 205 | + end if |
| 206 | + |
| 207 | + if (strict_on) then |
| 208 | + if (.not. check_flag(options, '-stand f18', 'Strict', '-stand f18')) failed_count = failed_count + 1 |
| 209 | + if (.not. check_flag(options, '-warn errors', 'Strict', '-warn errors')) failed_count = failed_count + 1 |
| 210 | + end if |
| 211 | + end function |
| 212 | + |
| 213 | +end program main |
0 commit comments