resolve_target_linking Subroutine

public subroutine resolve_target_linking(targets, model)

Construct the linker flags string for each target target%link_flags includes non-library objects and library flags

Arguments

Type IntentOptional AttributesName
type(build_target_ptr), intent(inout), target:: targets(:)
type(fpm_model_t), intent(in) :: model

Contents


Source Code

subroutine resolve_target_linking(targets, model)
    type(build_target_ptr), intent(inout), target :: targets(:)
    type(fpm_model_t), intent(in) :: model

    integer :: i
    character(:), allocatable :: global_link_flags
    character(:), allocatable :: global_include_flags

    if (size(targets) == 0) return

    if (targets(1)%ptr%target_type == FPM_TARGET_ARCHIVE) then
        global_link_flags = targets(1)%ptr%output_file
    else
        allocate(character(0) :: global_link_flags)
    end if

    if (allocated(model%link_libraries)) then
        if (size(model%link_libraries) > 0) then
            global_link_flags = global_link_flags // " -l" // string_cat(model%link_libraries," -l")
        end if
    end if

    allocate(character(0) :: global_include_flags)
    if (allocated(model%include_dirs)) then
        if (size(model%include_dirs) > 0) then
            global_include_flags = global_include_flags // &
            & " -I" // string_cat(model%include_dirs," -I")
        end if
    end if

    do i=1,size(targets)

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

            if (target%target_type /= FPM_TARGET_C_OBJECT) then
                target%compile_flags = model%fortran_compile_flags//" "//global_include_flags
            else
                target%compile_flags = model%c_compile_flags//" "//global_include_flags
            end if

            allocate(target%link_objects(0))

            if (target%target_type == FPM_TARGET_ARCHIVE) then

                call get_link_objects(target%link_objects,target,is_exe=.false.)

                allocate(character(0) :: target%link_flags)

            else if (target%target_type == FPM_TARGET_EXECUTABLE) then

                call get_link_objects(target%link_objects,target,is_exe=.true.)

                target%link_flags = model%link_flags//" "//string_cat(target%link_objects," ")

                if (allocated(target%link_libraries)) then
                    if (size(target%link_libraries) > 0) then
                        target%link_flags = target%link_flags // " -l" // string_cat(target%link_libraries," -l")
                    end if
                end if

                target%link_flags = target%link_flags//" "//global_link_flags

            end if

        end associate

    end do

contains

    !> Wrapper to build link object list
    !>
    !>  For libraries: just list dependency objects of lib target
    !>
    !>  For executables: need to recursively discover non-library
    !>   dependency objects. (i.e. modules in same dir as program)
    !>
    recursive subroutine get_link_objects(link_objects,target,is_exe)
        type(string_t), intent(inout), allocatable :: link_objects(:)
        type(build_target_t), intent(in) :: target
        logical, intent(in) :: is_exe

        integer :: i
        type(string_t) :: temp_str

        if (.not.allocated(target%dependencies)) return

        do i=1,size(target%dependencies)

            associate(dep => target%dependencies(i)%ptr)

                if (.not.allocated(dep%source)) cycle

                ! Skip library dependencies for executable targets
                !  since the library archive will always be linked
                if (is_exe.and.(dep%source%unit_scope == FPM_SCOPE_LIB)) cycle

                ! Skip if dependency object already listed
                if (dep%output_file .in. link_objects) cycle

                ! Add dependency object file to link object list
                temp_str%s = dep%output_file
                link_objects = [link_objects, temp_str]

                ! For executable objects, also need to include non-library
                !  dependencies from dependencies (recurse)
                if (is_exe) call get_link_objects(link_objects,dep,is_exe=.true.)

            end associate

        end do

    end subroutine get_link_objects

end subroutine resolve_target_linking