FPM dependencies vs. copying code

FPM makes it easy for a package to depend on other packages, and @ivanpribec made a tool to graph dependencies, discussed at Dependency graph for FORD.

It’s nice to not reproduce code from other packages, but don’t you have the risk that your project breaks if any of the packages it depends on makes incompatible changes? If you just copy needed modules into your repo, you avoid this problem, although you won’t benefit from downstream bug fixes or algorithm improvements.

Asked about FPM dependencies vs. copying, ChatGPT-4o mentioned the ability to pin versions in fpm.toml (e.g., use a specific commit or tag).

1 Like

That is a risk, not just because of incompatible changes, but also because a package can disappear. As you mentioned the options available currently are:

  • specifying a commit hash or git tag
  • vendoring the dependency (making your own copy)

In the future, an fpm package registry may also provide some guarantees.

There have been notable incidents of this type with other programming languages, e.g. the npm left-pad incident - Wikipedia.

Currently all the plain fpm dependencies (not external dependencies like an MPI library, etc.) are copied into build/dependencies when you build. If some of those are on platforms you cannot always access you can move that directory into another subdirectory and change your dependencies from URLs to paths. That is, out of the three principal ways to designate a dependency on an external package

# URL
   git = "https://github.com/urbanjost/M_CLI2.git"
   # Registry
   namespace = "GPF"
   # PATH
   path = "dependencies/M_CLI2"

change from the URL to a path. You can also start your own local registry, which reduces duplication. I tend to use the path method but make the dependencies directory a soft link to a directory with everything my packages are dependent on even though links are not very portable between OSes. Then I can tar up that directory and copy it to a machine not even on a network and use fpm with dependencies just fine,
without having to change my manifest file all the time from URLs to paths and back again as well.

I also often run a script to make a single-file source as well; but with modules and no elaborate tool to shake unused code out of the modules I sometimes find my 100-line program now has become a 60 000-line file. But if the code is pure Fortran knowing I have a single-file source available if everything else goes away is very nice, particularly for archiving.

Fortran is so backward-compatible having a single-file source is reassuring. Years from now Cmake/Make/fpm/… may all change but there is a good chance I can pull that single file from an Archive and get it going as long as I stick to standard Fortran.

Not really generic enough for public consumption, but I make the single-file generator a
plug-in so I can just enter “fpm standalone” to generate it. I think it would be pretty easy to make a fpm-selfcontained program or script as well, so you could just enter “fpm selfcontained” and it would make a copy of your package and use maybe a build command to get all the dependencies and then move them to a subdirectory so that package could be built from files within the repository. Maybe call it “fpm-archive” or “fpm-snapshot”. Thinking I like “fpm snapshot”.

Does rust or npm or other package managers have some kind of capture of current dependencies like that? I have not run across such an option, but have not specifically looked for that capability either.

2 Likes

Indeed, the left-pad incident is a famous example. Azer Koçulu after a fight over the name of one of his packages took down all his packages from npm among which left-pad (11 lines of code). That dependency happened to be used all over the Internet and broke countless web sites depending on it. NPM finally decided to republish the package against the will of the original developer.
So the key message here is probably to always control the dependencies, even from third-parties.

In order to prevent such issues from happening in a industrial context, I am personally running my own package server. In the present case, it is a nugget server for .NET dependencies. I use it to publish my own closed-source dependencies and mirror the public dependencies that I want. By doing so I can control the versions and the upgrade when needed.
I never tried with fortran dependencies though and do not know how difficult it would be to set-up a private fpm-registry and mirror existing packages.