Working with Dependent Projects

Posted on 2018-12-13

NOTE: Users will need at least version 3.0 build 2898 for this example

With the release of Simply Fortran version 3.0, the development environment now supports the concept of dependent projects. A parent project can now include a dependent project in its Project Outline panel, and building the parent project will build the dependent project first without necessarily having the dependent project open in Simply Fortran at all. This paradigm is useful if users have, for example, an executable project that relies on one or more libraries that are also built using Simply Fortran. In version 3.0, building the executable project can trigger building the libraries automatically.

To demonstrate this feature, consider a simple project where we need to generate some lucky numbers. Conceptually, we might want a few different user interfaces, but the underlying computational code wouldn't rely on the user-facing program. We'll start with a simple, single-file library that includes a random number generator:

C     Initialize our lucky number system
      subroutine init_lucky_numbers()
      implicit none

          call random_seed()

      end subroutine init_lucky_numbers

C     Generate an array of random numbers between the two
C     specified values
      subroutine lucky_numbers(values, lowest, highest)
      implicit none

      integer, dimension(:), intent(inout)::values
      integer, intent(in)::lowest, highest
      integer::i, full_range

C         Error checking
          if(highest <= lowest) then
              values = lowest
          end if

          full_range = highest - lowest

C         Loop through our array
          do i=lbound(values, 1), ubound(values, 1)
              call random_number(random_value)

C             Scale the value to be between our numbers of interest
              random_value = random_value*real(full_range) + 
     .                       real(lowest)

C             Scale to the nearest integer and store it
              values(i) = nint(random_value)

          end do

      end subroutine lucky_numbers

We've written this code in fixed-format Fortran, though it uses a substantial amount of modern Fortran intrinsic procedures and syntax. The file contains two subroutines. The first simply initializes the random number generator, and the second will fill the array values with random integers between lowest and highest. There is some math involved in converting the uniform random numbers from the intrinsic random_number, but it's relatively straightforward and completely portable. We can place this file in a static library project by itself called libnumbers.prj with a target libnumbers.a.

Next, we'll need to write an interface to this library. To be cross-platform, a text interface is the simplest route. Since our library is external, we'll also need interface blocks for the two functions. Here's a simple example program:

program main
implicit none

    integer, parameter::lowest = 1
    integer, parameter::highest = 69
    integer, parameter::length = 5

    integer, dimension(length)::values

        subroutine init_lucky_numbers
        end subroutine init_lucky_numbers
    end interface

        subroutine lucky_numbers(v, l, h)
        integer, dimension(:), intent(inout)::v
        integer, intent(in)::l, h
        end subroutine lucky_numbers
    end interface

    call init_lucky_numbers()

    write(*, '(A)', ADVANCE='NO') "Press [ENTER] to generate or [Q] and [ENTER] to quit: "
    read(*,'(A1)') cmd

    do while(cmd .NE. 'Q' .AND. cmd .NE. 'q')
        call lucky_numbers(values, lowest, highest)

        write(*, '(2X,5(I2,4X))') (values(i),i=1,length)

        write(*, '(A)', ADVANCE='NO') "Press [ENTER] to generate or [Q] and [ENTER] to quit: "
        read(*,'(A1)') cmd
    end do

    write (*,*) " "

end program main

Normally in the past, we'd build the original library separately and add a flag to this parent project to link to said library. With version 3.0 of Simply Fortran, we can directly add the library project to our parent project. After clicking "Add File(s)..." in the Project menu, navigate and select the project file itself. Once added, our parent project should look like this:


From our parent project, we can now build everything, including our dependent project. Clicking "Build Project" from the Build menu will produce the following in our Build Status tab:


Notice in the Build Status tab that the libnumbers project was also built simply by building our parent project. The resulting executable works exactly as one expects.

We can also build a different front end using the same library for Windows users with AppGraphics:


This example is, of course, somewhat trivial. It does, however, illustrate the ease with which project dependencies can be used. While we've shown a static library as a dependent project, the same procedure works with dynamic libraries or even executable projects. In the case of an executable, the dependent executable is simply built first (as opposed to linking to the parent project).

Below is a link to an archive containing our three projects: two parent projects and one dependent library project. The AppGraphics project only works on the Windows platform.

If you have any troubles with dependent projects or have any suggestions for additional features, please see our Support page for documentation and contact information. We're always happy to help!

Back to the Blog...