Problem using external libraries with IntelliSense

Hello! I’ve been trying to figure out the correct options to make linting work with Modern Fortran extension in VS Code. My code uses the PETSc library, and the library uses MPI. The linting compiler is having trouble finding the modules and declarations, etc. I have attached a screenshot demonstrating the problem:


(SNES, Vec, PetscErrorCode are types defined in the library, in “use petscsnes” there is also a warning that this module cannot be found in project)

I have added the include directories to extension settings as well as various compiler flags necessary for the program to compile.

I have tested manual compilation with gfortran with these flags and my program compiles just fine. The program itself is an example program from the PETSc library. Here is the command line I used to successfully compiling the example

gfortran -I/usr/lib/x86_64-linux-gnu/openmpi/include -I/usr/lib/petscdir/petsc3.12/x86_64-linux-gnu-real/include -L/usr/lib/x86_64-linux-gnu/openmpi/lib -L/usr/lib/petscdir/petsc3.12/x86_64-linux-gnu-real/lib -Wl,--copy-dt-needed-entries -lmpi_usempif08 -lmpi_usempi_ignore_tkr -lmpi_mpifh -lmpi -o ex1f ex1f.F90 -lpetsc_real -lm

The settings.json contains the following lines relating to Modern Fortran extension:

    "fortran.fortls.maxLineLength": 132,
    "fortran.fortls.path": "/home/yuhongrui/.local/bin/fortls",
    "fortran.linter.extraArgs": [
        "-w",
        "-L/usr/lib/x86_64-linux-gnu/openmpi/lib",
        "-Wl,--copy-dt-needed-entries",
        "-lmpi_mpifh",
        "-lmpi -lpetsc_real",
        "-lmpi_usempi_ignore_tkr",
        "-lm",
        "-lmpi_usempif08",
        "-L/usr/lib/petscdir/petsc3.12/x86_64-linux-gnu-real/lib"
    ],
    "fortran.linter.includePaths": [
        "/usr/lib/petscdir/petsc3.12/x86_64-linux-gnu-real/include",
        "/usr/lib/x86_64-linux-gnu/openmpi/include",
        "${workspaceFolder}/fortran_mods"
    ],
    "fortran.linter.modOutput": "${workspaceFolder}/fortran_mods",
	"fortran.linter.compiler": "gfortran",
    "fortran.linter.compilerPath": "/usr/bin/gfortran",
    "fortran.experimental.keepInitDiagnostics": false,
    "fortran.fortls.excludeDirectories": [
        "/home/yuhongrui/.vscode-server",
        "/home/yuhongrui/smagrad-dtn"
    ],
    "fortran.linter.initialize": false

I really appreciate any suggestion you might have. Thanks a lot!

1 Like

@hongruiy ,

Welcome to the forum.

What happens if you “correct” the type declaration statement vis-a-vis standard Fortran syntax and have it as

type(SNES), intent(in) :: snes  !<-- note the TYPE(..); also, I presume it's INTENT(IN)

Same with your other function parameters of Vec and PetscErrorCode types.

Hey! Thank you very much for your suggestion. I managed to set the correct include directory for the library so now use petscXXX no longer generates a warning. I can now go to the definition of these modules and I can see .mod files being generated at the specified output directory. But the subroutine argument error persists.

I tried your suggestion and a new “error” would occur saying: Derived type ‘type’ at (1) is being used before it is defined.

I think the problem is that the linter is having trouble finding or generating .mod files for the library that contains the declaration of SNES and other types.

Also, I dug into the logs from VS Code and I found an error from Modern Fortran
[lint] invalid compiler version: undefined

I’m not sure if it is related to this issue at hand.

If you are using preprocessor macros as types you should define them in fortls first see docs. In the VS Code settings that should be fortran.fortls.preprocessor.definitions. This should fix the “No matching declaration found” errors.

The second types of errors you are having “Derived type of type…” is probably because of how you are importing the PETSc dependencies. In addition to the Fortran USE statement you usually have to use #include to include the definitions of PETSc variables, types, etc.

That’s strange. If you could post a bug report on GitHub for me to have a look at, that would be great.

Thank you very much for the response!

I did include them at the beginning of main program.

Thanks, this does help with types. However, these types are supplied by PETSc so it’d be hard for me to set them all up manually. I did play around with include_dirs and source_dirs and added “.h” to incl_suffixes but the language server still doesn’t seem to recognize them.

Here is the updated settings.json file:

    "fortran.fortls.maxLineLength": 132,
    "fortran.fortls.path": "/home/yuhongrui/.local/bin/fortls",
    "fortran.linter.modOutput": "${workspaceFolder}/fortran_mods",
    "fortran.linter.includePaths": [
        "/usr/lib/x86_64-linux-gnu/openmpi/include",
        "/usr/lib/x86_64-linux-gnu/openmpi/lib",
        "/usr/lib/x86_64-linux-gnu/openmpi/lib",
        "/home/yuhongrui/petsc/arch-linux-c-debug/include",
        "/home/yuhongrui/petsc/include",
        "${workspaceFolder}/fortran_mods"
    ],
    "fortran.linter.extraArgs": [
        "-Wl,-rpath,/home/yuhongrui/petsc/arch-linux-c-debug/lib",
        "-L/home/yuhongrui/petsc/arch-linux-c-debug/lib",
        "-L/usr/lib/x86_64-linux-gnu/openmpi/lib",
        "-fPIC",
        "-w",
        "-ffree-line-length-none",
        "-ffree-line-length-0",
        "-Wno-lto-type-mismatch",
        "-Wno-unused-dummy-argument",
        "-pthread",
        "-g",
        "-O0",
        "-lpetsc",
        "-lm",
        "-lmpi_usempif08",
        "-lmpi_usempi_ignore_tkr",
        "-lmpi_mpifh",
        "-lmpi"
    ],
    "fortran.fortls.preprocessor.directories": [
        "$HOME/petsc/include/petsc/finclude"
    ],
    "fortran.fortls.directories": [
        "$HOME/petsc/include/petsc/finclude"
    ],
    "fortran.fortls.suffixes": [
        ".h"
    ],
    "fortran.fortls.preprocessor.definitions": {
        "Mat": "type(tMat)",
        "Vec": "type(tVec)"
    }

The problem with using preprocessor macros as types, like you can in PETSc, is that a lot of the include files that include the macros contain relative paths relative to some root directory, that is not in your project. For PETSc that is $PETSC_DIR/$PETSC_ARCH so when fortls tries to resolve that relative link it simply fails because

! main_include.h
#include "root/includeA.h"
! includeA.h
#define SNES type(SNES)

In a directory structure like this:

root
├── main_include.h
└── includeA.h

The only easy way I can think of to solve this is to use glob patterns and include all *.h files under finclude. You can use a terminal, a .fortlsrc configuration file and --debug_parser to load options and see what the fortls preprocessor is doing.

The proper way of resolving this is with multiroot workspaces, which fortls somewhat supports, the vscode extension fully supports them, but most other code editors don’t. With multiroot workspaces you would register your project as one root, the PETSc directory as another and fortls would exchange information between the 2 roots, which is easier said than done.

1 Like