Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Error passing variables from Gnu C/C++ main to ifort F90 shared object subroutine

ergeorge
Beginner
1,017 Views

Hi Folks,
I have an F90 shared object library compiled with the Intel FORTRAN compiler - don't know what version.

I have a C++ driver compiled with the Gnu compiler (v4.4.7) which can link against the fortran library fine.

I'm trying to recompile the fortran library so I can trace through it with a debugger (and eventually to modify it).  I'm using ifort Version 16.0.0.109 Build 20150815.

However, when I attempt to run the driver with the recompiled library, I get an error passing arguments into a subroutine.  The function prototype is as follows:

subroutine set_some_params(Dir, bufSize,Mode, flag1, flag2, param1, param2, param3)
!DEC$ IF DEFINED(_WIN32)
!DEC$ ATTRIBUTES DLLEXPORT, DEFAULT, ALIAS:'set_some_params' :: set_some_params
!DEC$ ELSE
!DEC$ ATTRIBUTES ALIAS:'set_some_params' :: set_some_params
!DEC$ END IF

   implicit none
   
   character(FILEPATHLEN), intent(in) :: Dir ! directory path
   integer, value :: bufSize                    ! buffer size [5000]
   integer, value :: Mode                       ! run mode
   integer, value :: flag1                        
   integer, value :: flag2
   real(8), value :: param1
   integer, value :: param2
   integer, value :: param3

...
   

This is the first call of a fortran library function, and it crashes.  Loading the exe & core file into gdb shows the failure where the bufSize parameter is first used.

Printing the Dir variable in gdb shows the expected value, however the rest of the arguments I get the following:

(gdb) p bufSize
Cannot access memory at address 0x1388
(gdb) p Mode
Cannot access memory at address 0x0
(gdb) p flag1
Cannot access memory at address 0x0
(gdb) p flag2
Cannot access memory at address 0x0

etc.

The ifort compile command looks like this:

/usr/local/bin/ifort -D_LINUX64 -g -c -u -r8 -i4 -fPIC -fpp1 -reentrancy -threads -recursive -fopenmp ../../Source_F/some_file.f90 -o some_file.o

Which produces the following warning:
ifort: command line remark #10128: invalid value '1' for '-fpp'; ignoring

The library link line looks like this:

/usr/local/bin/ifort -D_LINUX64 -V -fPIC -shared --reentrancy -threads -recursive -fopenmp -o ../../../lib_x64/some_lib.dll ./some_file.o ./some_file2.o ./some_file3.o -L. -L/opt/intel/lib/intel64/ -i-dynamic -lifport -lifcore -limf -lsvml -lintlc

I get the following warnings here:
ifort: command line warning #10006: ignoring unknown option '-freentrancy'
ifort: command line remark #10148: option '-i-dynamic' not supported

And the -L path /opt/intel/lib/intel64/ doesn't exist on my system, but it apparently doesn't need anything there.

The C++ command line:

g++ -g -m64 driver.cc -o driver ./DllUtils.o ./DllMainDll.o -ldl -lc -lm

where DllUtils.o and DllMainDll.o are C++ object files that specify some helper functions and interfaces to the shared object library.  Sorry about the "Dll" notation - that's from the original developer.

The header file, DllUtils.h contains the following:

typedef void (STDCALL *fnPtrset_some_params)(char Dir[512], int bufSize, int Mode, int flag1, int flag2, double param1, int param2, int param3);

So to summarize - the original library works fine.  When I attempt to recompile the library using the original makefiles (modified for different path to ifort only) I get an error passing arguments.  First argument (pointer) is OK, the rest fail.

Sorry this is so vague - it's a huge project, I'm trying to extract what may be relevant here.  This is on a CentOS 6 box

0 Kudos
1 Solution
Steven_L_Intel1
Employee
1,017 Views

The VALUE behavior did change a couple of releases ago. We were incorrectly implementing it. There's an option -assume nostd_value if you want the old behavior.

If you want to use BIND(C) then you should remove the ATTRIBUTES directives entirely. But as I mentioned, the CHARACTER declaration with a length other than 1 won't be accepted. (For C interoperability, one would declare this as CHARACTER(1), DIMENSION(*)).

View solution in original post

0 Kudos
4 Replies
Steven_L_Intel1
Employee
1,017 Views

The VALUE attribute doesn't mean "pass (or accept) by value" unless the procedure also has BIND(C). 

I'd suggest the simple fix of adding BIND(C) to the Fortran routine (it goes after the argument list on the SUBROUTINE line), but then your use of CHARACTER(FILEPATHLEN) would be disallowed.

If one is willing to stray further from the standard, add "MIXED_STR_LEN_ARG,C," before "ALIAS" in both directives( and remove DEFAULT on the WIndows side). I think this will do what you want. 

0 Kudos
ergeorge
Beginner
1,017 Views

Is the BIND(C) thing something that has changed between compiler releases or such?  Because this code worked as written with a different version of the Intel fortran compiler.

When I add BIND(C) as suggested:

subroutine set_some_params(geoDir, bufSize, runMode, savePartials, isSpectr, consider, decayAlt, outCoord) BIND(C) !@ES
!DEC$ IF DEFINED(_WIN32)
!DEC$ ATTRIBUTES DLLEXPORT, DEFAULT, ALIAS:'set_some_params' :: set_some_params
!DEC$ ELSE
!DEC$ ATTRIBUTES ALIAS:'set_some_params' :: set_some_params
!DEC$ END IF

I get the following error:
error #8143: The BIND(C) attribute for this symbol conflicts with a DEC$ ATTRIBUTES ALIAS, DECORATE, CVF, C, [NO_]MIXED_STR_LEN_ARG or REFERENCE attribute for this symbol.   [SET_SOME_PARAMS]
!DEC$ ATTRIBUTES ALIAS:'set_some_params' :: set_some_params
-----------------------------------------------------------^

Thanks!
 

 

0 Kudos
Steven_L_Intel1
Employee
1,018 Views

The VALUE behavior did change a couple of releases ago. We were incorrectly implementing it. There's an option -assume nostd_value if you want the old behavior.

If you want to use BIND(C) then you should remove the ATTRIBUTES directives entirely. But as I mentioned, the CHARACTER declaration with a length other than 1 won't be accepted. (For C interoperability, one would declare this as CHARACTER(1), DIMENSION(*)).

0 Kudos
ergeorge
Beginner
1,017 Views

That did it!  The binaries I have must have been compiled with a release that used the incorrect behavior.  Using -assume nostd_value replicates it for my version of the compiler.  They'll have to modify quite a bit of code when they upgrade compilers.

Thanks for the help!

0 Kudos
Reply