Skip to content

Commit 849db65

Browse files
authored
Merge pull request #267 from LKedward/fix-link-objects
Fix enumeration of non-library link objects
2 parents 1b72fd7 + db93172 commit 849db65

File tree

5 files changed

+131
-56
lines changed

5 files changed

+131
-56
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module app_extra_mod
2+
implicit none
3+
4+
character(len=5) :: greet_object = "World"
5+
6+
end module app_extra_mod

example_packages/hello_complex_2/app/say_hello/app_hello_mod.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module app_hello_mod
2+
use app_extra_mod, only: greet_object
23
implicit none
34

45
integer :: hello_int = 42
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
program say_Hello
22
use greet_m, only: make_greeting
3-
use app_hello_mod
3+
use app_hello_mod, only: greet_object
44

55
implicit none
66

7-
print *, make_greeting("World")
7+
print *, make_greeting(greet_object)
88
end program say_Hello

fpm/src/fpm_targets.f90

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -259,60 +259,81 @@ function find_module_dependency(targets,module_name,include_dir) result(target_p
259259
end function find_module_dependency
260260

261261

262-
!> For link targets, enumerate any dependency objects required for linking
262+
!> For libraries and executables, build a list of objects required for linking
263+
!>
264+
!> stored in `target%link_objects`
265+
!>
263266
subroutine resolve_target_linking(targets)
264267
type(build_target_ptr), intent(inout), target :: targets(:)
265268

266-
integer :: i,j,k
267-
type(string_t) :: link_object
269+
integer :: i
268270

269271
do i=1,size(targets)
270272

271273
associate(target => targets(i)%ptr)
272274

273275
allocate(target%link_objects(0))
274276

275-
do j=1,size(target%dependencies)
276-
277-
if (target%target_type == FPM_TARGET_ARCHIVE ) then
278-
279-
! Construct object list for archive
280-
link_object%s = target%dependencies(j)%ptr%output_file
281-
target%link_objects = [target%link_objects, link_object]
282-
283-
else if (target%target_type == FPM_TARGET_EXECUTABLE .and. &
284-
target%dependencies(j)%ptr%target_type == FPM_TARGET_OBJECT) then
285-
286-
associate(exe_obj => target%dependencies(j)%ptr)
287-
288-
! Construct object list for executable
289-
link_object%s = exe_obj%output_file
290-
target%link_objects = [target%link_objects, link_object]
291-
292-
! Include non-library object dependencies
293-
do k=1,size(exe_obj%dependencies)
294-
295-
if (allocated(exe_obj%dependencies(k)%ptr%source)) then
296-
if (exe_obj%dependencies(k)%ptr%source%unit_scope == &
297-
exe_obj%source%unit_scope) then
277+
if (target%target_type == FPM_TARGET_ARCHIVE) then
298278

299-
link_object%s = exe_obj%dependencies(k)%ptr%output_file
300-
target%link_objects = [target%link_objects, link_object]
279+
call get_link_objects(target%link_objects,target,is_exe=.false.)
301280

302-
end if
303-
end if
304-
305-
end do
281+
else if (target%target_type == FPM_TARGET_EXECUTABLE) then
306282

307-
end associate
308-
309-
end if
283+
call get_link_objects(target%link_objects,target,is_exe=.true.)
284+
285+
end if
310286

311-
end do
312287
end associate
313288

314289
end do
315290

291+
contains
292+
293+
!> Wrapper to build link object list
294+
!>
295+
!> For libraries: just list dependency objects of lib target
296+
!>
297+
!> For executables: need to recursively discover non-library
298+
!> dependency objects. (i.e. modules in same dir as program)
299+
!>
300+
recursive subroutine get_link_objects(link_objects,target,is_exe)
301+
type(string_t), intent(inout), allocatable :: link_objects(:)
302+
type(build_target_t), intent(in) :: target
303+
logical, intent(in) :: is_exe
304+
305+
integer :: i
306+
type(string_t) :: temp_str
307+
308+
if (.not.allocated(target%dependencies)) return
309+
310+
do i=1,size(target%dependencies)
311+
312+
associate(dep => target%dependencies(i)%ptr)
313+
314+
if (.not.allocated(dep%source)) cycle
315+
316+
! Skip library dependencies for executable targets
317+
! since the library archive will always be linked
318+
if (is_exe.and.(dep%source%unit_scope == FPM_SCOPE_LIB)) cycle
319+
320+
! Skip if dependency object already listed
321+
if (dep%output_file .in. link_objects) cycle
322+
323+
! Add dependency object file to link object list
324+
temp_str%s = dep%output_file
325+
link_objects = [link_objects, temp_str]
326+
327+
! For executable objects, also need to include non-library
328+
! dependencies from dependencies (recurse)
329+
if (is_exe) call get_link_objects(link_objects,dep,is_exe=.true.)
330+
331+
end associate
332+
333+
end do
334+
335+
end subroutine get_link_objects
336+
316337
end subroutine resolve_target_linking
317338

318339

fpm/test/fpm_test/test_module_dependencies.f90

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
!> Define tests for the `fpm_sources` module (module dependency checking)
22
module test_module_dependencies
33
use testsuite, only : new_unittest, unittest_t, error_t, test_failed
4-
use fpm_targets, only: targets_from_sources, resolve_module_dependencies
4+
use fpm_targets, only: targets_from_sources, resolve_module_dependencies, &
5+
resolve_target_linking
56
use fpm_model, only: fpm_model_t, srcfile_t, build_target_t, build_target_ptr, &
67
FPM_UNIT_UNKNOWN, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, &
78
FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, FPM_UNIT_CSOURCE, &
89
FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, &
910
FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST, &
1011
FPM_TARGET_EXECUTABLE, FPM_TARGET_OBJECT, FPM_TARGET_ARCHIVE
11-
use fpm_strings, only: string_t
12+
use fpm_strings, only: string_t, operator(.in.)
1213
implicit none
1314
private
1415

@@ -71,14 +72,16 @@ subroutine test_library_module_use(error)
7172
if (allocated(error)) then
7273
return
7374
end if
74-
7575
if (size(model%targets) /= 3) then
7676
call test_failed(error,'Incorrect number of model%targets - expecting three')
7777
return
7878
end if
7979

80+
call resolve_target_linking(model%targets)
81+
8082
call check_target(model%targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=2, &
81-
deps = [model%targets(2),model%targets(3)],error=error)
83+
deps = [model%targets(2),model%targets(3)], &
84+
links = model%targets(2:3), error=error)
8285

8386
if (allocated(error)) return
8487

@@ -146,8 +149,10 @@ subroutine test_scope(exe_scope,error)
146149
return
147150
end if
148151

152+
call resolve_target_linking(model%targets)
153+
149154
call check_target(model%targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=1, &
150-
deps=[model%targets(2)],error=error)
155+
deps=[model%targets(2)],links=[model%targets(2)],error=error)
151156

152157
if (allocated(error)) return
153158

@@ -162,7 +167,8 @@ subroutine test_scope(exe_scope,error)
162167
if (allocated(error)) return
163168

164169
call check_target(model%targets(4)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=2, &
165-
deps=[model%targets(1),model%targets(3)],error=error)
170+
deps=[model%targets(1),model%targets(3)], &
171+
links=[model%targets(3)], error=error)
166172

167173
if (allocated(error)) return
168174

@@ -202,20 +208,22 @@ subroutine test_program_with_module(error)
202208
return
203209
end if
204210

211+
call resolve_target_linking(model%targets)
212+
205213
call check_target(model%targets(1)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, &
206214
source=sources(1),error=error)
207215

208216
if (allocated(error)) return
209217

210218
call check_target(model%targets(2)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=1, &
211-
deps=[model%targets(1)],error=error)
219+
deps=[model%targets(1)],links=[model%targets(1)],error=error)
212220

213221
if (allocated(error)) return
214222

215223
end subroutine test_program_with_module
216224

217225

218-
!> Check program using a module in same directory
226+
!> Check program using modules in same directory
219227
subroutine test_program_own_module_use(error)
220228

221229
!> Error handling
@@ -233,21 +241,25 @@ subroutine test_scope(exe_scope,error)
233241
integer, intent(in) :: exe_scope
234242
type(error_t), allocatable, intent(out) :: error
235243

236-
type(srcfile_t) :: sources(2)
244+
type(srcfile_t) :: sources(3)
237245
type(fpm_model_t) :: model
238246
character(:), allocatable :: scope_str
239247

240248
model%output_directory = ''
241249

242250
scope_str = merge('FPM_SCOPE_APP ','FPM_SCOPE_TEST',exe_scope==FPM_SCOPE_APP)//' - '
243251

244-
sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod.f90", &
252+
sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod1.f90", &
245253
scope = exe_scope, &
246-
provides=[string_t('app_mod')])
254+
provides=[string_t('app_mod1')])
247255

248-
sources(2) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", &
256+
sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod2.f90", &
257+
scope = exe_scope, &
258+
provides=[string_t('app_mod2')],uses=[string_t('app_mod1')])
259+
260+
sources(3) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", &
249261
scope=exe_scope, &
250-
uses=[string_t('app_mod')])
262+
uses=[string_t('app_mod2')])
251263

252264
call targets_from_sources(model,sources)
253265
call resolve_module_dependencies(model%targets,error)
@@ -256,11 +268,12 @@ subroutine test_scope(exe_scope,error)
256268
return
257269
end if
258270

259-
if (size(model%targets) /= 3) then
271+
if (size(model%targets) /= 4) then
260272
call test_failed(error,scope_str//'Incorrect number of model%targets - expecting three')
261273
return
262274
end if
263275

276+
call resolve_target_linking(model%targets)
264277

265278
call check_target(model%targets(1)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, &
266279
source=sources(1),error=error)
@@ -272,11 +285,16 @@ subroutine test_scope(exe_scope,error)
272285

273286
if (allocated(error)) return
274287

275-
call check_target(model%targets(3)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=1, &
276-
deps=[model%targets(2)],error=error)
288+
call check_target(model%targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, &
289+
source=sources(3),deps=[model%targets(2)],error=error)
290+
291+
if (allocated(error)) return
292+
293+
call check_target(model%targets(4)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=1, &
294+
deps=[model%targets(3)],links=model%targets(1:3), error=error)
277295

278296
if (allocated(error)) return
279-
297+
280298
end subroutine test_scope
281299
end subroutine test_program_own_module_use
282300

@@ -414,12 +432,13 @@ end function new_test_source
414432

415433

416434
!> Helper to check an expected output target
417-
subroutine check_target(target,type,n_depends,deps,source,error)
435+
subroutine check_target(target,type,n_depends,deps,links,source,error)
418436
type(build_target_t), intent(in) :: target
419437
integer, intent(in) :: type
420438
integer, intent(in) :: n_depends
421439
type(srcfile_t), intent(in), optional :: source
422440
type(build_target_ptr), intent(in), optional :: deps(:)
441+
type(build_target_ptr), intent(in), optional :: links(:)
423442
type(error_t), intent(out), allocatable :: error
424443

425444
integer :: i
@@ -448,6 +467,34 @@ subroutine check_target(target,type,n_depends,deps,source,error)
448467

449468
end if
450469

470+
if (present(links)) then
471+
472+
do i=1,size(links)
473+
474+
if (.not.(links(i)%ptr%output_file .in. target%link_objects)) then
475+
call test_failed(error,'Missing object ('//links(i)%ptr%output_file//&
476+
') for executable "'//target%output_file//'"')
477+
return
478+
end if
479+
480+
end do
481+
482+
if (size(links) > size(target%link_objects)) then
483+
484+
call test_failed(error,'There are missing link objects for target "'&
485+
//target%output_file//'"')
486+
return
487+
488+
elseif (size(links) < size(target%link_objects)) then
489+
490+
call test_failed(error,'There are more link objects than expected for target "'&
491+
//target%output_file//'"')
492+
return
493+
494+
end if
495+
496+
end if
497+
451498
if (present(source)) then
452499

453500
if (allocated(target%source)) then

0 commit comments

Comments
 (0)