Fpm - builds where the build dir is in the source-dir

I’m not sure if this classes as a bug or a “that’s a stupid thing to do so you shouldn’t be doing it” example, but…

I am trying to fpm-ify some existing code, which includes pulling in a dependency. The source code is in the root directory, so I am putting the following in my fpm.toml file to build the library:

[library]
source-dir = "./"

If I specify my dependency as a local path, then everything works fine:

[dependency]
my-dependency = { path = "/path/to/my/dependency" }

However, if I specify my dependency as a Git URL, then building fails due to <ERROR>*build_model*:Error: One or more duplicate module names found.

[dependency]
my-dependency = { git = "https://github.com/<git-org>/<git-repo>" }

From what I can figure out, this is because fpm first pulls the Git dependency into build/dependencies (which it doesn’t for local dependencies), but then it also thinks because build/dependencies is in source-dir, that it is a local file to build - hence the duplicate module error. If I change the source-dir to not include the build dir, the error disappears.

If I’m correct in my diagnosis, then is this expected behaviour? I guess my expected behaviour would be for fpm to automagically exclude the build dir for source-dir, if someone is stupid enough to set source-dir as the project root.

P.S. If everyone thinks this is a bug then I’ll happily recreate this post as an issue over on GitHub.

I think the expectation of fpm is the project root won’t be the source directory, as fpm uses folders to disambiguate between tests, examples, apps, and libraries. However I think it’s a valid question what should happen in case a fpm user does this.

The two options I see to address this:

  1. Raise an error in case the source-dir is set to ./ (forbid the source directory from being the project root)
  2. Exclude the build, test, example, and app, directories, and consider everything else to be source.

The second option look undesirable to me, because fpm will recursively process sub-folders which are of no relevance (documentation, scripts, other build systems, etc.) to it.

My two cents.

1 Like

I think there are a (pretty small) number of times you’d want this to work. It’s been this long since somebody has asked for it. I think that means it’s probably low priority.

That said, I do think it should “work”. In the general case traversing a directory to find source files should exclude the build folder and any other explicit source directory. I.e. if you put an app folder in your source folder and tell fpm there is an app in there, it should know to ignore it.

@samharrison7 , I’d say it’s worth at least a bug report, and if you’re at all interested in contributing you could submit a PR too :wink: .

1 Like

Thanks both. I agree it is a bit of an edge case, though I suspect not uncommon for a lot of legacy (scientific) code. I’ll submit a bug report, and if I can figure out my way around the fpm code, I’m not adverse to working on a PR!

This was once part of a deferred feature for a “single file build”. There was once a test file for it. The idea was that a minimal project could be just an application file and an fpm.toml file. So the smallest project was just a directory with app source and an fpm.toml file. In combination with the -C option and a switch to copy the file the related idea was you could have a “default” directory set up with an fpm.toml file with your favorite set of dependencies and src files and that you would then be able to, give an application file located anywhere, enter something like
“fpm install [-C directory] ./myprogram.f90” and myprogram.f90 would be built just like it had been copied to “directory”/app and then the fpm install had been done. The exact syntax had not been worked out. The prototype assumed if the filename contained a / or a suffix that it would be copied to the -C directory; and that a default FPM_DIRECTORY environment variable would be used as the default. Never quiet worked out the defaults; and part of it required changing the install subcommand to only install named files instead of “everything”. Might be an idea in there for your PR.

I made a little plugin bash shell script that basically does the same thing and I find it useful. I find it very convenient to just be able to have such “single file” projects where there is no sign of fpm but you just enter a command and a standalone program, which can have all kinds of fpm dependencies in it is just built and installed wherever it sits, which is close to the original project
description.

1 Like

That would be really neat, I was definitely thinking that single file projects would be those likely to have source code in the project root.

As a slight aside, the actual reason this project “needs” the project root as source-dir is because the source code is split over two folders inside the project root. I tried to list the two directories in the source-dir field (source-dir = ['folder1', 'folder2']), but I don’t think that worked. The other option would be, because they are effectively standalone projects, to have one built as a dependency of the other, but that’s a little faffy. Has being able to specify a list of source-dir folders ever been suggested, in a similar way that you can list multiple include dirs?

The last time it came up was source-dir in fpm.toml must not be an array · Issue #821 · fortran-lang/fpm · GitHub

The work-around was links, as src/ can contain multiple subdirectors, so if in the top directory were directories A,B,C with source that for some reason you could not move into src/, you could put links in src called A,B,C that pointed to the real directories. The problem being soft links are not portable between all platforms and may or may not work with different systems like github, gitlab, the fpm repository, …

The other work-around was to make A, B, and C their own packages, putting an fpm.toml file in each one and then using them as local dependencies.

The third one was to have a file in src that did an include of the files in A,B,C. They might have to be in a particular order.

So the second one makes the most sense assuming you really cannot just move A,B,C into src/,
which is obviously the easy solution for working with fpm(1) as it is now.

2 Likes