# Path manipulation library

**URL:** <https://fortran-lang.discourse.group/t/path-manipulation-library/2355>\
**Category:** Announcements\
**Created:** [December 1, 2021, 8:30pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355 "2021-12-01T20:30:48Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [December 1, 2021, 8:30pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/1 "2021-12-01T20:30:48Z")

</div>

I recently updated my Fortran “pathlib” library to have an [object-oriented interface](https://github.com/scivision/fortran-pathlib/#readme).  
It works equally well across operating systems (Linux, macOS, Windows).  
It is inspired by Python pathlib and C++ filesystem.

a small sample of “path%” methods include:

```auto
expanduser() ! expand tilde '~' to user home directory
with_suffix(new) ! replace filename suffix
as_posix() ! switch "\" for "/"
is_directory() ! directory and not a file
is_file() ! is a file and not a directory
parent() ! one level up path

```

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [December 1, 2021, 9:59pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/2 "2021-12-01T21:59:42Z")

</div>

Excellent, thanks for sharing! Fortran definitely needs that.

---

<div class="post-metadata">

**Author:** ![urbanjost](https://avatars.discourse-cdn.com/v4/letter/u/0ea827/32.png) [@urbanjost](https://fortran-lang.discourse.group/u/urbanjost)\
**Post date:** [December 2, 2021, 12:58am UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/3 "2021-12-02T00:58:20Z")

</div>

I have needed similar functions ( [M\_path](https://urbanjost.github.io/M_path) ) that complement some other modules I have; but quite a few of mine require a POSIX C interface and so do not work in several MSWindows environments. Nice. Wondering if you plan on making it available as an fpm(1) package? I particularly like the expanduser() and as\_posix() which I do not have an equivalent of but already have programs where I should use them, and the interface is very intuitive. Thanks!

---

<div class="post-metadata">

**Author:** ![interkosmos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/interkosmos/32/296_2.png) [@interkosmos](https://fortran-lang.discourse.group/u/interkosmos)\
**Post date:** [December 2, 2021, 8:51am UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/4 "2021-12-02T08:51:12Z")

</div>

Is there a reason `expanduser()` is not named `expand_user()`?

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [December 3, 2021, 7:11am UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/5 "2021-12-03T07:11:48Z")

</div>

expanduser was named like Python pathlib and os.path method as well as Meson filesystem method

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [December 3, 2021, 7:13am UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/6 "2021-12-03T07:13:59Z")

</div>

I’m not sure if fpm can yet do the logic for including different source files based on operating system and compiler. Can fpm do “if” logic like that?

I use Windows CRT or Unix CRT as needed.

---

<div class="post-metadata">

**Author:** ![plevold](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/plevold/32/754_2.png) [@plevold](https://fortran-lang.discourse.group/u/plevold)\
**Post date:** [December 3, 2021, 12:02pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/7 "2021-12-03T12:02:53Z")

</div>

Looks great! In addition to the procedures you’ve already implemented I think a `relative_to` procedure similar to the one in [pathlib](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.relative_to) would be highly appreciated.

Also, I would strongly consider making `character(len=:), allocatable :: path` private inside the `path` type. You could then implement a constructor that takes a string like this:

```fortran
type :: path
    private
    character(len=:), allocatable :: path
end type

interface path
    module procedure new_from_chars
end interface

contains

type(path) pure function new_from_chars(chars) result(p)
    character(len=*), intent(in) :: chars
    this%path = chars
end function

```

Usage:

```fortran
type(path) :: p
p = path('/foo/bar')

```

To get the string back (e.g. for printing/opening files/etc.) you could then implement a `procedure :: to_chars` that takes the path object and returns a `character(len=:), allocatable`.

Personally I would also name the type `path_t` and not `path` so that we can have a variable `type(path_t) :: path`, but I don’t think there’s any consensus on such naming conventions at the moment.

EDIT: Oh and I forgot to suggest a `join` procedure to concatenate two paths 😃 Would also be very handy!

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [December 3, 2021, 2:55pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/8 "2021-12-03T14:55:47Z")

</div>

Thank you Pål Levold, I switched the base type name to “path\_t” for clarity as you suggest.

I added getter/setter methods as you suggest also.

Very helpful!!

---

<div class="post-metadata">

**Author:** ![plevold](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/plevold/32/754_2.png) [@plevold](https://fortran-lang.discourse.group/u/plevold)\
**Post date:** [December 3, 2021, 8:11pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/9 "2021-12-03T20:11:27Z")

</div>

> [@scivision](#):
>
> I’m not sure if fpm can yet do the logic for including different source files based on operating system and compiler. Can fpm do “if” logic like that?

I don’t think fpm can do that, but you might be able to surround the submodule code with preprocessor directives like `#ifdef _WIN32` etc as a workaround.

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [January 20, 2022, 3:10pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/10 "2022-01-20T15:10:11Z")

</div>

Update: now [Fortran-pathlib](https://github.com/scivision/fortran-pathlib) is entirely based on C++17 filesystem. This avoids the platform-specific and compiler-specific workarounds I had to use in earlier versions of pathlib.

GCC \>= 8, Clang, Intel compiler, Visual Studio, etc. have C++17 to work with the Fortran pathlib interface.

I have retained as a fallback the original pathlib C stdlib-based routines as a fallback for non-C++17 systems.

fpm is not yet supported as “build-script” and/or non-Fortran source are not yet fpm features.

pathlib can build with GNU Make, CMake or Meson.

---

<div class="post-metadata">

**Author:** ![epagone](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/epagone/32/252_2.png) [@epagone](https://fortran-lang.discourse.group/u/epagone)\
**Post date:** [January 20, 2022, 4:40pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/11 "2022-01-20T16:40:13Z")

</div>

Thank you! 🌠

I guess the current version does not yet support fpm _tests_ (cloned your repository a few moments ago):

```bash
$ fpm test
<INFO> No tests to run
STOP 0

$ fpm --version
Version: 0.5.0, alpha
Program: fpm(1)
Description: A Fortran package manager and build system
Home Page: https://github.com/fortran-lang/fpm
License: MIT
OS Type: Linux

```

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [January 20, 2022, 4:56pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/12 "2022-01-20T16:56:52Z")

</div>

Yes I was incorrect, fpm is not linking in C++ fs.cpp that is needed. thus libpathlib.a is missing the functions provided by C++ with fpm. I think there are some open PRs/issues for FPM but maybe build/link C++ isn’t yet possible with FPM, without using a Makefile/script

---

<div class="post-metadata">

**Author:** ![epagone](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/epagone/32/252_2.png) [@epagone](https://fortran-lang.discourse.group/u/epagone)\
**Post date:** [January 20, 2022, 4:59pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/13 "2022-01-20T16:59:45Z")

</div>

Ok, thanks, but I will note that it builds ok:

```bash
$ fpm build
 + mkdir -p build/gfortran_2A42023B310FA28D
 + mkdir -p build/gfortran_2A42023B310FA28D/fortran-pathlib/
 + gfortran -c ./src/pathlib.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build/gfortran_2A42023B310FA28D -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_pathlib.f90.o
 + gfortran -c ./src/find.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build/gfortran_2A42023B310FA28D -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_find.f90.o
./src/find.f90:58:0:

   58 | p = expanduser(path)
      | 
Warning: ‘.p’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/find.f90:11:0:

   11 | character(:), allocatable :: path1, suff(:)
      | 
Warning: ‘.suff’ is used uninitialized in this function [-Wuninitialized]
./src/find.f90:27:0:

   27 | get_filename = get_filename // '/' // name
      | 
Warning: ‘.__var_1_realloc_string’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/find.f90:37:0:

   37 | path1 = get_filename
      | 
Warning: ‘.path1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
 + gfortran -c ./src/io.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build/gfortran_2A42023B310FA28D -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_io.f90.o
 + gfortran -c ./src/fs_cpp.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build/gfortran_2A42023B310FA28D -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_fs_cpp.f90.o
./src/fs_cpp.f90:571:0:

  571 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:504:0:

  504 | s1 = trim(path) // C_NULL_CHAR
      | 
Warning: ‘.s1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:484:0:

  484 | s1 = a // C_NULL_CHAR
      | 
Warning: ‘.s1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:485:0:

  485 | s2 = b // C_NULL_CHAR
      | 
Warning: ‘.s2’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:470:0:

  470 | csrc = src // C_NULL_CHAR
      | 
Warning: ‘.csrc’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:471:0:

  471 | cdest = dest // C_NULL_CHAR
      | 
Warning: ‘.cdest’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:456:0:

  456 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:444:0:

  444 | c1 = path1 // C_NULL_CHAR
      | 
Warning: ‘.c1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:445:0:

  445 | c2 = path2 // C_NULL_CHAR
      | 
Warning: ‘.c2’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:436:0:

  436 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:428:0:

  428 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:421:0:

  421 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:413:0:

  413 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:362:0:

  362 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:352:0:

  352 | ctgt = tgt // C_NULL_CHAR
      | 
Warning: ‘.ctgt’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:353:0:

  353 | clink = link // C_NULL_CHAR
      | 
Warning: ‘.clink’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:344:0:

  344 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:336:0:

  336 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/fs_cpp.f90:326:0:

  326 | cpath = path // C_NULL_CHAR
      | 
Warning: ‘.cpath’ may be used uninitialized in this function [-Wmaybe-uninitialized]
 + gfortran -c ./src/iter.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build/gfortran_2A42023B310FA28D -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_iter.f90.o
./src/iter.f90:26:0:

   26 | wk = as_posix(path)
      | 
Warning: ‘.wk’ may be used uninitialized in this function [-Wmaybe-uninitialized]
./src/iter.f90:43:0:

   43 | if(wk(j:j) == "/") wk = wk(:j-1)
      | 
Warning: ‘.__var_1_realloc_string’ may be used uninitialized in this function [-Wmaybe-uninitialized]
 + ar -rs build/gfortran_2A42023B310FA28D/fortran-pathlib/libfortran-pathlib.a build/gfortran_2A42023B310FA28D/fortran-pathlib/src_find.f90.o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_io.f90.o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_fs_cpp.f90.o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_iter.f90.o build/gfortran_2A42023B310FA28D/fortran-pathlib/src_pathlib.f90.o
ar: creating build/gfortran_2A42023B310FA28D/fortran-pathlib/libfortran-pathlib.a

```

The error message with `fpm test` looks more like tests are not found, not that they are found and fail.

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [January 20, 2022, 6:22pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/14 "2022-01-20T18:22:39Z")

</div>

I attempt to use Makefile from fpm with parameter:

```auto
[library]
build-script="src/Makefile"

```

I’m not sure why that doesn’t work. Maybe my fpm 0.5.0 is too old?

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [January 20, 2022, 6:24pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/15 "2022-01-20T18:24:35Z")

</div>

Yes I think fpm is not recognizing that I’ve specified in fpm.toml to use src/Makefile. Fpm instead tries to build like a default fpm project, and then the test fails to link because it’s missing the fs.cpp content and c++ flags.

Using just the Makefile works from src/ directory `make` produces pathlib.a, which can be used like

```auto
gfortran tests/test_pathlib.f90 pathlib.a -lstdc++

```

---

<div class="post-metadata">

**Author:** ![epagone](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/epagone/32/252_2.png) [@epagone](https://fortran-lang.discourse.group/u/epagone)\
**Post date:** [January 20, 2022, 6:39pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/16 "2022-01-20T18:39:02Z")

</div>

> [@scivision](#):
>
> the test fails to link because it’s missing the fs.cpp content and c++ flags

In my last post I was pointing out that, reading the console message

> [@epagone](#):
>
> ```auto
> $ fpm test
> <INFO> No tests to run
> STOP 0
> 
> ```

I am under the impression that fpm doesn’t find the tests, _not_ that there is a linking error. I may be mistaken though.

---

<div class="post-metadata">

**Author:** ![lkedward](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/lkedward/32/72_2.png) [@lkedward](https://fortran-lang.discourse.group/u/lkedward)\
**Post date:** [January 20, 2022, 6:48pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/17 "2022-01-20T18:48:40Z")

</div>

To clarify: fpm does not yet support c++ sources. You can use `fpm build --list` to check which objects will be compiled.

Because there are no tests detected, fpm doesn’t get to the link step so we won’t see any link errors. (try moving `./src/tests` folder to `./test`).

> [@scivision](#):
>
> I attempt to use Makefile from fpm with parameter:

Unfortunately fpm doesn’t currently support the `build-script` option.

---

<div class="post-metadata">

**Author:** ![epagone](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/epagone/32/252_2.png) [@epagone](https://fortran-lang.discourse.group/u/epagone)\
**Post date:** [January 20, 2022, 6:56pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/18 "2022-01-20T18:56:15Z")

</div>

> [@lkedward](#):
>
> try moving `./src/tests` folder to `./test`

But this part of `fpm.toml`

```toml
...
[[test]]
name="core"
source-dir = "src/tests"
main="test_pathlib.f90"

```

made me think that fpm knows where the tests are located… 🤔

---

<div class="post-metadata">

**Author:** ![lkedward](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/lkedward/32/72_2.png) [@lkedward](https://fortran-lang.discourse.group/u/lkedward)\
**Post date:** [January 20, 2022, 7:00pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/19 "2022-01-20T19:00:05Z")

</div>

Yes, that should work; I think it’s been updated since I last tried it.

---

<div class="post-metadata">

**Author:** ![scivision](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@scivision](https://fortran-lang.discourse.group/u/scivision)\
**Post date:** [January 20, 2022, 7:05pm UTC](https://fortran-lang.discourse.group/t/path-manipulation-library/2355/20 "2022-01-20T19:05:46Z")

</div>

OK thanks I updated the note to show that pathlib can build with Make, CMake or Meson. Thanks!

[Next page](https://fortran-lang.discourse.group/t/path-manipulation-library/2355.md?page=2)
