Skip to content

Commit ab72aad

Browse files
committed
Use shlex for compiler flags
1 parent 5f8cec5 commit ab72aad

File tree

2 files changed

+90
-99
lines changed

2 files changed

+90
-99
lines changed

src/fpm_compiler.F90

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@ module fpm_compiler
3939
OS_UNKNOWN
4040
use fpm_filesystem, only: join_path, basename, get_temp_filename, delete_file, unix_path, &
4141
& 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
4344
use fpm_manifest, only : package_config_t
4445
use fpm_error, only: error_t, fatal_error
4546
use fpm_toml, only: serializable_t, toml_table, set_string, set_value, toml_stat, get_value
47+
use shlex_module, only: shlex_split => split
4648
implicit none
4749
public :: compiler_t, new_compiler, archiver_t, new_archiver, get_macros
50+
public :: append_clean_flags, append_clean_flags_array
4851
public :: debug
4952

5053
enum, bind(C)
@@ -1071,17 +1074,17 @@ subroutine new_archiver(self, ar, echo, verbose)
10711074
! Attempt "ar"
10721075
call execute_command_line("ar --version > "//get_temp_filename()//" 2>&1", &
10731076
& exitstat=estat)
1074-
1075-
if (estat == 0) then
1076-
1077+
1078+
if (estat == 0) then
1079+
10771080
self%ar = "ar"//arflags
1078-
1081+
10791082
else
1080-
1083+
10811084
! Then "gcc-ar"
10821085
call execute_command_line("gcc-ar --version > "//get_temp_filename()//" 2>&1", &
1083-
& exitstat=estat)
1084-
1086+
& exitstat=estat)
1087+
10851088
if (estat /= 0) then
10861089
self%ar = "lib"//libflags
10871090
else
@@ -1440,38 +1443,38 @@ end function compiler_name
14401443
logical function check_fortran_source_runs(self, input) result(success)
14411444
!> Instance of the compiler object
14421445
class(compiler_t), intent(in) :: self
1443-
!> Program Source
1446+
!> Program Source
14441447
character(len=*), intent(in) :: input
1445-
1448+
14461449
integer :: stat,unit
14471450
character(:), allocatable :: source,object,logf,exe
1448-
1451+
14491452
success = .false.
1450-
1453+
14511454
!> Create temporary source file
14521455
exe = get_temp_filename()
14531456
source = exe//'.f90'
14541457
object = exe//'.o'
14551458
logf = exe//'.log'
14561459
open(newunit=unit, file=source, action='readwrite', iostat=stat)
14571460
if (stat/=0) return
1458-
1461+
14591462
!> Write contents
14601463
write(unit,*) input
1461-
close(unit)
1462-
1463-
!> Compile and link program
1464+
close(unit)
1465+
1466+
!> Compile and link program
14641467
call self%compile_fortran(source, object, self%get_default_flags(release=.false.), logf, stat)
14651468
if (stat==0) &
14661469
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
14691472
if (stat==0) &
14701473
call run(exe,echo=.false., exitstat=stat, verbose=.false., redirect=logf)
1471-
1474+
14721475
!> Successful exit on 0 exit code
14731476
success = stat==0
1474-
1477+
14751478
!> Delete files
14761479
open(newunit=unit, file=source, action='readwrite', iostat=stat)
14771480
close(unit,status='delete')
@@ -1481,23 +1484,76 @@ logical function check_fortran_source_runs(self, input) result(success)
14811484
close(unit,status='delete')
14821485
open(newunit=unit, file=exe, action='readwrite', iostat=stat)
14831486
close(unit,status='delete')
1484-
1487+
14851488
end function check_fortran_source_runs
14861489

1487-
!> Check if the current compiler supports 128-bit real precision
1490+
!> Check if the current compiler supports 128-bit real precision
14881491
logical function with_qp(self)
14891492
!> Instance of the compiler object
14901493
class(compiler_t), intent(in) :: self
14911494
with_qp = self%check_fortran_source_runs &
14921495
('if (selected_real_kind(33) == -1) stop 1; end')
14931496
end function with_qp
14941497

1495-
!> Check if the current compiler supports 80-bit "extended" real precision
1498+
!> Check if the current compiler supports 80-bit "extended" real precision
14961499
logical function with_xdp(self)
14971500
!> Instance of the compiler object
14981501
class(compiler_t), intent(in) :: self
14991502
with_xdp = self%check_fortran_source_runs &
15001503
('if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end')
15011504
end function with_xdp
15021505

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+
1552+
flags_char_array = shlex_split(flags)
1553+
allocate(flags_array(size(flags_char_array)))
1554+
do i = 1, size(flags_char_array)
1555+
flags_array(i)%s = trim(adjustl(flags_char_array(i)))
1556+
end do
1557+
end subroutine tokenize_flags
1558+
15031559
end module fpm_compiler

src/metapackage/fpm_meta_base.f90

Lines changed: 11 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module fpm_meta_base
66
use fpm_manifest_dependency, only: dependency_config_t
77
use fpm_manifest, only: package_config_t
88
use fpm_strings, only: string_t, len_trim, split, join
9+
use fpm_compiler, only: append_clean_flags, append_clean_flags_array
910

1011
implicit none
1112

@@ -111,30 +112,30 @@ subroutine resolve_model(self,model,error)
111112

112113
! Add global build flags, to apply to all sources
113114
if (self%has_build_flags) then
114-
call append_flags_without_duplicates(model%fortran_compile_flags, self%flags%s)
115-
call append_flags_without_duplicates(model%c_compile_flags, self%flags%s)
116-
call append_flags_without_duplicates(model%cxx_compile_flags, self%flags%s)
115+
call append_clean_flags(model%fortran_compile_flags, self%flags%s)
116+
call append_clean_flags(model%c_compile_flags, self%flags%s)
117+
call append_clean_flags(model%cxx_compile_flags, self%flags%s)
117118
endif
118119

119120
! Add language-specific flags
120-
if (self%has_fortran_flags) call append_flags_without_duplicates(model%fortran_compile_flags, self%fflags%s)
121-
if (self%has_c_flags) call append_flags_without_duplicates(model%c_compile_flags, self%cflags%s)
122-
if (self%has_cxx_flags) call append_flags_without_duplicates(model%cxx_compile_flags, self%cxxflags%s)
121+
if (self%has_fortran_flags) call append_clean_flags(model%fortran_compile_flags, self%fflags%s)
122+
if (self%has_c_flags) call append_clean_flags(model%c_compile_flags, self%cflags%s)
123+
if (self%has_cxx_flags) call append_clean_flags(model%cxx_compile_flags, self%cxxflags%s)
123124

124125
if (self%has_link_flags) then
125-
call append_flags_without_duplicates(model%link_flags, self%link_flags%s)
126+
call append_clean_flags(model%link_flags, self%link_flags%s)
126127
end if
127128

128129
if (self%has_link_libraries) then
129-
call append_array_without_duplicates(model%link_libraries, self%link_libs)
130+
call append_clean_flags_array(model%link_libraries, self%link_libs)
130131
end if
131132

132133
if (self%has_include_dirs) then
133-
call append_array_without_duplicates(model%include_dirs, self%incl_dirs)
134+
call append_clean_flags_array(model%include_dirs, self%incl_dirs)
134135
end if
135136

136137
if (self%has_external_modules) then
137-
call append_array_without_duplicates(model%external_modules, self%external_modules)
138+
call append_clean_flags_array(model%external_modules, self%external_modules)
138139
end if
139140

140141
end subroutine resolve_model
@@ -187,70 +188,4 @@ end function dn
187188

188189
end subroutine resolve_package_config
189190

190-
subroutine append_flags_without_duplicates(flags, new_flags)
191-
character(:), intent(inout), allocatable :: flags
192-
character(*), intent(in) :: new_flags
193-
194-
character(len=:), allocatable :: flags_array(:), new_flags_array(:)
195-
type(string_t), allocatable :: flags_str_array(:), new_flags_str_array(:)
196-
integer :: i, max_len
197-
198-
call split(flags, flags_array, " ")
199-
call split(new_flags, new_flags_array, " ")
200-
201-
allocate(flags_str_array(size(flags_array, 1)))
202-
allocate(new_flags_str_array(size(new_flags_array, 1)))
203-
do i = 1, size(flags_array)
204-
flags_str_array(i) = string_t(flags_array(i))
205-
end do
206-
do i = 1, size(new_flags_array)
207-
new_flags_str_array(i) = string_t(new_flags_array(i))
208-
end do
209-
210-
call append_array_without_duplicates(flags_str_array, new_flags_str_array)
211-
212-
max_len = 0
213-
do i = 1, size(flags_str_array)
214-
max_len = max(max_len, len_trim(flags_str_array(i)%s))
215-
end do
216-
deallocate(flags_array)
217-
allocate(character(len=max_len) :: flags_array(size(flags_str_array)))
218-
do i = 1, size(flags_str_array)
219-
flags_array(i) = flags_str_array(i)%s
220-
end do
221-
222-
flags = join(flags_array, " ")
223-
224-
end subroutine append_flags_without_duplicates
225-
226-
subroutine append_array_without_duplicates(str_array, new_elements)
227-
type(string_t), allocatable, intent(inout) :: str_array(:)
228-
type(string_t), intent(in) :: new_elements(:)
229-
integer :: i
230-
231-
do i = 1, size(new_elements)
232-
if (contains_element(str_array, new_elements(i))) cycle
233-
! Filter out empty flags
234-
if (new_elements(i)%s == "") cycle
235-
if (new_elements(i)%s == "-l") cycle
236-
if (new_elements(i)%s == "-L") cycle
237-
if (new_elements(i)%s == "-I") cycle
238-
if (new_elements(i)%s == "-J") cycle
239-
str_array = [str_array, new_elements(i)]
240-
end do
241-
end subroutine append_array_without_duplicates
242-
243-
function contains_element(str_array, element)
244-
logical :: contains_element
245-
type(string_t), intent(in) :: str_array(:), element
246-
integer :: i
247-
248-
contains_element = .false.
249-
do i = 1, size(str_array)
250-
if (str_array(i)%s == element%s) then
251-
contains_element = .true.
252-
exit
253-
end if
254-
end do
255-
end function contains_element
256191
end module fpm_meta_base

0 commit comments

Comments
 (0)