Skip to content

Commit 5422ec5

Browse files
authored
Merge pull request #412 from kubajj/Duplicate_module_definitions
Fix for Issue #396 - Duplicate module definitions
2 parents a4e8d22 + e0d336c commit 5422ec5

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

Diff for: fpm/src/fpm.f90

+52-1
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ module fpm
2323
& stdout=>output_unit, &
2424
& stderr=>error_unit
2525
use fpm_manifest_dependency, only: dependency_config_t
26+
use, intrinsic :: iso_fortran_env, only: error_unit
2627
implicit none
2728
private
2829
public :: cmd_build, cmd_run
29-
public :: build_model
30+
public :: build_model, check_modules_for_duplicates
3031

3132
contains
3233

@@ -42,6 +43,8 @@ subroutine build_model(model, settings, package, error)
4243
integer :: i, j
4344
type(package_config_t) :: dependency
4445
character(len=:), allocatable :: manifest, lib_dir
46+
47+
logical :: duplicates_found = .false.
4548
type(string_t) :: include_dir
4649

4750
model%package_name = package%name
@@ -179,8 +182,56 @@ subroutine build_model(model, settings, package, error)
179182
write(*,*)'<INFO> INCLUDE DIRECTORIES: [', string_cat(model%include_dirs,','),']'
180183
end if
181184

185+
! Check for duplicate modules
186+
call check_modules_for_duplicates(model, duplicates_found)
187+
if (duplicates_found) then
188+
error stop 'Error: One or more duplicate module names found.'
189+
end if
182190
end subroutine build_model
183191

192+
! Check for duplicate modules
193+
subroutine check_modules_for_duplicates(model, duplicates_found)
194+
type(fpm_model_t), intent(in) :: model
195+
integer :: maxsize
196+
integer :: i,j,k,l,m,modi
197+
type(string_t), allocatable :: modules(:)
198+
logical :: duplicates_found
199+
! Initialise the size of array
200+
maxsize = 0
201+
! Get number of modules provided by each source file of every package
202+
do i=1,size(model%packages)
203+
do j=1,size(model%packages(i)%sources)
204+
if (allocated(model%packages(i)%sources(j)%modules_provided)) then
205+
maxsize = maxsize + size(model%packages(i)%sources(j)%modules_provided)
206+
end if
207+
end do
208+
end do
209+
! Allocate array to contain distinct names of modules
210+
allocate(modules(maxsize))
211+
212+
! Initialise index to point at start of the newly allocated array
213+
modi = 1
214+
215+
! Loop through modules provided by each source file of every package
216+
! Add it to the array if it is not already there
217+
! Otherwise print out warning about duplicates
218+
do k=1,size(model%packages)
219+
do l=1,size(model%packages(k)%sources)
220+
if (allocated(model%packages(k)%sources(l)%modules_provided)) then
221+
do m=1,size(model%packages(k)%sources(l)%modules_provided)
222+
if (model%packages(k)%sources(l)%modules_provided(m)%s.in.modules(:modi-1)) then
223+
write(error_unit, *) "Warning: Module ",model%packages(k)%sources(l)%modules_provided(m)%s, &
224+
" in ",model%packages(k)%sources(l)%file_name," is a duplicate"
225+
duplicates_found = .true.
226+
else
227+
modules(modi) = model%packages(k)%sources(l)%modules_provided(m)
228+
modi = modi + 1
229+
end if
230+
end do
231+
end if
232+
end do
233+
end do
234+
end subroutine check_modules_for_duplicates
184235

185236
subroutine cmd_build(settings)
186237
type(fpm_build_settings), intent(in) :: settings

Diff for: fpm/test/fpm_test/test_module_dependencies.f90

+104-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module test_module_dependencies
1010
FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, &
1111
FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST
1212
use fpm_strings, only: string_t, operator(.in.)
13+
use fpm, only: check_modules_for_duplicates
1314
implicit none
1415
private
1516

@@ -39,6 +40,14 @@ subroutine collect_module_dependencies(testsuite)
3940
test_missing_program_use, should_fail=.true.), &
4041
& new_unittest("invalid-library-use", &
4142
test_invalid_library_use, should_fail=.true.), &
43+
& new_unittest("package-with-no-duplicates", &
44+
test_package_with_no_module_duplicates), &
45+
& new_unittest("package-with-duplicates-in-same-source", &
46+
test_package_module_duplicates_same_source, should_fail=.true.), &
47+
& new_unittest("package-with-duplicates-in-one-package", &
48+
test_package_module_duplicates_one_package, should_fail=.true.), &
49+
& new_unittest("package-with-duplicates-in-two-packages", &
50+
test_package_module_duplicates_two_packages, should_fail=.true.), &
4251
& new_unittest("subdirectory-module-use", &
4352
test_subdirectory_module_use), &
4453
& new_unittest("invalid-subdirectory-module-use", &
@@ -391,9 +400,103 @@ subroutine test_subdirectory_module_use(error)
391400
uses=[string_t('app_mod')])
392401

393402
call targets_from_sources(targets,model,error)
394-
403+
395404
end subroutine test_subdirectory_module_use
396405

406+
!> Check program with no duplicate modules
407+
subroutine test_package_with_no_module_duplicates(error)
408+
409+
type(error_t), allocatable, intent(out) :: error
410+
411+
type(fpm_model_t) :: model
412+
logical :: duplicates_found = .false.
413+
414+
allocate(model%packages(1))
415+
allocate(model%packages(1)%sources(2))
416+
417+
model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", &
418+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')])
419+
420+
model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_2.f90", &
421+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_2')])
422+
423+
call check_modules_for_duplicates(model, duplicates_found)
424+
if (duplicates_found) then
425+
call test_failed(error,'Duplicate modules found')
426+
return
427+
end if
428+
end subroutine test_package_with_no_module_duplicates
429+
430+
!> Check program with duplicate modules in same source file
431+
subroutine test_package_module_duplicates_same_source(error)
432+
433+
type(error_t), allocatable, intent(out) :: error
434+
435+
type(fpm_model_t) :: model
436+
logical :: duplicates_found
437+
438+
allocate(model%packages(1))
439+
allocate(model%packages(1)%sources(1))
440+
441+
model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", &
442+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1'), string_t('my_mod_1')])
443+
444+
call check_modules_for_duplicates(model, duplicates_found)
445+
if (duplicates_found) then
446+
call test_failed(error,'Duplicate modules found')
447+
return
448+
end if
449+
end subroutine test_package_module_duplicates_same_source
450+
451+
!> Check program with duplicate modules in two different source files in one package
452+
subroutine test_package_module_duplicates_one_package(error)
453+
454+
type(error_t), allocatable, intent(out) :: error
455+
456+
type(fpm_model_t) :: model
457+
logical :: duplicates_found
458+
459+
allocate(model%packages(1))
460+
allocate(model%packages(1)%sources(2))
461+
462+
model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1_a.f90", &
463+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')])
464+
465+
model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1_b.f90", &
466+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')])
467+
468+
call check_modules_for_duplicates(model, duplicates_found)
469+
if (duplicates_found) then
470+
call test_failed(error,'Duplicate modules found')
471+
return
472+
end if
473+
end subroutine test_package_module_duplicates_one_package
474+
475+
!> Check program with duplicate modules in two different packages
476+
subroutine test_package_module_duplicates_two_packages(error)
477+
478+
type(error_t), allocatable, intent(out) :: error
479+
480+
type(fpm_model_t) :: model
481+
logical :: duplicates_found
482+
483+
allocate(model%packages(2))
484+
allocate(model%packages(1)%sources(1))
485+
allocate(model%packages(2)%sources(1))
486+
487+
model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/subdir1/my_mod_1.f90", &
488+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')])
489+
490+
model%packages(2)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/subdir2/my_mod_1.f90", &
491+
scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')])
492+
493+
call check_modules_for_duplicates(model, duplicates_found)
494+
if (duplicates_found) then
495+
call test_failed(error,'Duplicate modules found')
496+
return
497+
end if
498+
end subroutine test_package_module_duplicates_two_packages
499+
397500
!> Check program using a non-library module in a differente sub-directory
398501
subroutine test_invalid_subdirectory_module_use(error)
399502

0 commit comments

Comments
 (0)