How to access a subdirectory in a Win/Unix compatible way?

I am working on a fpm project that will contain tens of .txt files that can be read by the Fortran program. It seems I must put all these text files a the root of the fpm project if I want open(newunit=file_unit, file=filename) to access them. It runs but I am not entirely satisfied as my project root directory will be cluttered with those files.

I could put them into a txt/ subdirectory and access them with something like file="txt/"//filename but I would stumble on the Unix/Windows directories separator problem and I want my project to work on all systems.

Is there a way to deal with that problem with an fpm option (for example an option changing the working directory)? I do not want to use an additional library to deal with that problem, as I want to stay simple (if there is no solution, I will live with that).

What I do is to have this parameter stored in a module

#ifdef WIN32
  character(len=1), parameter, public :: path_sep='\'
#else
  character(len=1), parameter, public :: path_sep='/'
#endif

then use it as needed
file=<something>//path_sep//<something>

1 Like

The file I/O Windows API (which I assume is used behind the scene by the Fortran compiler) supports the slash “/” as a separator.

The name of the file or device to be created or opened. You may use either forward slashes (/) or backslashes (\) in this name.

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea

1 Like

You could determine at run-time whether the OS is Unix or Windows by checking if the PATH environment variable contains forward or back slashes. For example, on my Windows PC the output of

use iso_fortran_env
implicit none
character (len=100) :: pathstring
call get_environment_variable("PATH",pathstring)
print*,trim(pathstring)
end

is

c:\Users\myname\AppData\Local\Programs\R\R-4.2.2\bin\x64;c:\programs\gnuplot\bin;c:\Users\myname

In the (distant) past I used both what @hkvzjal and @Beliavsky suggested. Both work, but I don’t think they are needed anymore. / works just fine in that other operating system that normally expects \ instead. I’m using MinGW-w64 though, and occasionally TDM_GCC - I’m not sure if that’s true for other compilers. So I don’t have to do anything special, the code is exactly the same as in Unix-like systems.

This, however, is not true for Makefiles. In some cases / works as expected (for example, when you do the actual compiling with something like $(FC) $(SRC_DIR)/filename.f90 .... But in some other cases it won’t work. For example if you want to set directories in a Makefile, you have to use, e.g., EXE_DIR=..\bin intstead of what you would do on Unix-like systems. This is why, while the code itself is the same, Makefiles are not.

What I do is to have a generic Makefile that detects the OS and sets stuff accordingly, then two Makefiles, one for GNU/Linux. BSD, etc and one for… that other operating system. The generic makefile will then include the actual Makefile in the end, depending on the OS detected. It works all the time.

For a generic Makefile, see this post.

There is a flag for this purpose:

 -C, --directory PATH
             Change working directory to PATH before running any command
1 Like

I knew this was on a TODO list somewhere, but I was unaware this got added. Thanks for reminder.

Thanks @hkvzjal , @PierU , @Pap , @Beliavsky
It’s true I had noticed that the / can be used in the Windows Powershell. If that solves the problem in Fortran programs, it’s “one giant leap for mankind”! In MinGW environments, it should evidently not be a problem, but if it is the same with Powershell, let’s have a drink!

Thanks @ivanpribec , it’s an option I will note for another project.
In the present case, I just realized my idea was stupid as my project will be a library. So when it is used as a fpm dependency, we can not have a working directory for that library that would be different of the working directory of the parent project, as there is only one executable.
But wait, it seems therefore still worse: if I use that library as a fpm dependency, the final executable will not try to read my .txt files in the root directory of my library, isn’t it? It will try to read in the root directory of the parent project, I guess… :woozy_face:

1 Like

I have just tried in Windows 10: in its file manager, you can type a path containing both \ and / and it works. :champagne:

Is there a special reason you need Powershell? I’m asking because I never used it, at least not for building/installing Fortran applications/libraries. I am using Emacs’ built-in terminals (it has two kinds of them, actually) and both work with / for everything. I know you are a Vim user, and if I remember correctly it does have a shell via plugins. Also Neovim seems to have such functionality built-in.

No, I am just trying to figure out how modern Windows manages directory paths because I want my Fortran library to work everywhere. It’s not a personal need…

Well, I will revise my strategy. My .txt files should be read and be put into arrays of integers. I think I will transform them into Fortran code, it will be easier to manage (no path working directory problem). Usually, I would have written a Python script, but this time I will recycle the small subroutine I had written in Fortran to read them, to generate a Fortran module declaring those arrays. A Fortran code generating a Fortran code is more fun!

3 Likes