@@ -39,12 +39,15 @@ module fpm_compiler
39
39
OS_UNKNOWN
40
40
use fpm_filesystem, only: join_path, basename, get_temp_filename, delete_file, unix_path, &
41
41
& getline, run
42
- use fpm_strings, only: split, string_cat, string_t, str_ends_with, str_begins_with_str
42
+ use fpm_strings, only: split, string_cat, string_t, str_ends_with, str_begins_with_str, &
43
+ & string_array_contains
43
44
use fpm_manifest, only : package_config_t
44
45
use fpm_error, only: error_t, fatal_error
45
46
use fpm_toml, only: serializable_t, toml_table, set_string, set_value, toml_stat, get_value
47
+ use shlex_module, only: shlex_split = > split
46
48
implicit none
47
49
public :: compiler_t, new_compiler, archiver_t, new_archiver, get_macros
50
+ public :: append_clean_flags, append_clean_flags_array
48
51
public :: debug
49
52
50
53
enum, bind(C)
@@ -1071,17 +1074,17 @@ subroutine new_archiver(self, ar, echo, verbose)
1071
1074
! Attempt "ar"
1072
1075
call execute_command_line(" ar --version > " // get_temp_filename()// " 2>&1" , &
1073
1076
& exitstat= estat)
1074
-
1075
- if (estat == 0 ) then
1076
-
1077
+
1078
+ if (estat == 0 ) then
1079
+
1077
1080
self% ar = " ar" // arflags
1078
-
1081
+
1079
1082
else
1080
-
1083
+
1081
1084
! Then "gcc-ar"
1082
1085
call execute_command_line(" gcc-ar --version > " // get_temp_filename()// " 2>&1" , &
1083
- & exitstat= estat)
1084
-
1086
+ & exitstat= estat)
1087
+
1085
1088
if (estat /= 0 ) then
1086
1089
self% ar = " lib" // libflags
1087
1090
else
@@ -1440,38 +1443,38 @@ end function compiler_name
1440
1443
logical function check_fortran_source_runs (self , input ) result(success)
1441
1444
! > Instance of the compiler object
1442
1445
class(compiler_t), intent (in ) :: self
1443
- ! > Program Source
1446
+ ! > Program Source
1444
1447
character (len=* ), intent (in ) :: input
1445
-
1448
+
1446
1449
integer :: stat,unit
1447
1450
character (:), allocatable :: source,object,logf,exe
1448
-
1451
+
1449
1452
success = .false.
1450
-
1453
+
1451
1454
! > Create temporary source file
1452
1455
exe = get_temp_filename()
1453
1456
source = exe// ' .f90'
1454
1457
object = exe// ' .o'
1455
1458
logf = exe// ' .log'
1456
1459
open (newunit= unit, file= source, action= ' readwrite' , iostat= stat)
1457
1460
if (stat/= 0 ) return
1458
-
1461
+
1459
1462
! > Write contents
1460
1463
write (unit,* ) input
1461
- close (unit)
1462
-
1463
- ! > Compile and link program
1464
+ close (unit)
1465
+
1466
+ ! > Compile and link program
1464
1467
call self% compile_fortran(source, object, self% get_default_flags(release= .false. ), logf, stat)
1465
1468
if (stat== 0 ) &
1466
1469
call self% link(exe, self% get_default_flags(release= .false. )// " " // object, logf, stat)
1467
-
1468
- ! > Run and retrieve exit code
1470
+
1471
+ ! > Run and retrieve exit code
1469
1472
if (stat== 0 ) &
1470
1473
call run(exe,echo= .false. , exitstat= stat, verbose= .false. , redirect= logf)
1471
-
1474
+
1472
1475
! > Successful exit on 0 exit code
1473
1476
success = stat== 0
1474
-
1477
+
1475
1478
! > Delete files
1476
1479
open (newunit= unit, file= source, action= ' readwrite' , iostat= stat)
1477
1480
close (unit,status= ' delete' )
@@ -1481,23 +1484,81 @@ logical function check_fortran_source_runs(self, input) result(success)
1481
1484
close (unit,status= ' delete' )
1482
1485
open (newunit= unit, file= exe, action= ' readwrite' , iostat= stat)
1483
1486
close (unit,status= ' delete' )
1484
-
1487
+
1485
1488
end function check_fortran_source_runs
1486
1489
1487
- ! > Check if the current compiler supports 128-bit real precision
1490
+ ! > Check if the current compiler supports 128-bit real precision
1488
1491
logical function with_qp (self )
1489
1492
! > Instance of the compiler object
1490
1493
class(compiler_t), intent (in ) :: self
1491
1494
with_qp = self% check_fortran_source_runs &
1492
1495
(' if (selected_real_kind(33) == -1) stop 1; end' )
1493
1496
end function with_qp
1494
1497
1495
- ! > Check if the current compiler supports 80-bit "extended" real precision
1498
+ ! > Check if the current compiler supports 80-bit "extended" real precision
1496
1499
logical function with_xdp (self )
1497
1500
! > Instance of the compiler object
1498
1501
class(compiler_t), intent (in ) :: self
1499
1502
with_xdp = self% check_fortran_source_runs &
1500
1503
(' if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end' )
1501
1504
end function with_xdp
1502
1505
1506
+ ! > Append new flags to existing flags, removing duplicates and empty flags (string version)
1507
+ subroutine append_clean_flags (flags , new_flags )
1508
+ character (:), intent (inout ), allocatable :: flags
1509
+ character (* ), intent (in ) :: new_flags
1510
+
1511
+ type (string_t), allocatable :: flags_array(:), new_flags_array(:)
1512
+ integer :: i
1513
+
1514
+ call tokenize_flags(flags, flags_array)
1515
+ call tokenize_flags(new_flags, new_flags_array)
1516
+
1517
+ call append_clean_flags_array(flags_array, new_flags_array)
1518
+
1519
+ do i = 1 , size (flags_array)
1520
+ flags = flags // " " // flags_array(i)% s
1521
+ end do
1522
+ end subroutine append_clean_flags
1523
+
1524
+ ! > Append new flags to existing flags, removing duplicates and empty flags (array version)
1525
+ subroutine append_clean_flags_array (flags_array , new_flags_array )
1526
+ type (string_t), allocatable , intent (inout ) :: flags_array(:)
1527
+ type (string_t), intent (in ) :: new_flags_array(:)
1528
+
1529
+ integer :: i
1530
+
1531
+ do i = 1 , size (new_flags_array)
1532
+ if (string_array_contains(new_flags_array(i)% s, flags_array)) cycle
1533
+ ! Filter out empty flags and arguments
1534
+ if (new_flags_array(i)% s == " " ) cycle
1535
+ if (trim (new_flags_array(i)% s) == " -l" ) cycle
1536
+ if (trim (new_flags_array(i)% s) == " -L" ) cycle
1537
+ if (trim (new_flags_array(i)% s) == " -I" ) cycle
1538
+ if (trim (new_flags_array(i)% s) == " -J" ) cycle
1539
+ if (trim (new_flags_array(i)% s) == " -M" ) cycle
1540
+ flags_array = [flags_array, new_flags_array(i)]
1541
+ end do
1542
+ end subroutine append_clean_flags_array
1543
+
1544
+ ! > Tokenize a string into an array of compiler flags
1545
+ subroutine tokenize_flags (flags , flags_array )
1546
+ character (* ), intent (in ) :: flags
1547
+ type (string_t), allocatable , intent (out ) :: flags_array(:)
1548
+ character (len= :), allocatable :: flags_char_array(:)
1549
+
1550
+ integer :: i
1551
+ logical :: success
1552
+
1553
+ flags_char_array = shlex_split(flags, join_spaced= .true. , keep_quotes= .true. , success= success)
1554
+ if (.not. success) then
1555
+ allocate (flags_array(0 ))
1556
+ return
1557
+ end if
1558
+ allocate (flags_array(size (flags_char_array)))
1559
+ do i = 1 , size (flags_char_array)
1560
+ flags_array(i)% s = trim (adjustl (flags_char_array(i)))
1561
+ end do
1562
+ end subroutine tokenize_flags
1563
+
1503
1564
end module fpm_compiler
0 commit comments