Fpm 0.12.0 released 🎉

Congratulations! I‘m especially excited about the Intel LLVM and MPI support.

When can I expect fpm 0.12 on pypi? It seems “stuck” on 0.10.

1 Like

@FedericoPerini
I have got a little question about fpm code. In the repository, there are a few C files with a few functions like c_opendir() to manage the OS filesystem. But we know that fpm can also be downloaded and compiled as a standalone .F90 file. I see that the Fortran/C interfaces are declared in a #ifndef FPM_BOOTSTRAP structure. Can you explain when those C functions are necessary? (if I compile the .F90, it seems to run without problem)

Originally fpm was all Fortran and external system command calls to support running on non-POSIX environments.

All the non-standard system interface calls were done by executing shell commands and writing the output to a file and then reading that file. This kept fpm very portable.

Later the ISO_C_BINDING/C interface was introduced but so far the original interface design has been maintained primarily just for the purpose of still being able to generate a single-file bootstrap version.

If you look at the conditional code, you will see it is usually a function implemented with EXECUTE_COMMAND_LINE and an OS-specific command used with a file as above, and then a POSIX version, and then sometimes a MSWindows call all doing the same thing for the most part. There was a lot of functionality that required using a compiler extension or a C binding or a system command that was not in the earliest versions to keep it portable. Then there was a desire to keep it that way so a standalone file was possible.

With less and less non-POSIX environments there is probably a growing desire to add C functionality directly.

It was an early assumption that stdlib would have evolved to the point it would supply a portable interface and be used as a dependency largely for the purpose of providing portable system interface.. That is happening; but will add a large infra-structure requirement to building fpm.

So at least for the time-being you can still build fpm wth a single file, but at some point that might not be true.

Some of the non-Fortran functionality that is not a core function can be in essentially arbitrary languages and presented as a plug-in as well.

If it had been clear almost all fpm builds would be with gfortran all the current functionality (well, did not check; but at least most of it) could just be done with gfortran extensions that are already available on all gfortran-supported environments.

So there are some alternatives that can keep the single-file build viable.

But it might not be tomorrow, but at some point the bootstrap version may be just one of the versions you see now which will be frozen, but still useful; and fpm will likely need additional infrastructure to install with all functionality.

I personally often use the single-file version. I am not sure how many others do.

But your “little question” actually hits on an aspect of fpm that was (and is) a major design decision. The first fpm(1) prototype was not in Fortran, by the way. Maybe what is was could be the beginning of a fpm(1) trivia quiz :smile:

2 Likes

Thanks @urbanjost for the excellent reply, there is really not that much to add! Yes as said the C code cannot be part of the single file repository.

Most of those functions are just wrappers over system functions, so they could in theory just be interfaced on the Fortran side, but the main obstacle to that is unreliable preprocessor flags (gfortran does not export _WIN32).

So a Fortran-only solution would come at the cost of nontrivial build scripts; FPM_BOOTSTRAP is a good tradeoff, but of course if anyone has better ideas let’s discuss and see how we could improve this!

2 Likes

After you guess, check the answer.

1 Like

Thanks for that great/long answer to my “little question”.

I have a short script to upgrade fpm. Initially, after cloning, it was launching the install.sh script. And at some point I replaced it by a fpm install, upgrading to the new fpm with the previous version.

Reading the install.sh script, I can indeed see that the reference version is 0.8.0 which is downloaded as a single .F90 file. Then it is built, and launched to build the latest version (already cloned).

On the front side fpm is easy for the user, on the back side you need some hidden complexity.

Most if not all compilers have proprietrary extensions for most file system operations; but MSWindows needs custom interfaces, whereas many other platforms provide POSIX-like C functionality in the C companion compilers. Perhaps to take advantage of the extensions a common interface could be defined ala stdlib with a version for each compiler that calls their extensions. Then there could also be versions that call the C companion compilers and perhaps one that reads and writes output from system commands.

That leverages the work already done and supported by the compilers, creates a new standard reminiscent of the PXF interface attempt that vendors could start supporting directly, and allows otherwise pure Fortran programs to not require anything else accept their Fortran compiler, but in a far more portable manner.

So take getting a list of files from the current directory. Define a wrapper interface that becomes the target interface to provide. If the vendor provides the functionality already make it call that from a library just for that compiler. If not, call a shell command and write to a file and read it.
Then as an alternative C/POSIX and C/MSW interfaces providing the same functionality can be provided. But no matter what the underlying method the interface is defined and for many common functions it can be done quickly with the wrapper around the vendor functionality. Gradually perhaps the stdlib interface would then become supplied by vendors or become an optional component of the Fortran standard.

Not done with the file structure just proposed, but lets look at determining if a file is a tty or not.
The first three vendors looked at all provide the functionality, but each slightly differently. stdlib could provide the system_isatty or maybe stdlib_isatty procedure in a manner that on most platforms would be directly supplied by the existing vendor-supported routines and only use the other potentially less portable manners when the vendor had no extension (yet). The model could then be provided directly, perhaps prototyping it via LFortran, which seems to most supportive of providing prototyping currently.

module M_vendor
private
public system_isatty
contains
!>  call compiler-specific ISATTY() function or return .FALSE.
#undef ISATTY

#ifdef __INTEL_COMPILER
    function system_isatty(lun)
    use IFPORT
    integer,intent(in) :: lun
    logical :: system_isatty
       system_isatty=isatty(lun)
    end function system_isatty
#define ISATTY
#endif

#ifdef __NVCOMPILER_MAJOR__X
    ! __NVCOMPILER_MAJOR__ __NVCOMPILER_MINOR__ __NVCOMPILER_PATCHLEVEL__
    function system_isatty(lun)
    use DFPORT
    integer,intent(in) :: lun
    logical :: system_isatty
       system_isatty=isatty(lun)
    end function system_isatty
#define ISATTY
#endif

#ifdef __GFORTRAN__
    function system_isatty(lun)
    integer,intent(in) :: lun
    logical :: system_isatty
       system_isatty=isatty(lun)
    end function system_isatty
#define ISATTY
#endif
#ifndef ISATTY
    function system_isatty(lun)
    integer,intent(in) :: lun
    logical :: system_isatty
       system_isatty=.false.
    end function system_isatty
#define ISATTY
#endif
end module M_vendor

Is there a way to compile both static and shared library of a project at once?
Something like:

[library]
type = ["static", "shared"]
2 Likes

I posted an enhancement request for this as an issue on the fpm github site about 5 days ago. I think (at least on Linux) fpm’s default compile options include -fPIC (but I could be wrong). It should be fairly easy to just add a $(FC) -shared line after building the static library.

1 Like

I agree it’s a good idea to have the option for simultaneous static and shared build - thank you for opening an issue!

Thank you for your work on fpm. It’s come a long way since I first tried it a couple years ago (and had issues with it not correctly resolving module dependencies spread out over 10 or so sub-directories in /src). Tried it again on the same code last week and it worked great. I’m starting to add fpm to all my projects (but will still keep my hand stitched make files that I’ve used for 20 plus years as a backup).

3 Likes

I strongly recommend keeping the single option to bootstrap fpm. If a C file is needed, we can ship it with the single file. There might be a way to do everything from Fortran, for example by having a platform-specific single file.

1 Like