as/400: call C procedure from CL - module

The as/400 ILE allows procedures from different languages to be compiled into modules, then bound together to make a single program. I'm trying to accomplish this with a module containing a C function being called from my CL module which is the entry module.
The C module source:
mylib/myfile/csource
int getValue(void){
return 20;
}
The CL module source: mylib/myfile/clsource
pgm
dcl var(&NUM) type(*INT)
callprc prc(getValue) rtnval(&NUM) /* <== Calling C function. */
endpgm
Then I compile each file into their own module.
crtcmod module(cmodule) srcfile(myfile) srcmbr(csource)
crtclmod module(clmodule) srcfile(myfile) srcmbr(clsource)
These two compile, no problem.
Only, when I try to create a program from these two modules, the ILE binder complains that the function getValue in the CL source is undefined and the program creation fails.
crtpgm pgm(mypgm) module(clmodule cmodule) entmod(clmodule) detail(*basic)
The error that crtpgm gives me:
Unresolved references........................: 1
Symbol Type Library Object Linked Name
*MODULE mylib clmodule *YES getValue
What am I missing?

The CL language is case insensitive...
Actually, an unquoted string in CL is implicitly upper-cased.
However, C is case sensitive. You'll need to quote the procedure name
callprc prc('getValue') rtnval(&NUM)

Related

Fortran link modules for precision and global variable types

I am new to Fortran and trying to understand if the following is possible. My idea to structure the program is to declare the precision and variable types in one module. Then make use of those variables without declaring again the type in other modules or the main program.
module pre
implicit none
INTEGER, PARAMETER :: sp=SELECTED_REAL_KIND(6,37)
INTEGER, PARAMETER :: dp=SELECTED_REAL_KIND(15,307)
INTEGER, PARAMETER :: qp=SELECTED_REAL_KIND(33,4931)
REAL(dp), PARAMETER :: pi = 4.*ATAN(1.)
REAL(dp) :: H
REAL(dp) :: M
REAL(dp) :: KR
end module pre
Now I want to make use of all the variables in another module that contains one or more functions, such as:
module hon
use pre
implicit none
contains
function KE(H,M) result(KR)
KR = 2*PI/H/M
end function KE
end module hon
Then I use gfortran in this order:
gfortran -c mod_pre.f90
gfortran -c mod_hon.f90
Since 'module pre' is part of 'module hon' I compile in order, but gfortran shows an error.
With the code above I understand the variable types and parameters should have been included by USE; But the message I get from gfortran is that none of my variables have IMPLICIT type when I try to compile 'module hon'.
Could somebody clarify the problem or suggest a solution? I would like to avoid having my variables scattered in multiple modules.
Thanks!
In the function statement, the result(kr) says that the function result has name kr. This function result is not the same thing as the module variable kr. In particular, this function result makes inaccessible the module variable.
The function result is specific to the function itself and its properties must be declared within the function subprogram.
Similarly, the dummy arguments of the function, H and M, are distinct from the module variables and need to be declared in the function subprogram.
Beyond that, you perhaps have similar concerns to this other question.
To be clear, it isn't possible to say something like "all function results called kr and all dummy arguments called H or M have these characteristics". Each individual object must be given the properties.
However, although I don't recommend this, this is a situation where literal text inclusion (using a preprocessor or include file) could help you:
function ke(H, M) result (kr)
include 'resdummydecls'
...
end function
where the file has the declarations.

Calling C dll from Fortran

How to call C DLL from Fortran? I don't code in Fortran but I need to do some testing on it.
Let say in the test.dll have functions:
Open()
Close()
How can I tell Fortran to use the test.dll?
I mean like C# we may use
[DllImport("test.dll")]
static extern uint Open();
I could not find any example that can help me. I would also prefer if you could provide a compiler that you use.
Update
I use Plato compiler.
I tried to load test.dll using this method. However, it popped up error message saying Error 29, Call to missing routine: _LOADLIBRARY
Here is the code. I found it online. So not sure if I'm doing it correctly.
program test
integer :: p
pointer :: q
p = loadlibrary ("test.dll"C) ! the C at the end says -
! add a null byte as in C
q = getprocaddress (p, "Open"C)
end
EDIT
Sorry. The DLL is using C and not C++

FORTRAN DLL calling convention from MapleSim / Modelica

Modelica modeling language supports calling functions from external FORTRAN DLLs, however, MapleSim only includes the support of calling functions from C DLLs even though it says it has full support for the Modelica language, and I have no choice but to use this FORTRAN DLL (I can't reprogram it in C nor I can use other Modelica evironments than MapleSim), so I'm not in the undocumented features realm.
I tried forcing MapleSim to include the FORTRAN DLL and created a custom component but its not working. This is the code I got when I opened the custom component: [relevant portion only]
model ExternalCode
function GETPSAT
input Real TC;
output Real PC;
external "C" PC = GETPSAT(TC)
annotation (
Library = "C:/Path/To/My/DLL/FORTRAN.dll", __Maplesoft_callconv = "stdcall");
end GETPSAT;
equation
(PC) = GETPSAT(TC);
annotation (
experiment(__Maplesoft_engine = 2));
end ExternalCode;
I know I should change external "C" to external "FORTRAN", but what should I should I do with __Maplesoft_callconv = "stdcall"? ie: what is the call convention for FORTRAN functions? (I know nothing on the subject of calling conventions).
Note the parent evnironment of MapleSim 6.1 (Maple 17) supports importing external functions from FORTRAN so I think there is a possibility MapleSim will support it despite it being undocumented.
edit: By the way, the DLL was compiled with Compaq visual fortran (I don't remember the version)
edit2: The function in the FORTRAN DLL is exported as follows:
FUNCTION GETPSAT(TC)
!DEC$ ATTRIBUTES ALIAS:'GETPSAT' :: GETPSAT
!DEC$ ATTRIBUTES DLLEXPORT :: GETPSAT
!DEC$ ATTRIBUTES VALUE :: TC
GETPSAT=PSAT11(TC)
RETURN
END
edit3: I don't know it this helps, but the same function can be called from C# like this:
[DllImport("C:\\Path\\To\\My\\DLL\\FORTRAN.dll")]
static extern float GETPSAT(float T);
This particular Fortran function should behave like a completely normal C function because of the attributes it has. Do not add any external(FORTRAN) or similar. Its name should be GETPSAT and it accepts 1 float TC by value.
Use the same "stdcal" attribute, it is default for the DEC, Compaq and Intel Fortran https://software.intel.com/sites/products/documentation/hpc/mkl/mkl_userguide_win/GUID-E74229B0-7389-46A6-9FCF-91CD6CD5B0E4.htm

Linking fortran module: "undefined reference"

I'm trying to write some functions/subroutines in a module that call another function in the same module and running into linker errors. A toy example displaying the same behavior:
!in test.f
module m1
implicit none
contains
real function mult(a, b)
real :: a
real :: b
mult = a * b
return
end function mult
real function sq(a)
real :: a, mult
sq = mult(a, a)
return
end function sq
end module m1
program main
use m1
write(*,*) sq(2.0)
end program
When I try to compile this, I run into trouble:
[christopher#archlinux metropolis]$ gfortran -ffree-form test.f
/tmp/ccpzdTLE.o: In function `__m1_MOD_sq':
test.f:(.text+0x20): undefined reference to `mult_'
collect2: error: ld returned 1 exit status
On the other hand, compiling only (gfortran -c -ffree-form test.f -Wall) runs with no complaint.
Now this looks for all the world like a compiler error---in the module it comes up with a reference to mult_ when it really ought to com up with __m1_MOD_sq---but I have a very hard time believing that this is a compiler bug rather than me doing something stupid.
DDG didn't turn up anything useful. Most of the similar problems ocurred in splitting the module off from one main file. In those cases, things worked when the module was in the same file as the program, which is not the case here. I looked at a number of pages on modules in Fortran and didn't see anything relevant.
Can anyone point me to appropriate documentation or, better yet, explain what's going on and how I can fix it?
You don't need to declare function mult in function sq, i.e., there is no need for "real :: mult". sq already "knows" about mult since it is in the same module. The interface of mult is known to sq since they are in the same module. The interface of mult and sq are known to the main program since it uses the module. Having both the module providing the interface and the declaration is confusing the compiler.

why do omp functions not work when constants are declared in a module?

i have a module 'gvars' defined for my global variable declarations. when i define
integer :: nthreads, max_threads, tid, omp_get_max_threads, omp_get_num_threads, omp_get_thread_num inside of my gvars module, the call maxthreads = omp_get_max_threads() in my main routine gives me the following error upon compilation:
maxthreads = omp_get_max_threads()
1
Error: Unclassifiable statement at (1)
but when i include the integer :: definitions above inside my main routine, it compiles just fine and gives me the desired results. if i even go as far as to define nthreads = -1 inside my gvars module, i am able to print out the correct value in my main routine so i know it is being included and defined correctly, it's just that for some reason i cannot have it as a return value from openmp functions.
why would this be?
is there any other way to keep these values as global variables and still define them in my main routine instead of a module?
if it matters, i am using gfortran to compile
The problem is not with the declaration of maxthreads, but with the declaration, on the same line, of omp_get_max_threads. As haraldkl showed, you need to use omp_lib instead, to automatically get access to the declarations of these functions.
(If for some reason you really don't want to do it that way, you can also add the statement external :: omp_get_max_threads, ... to the module.)
Not really an answer, but I do not know how else to put the code in here. Sorry...
module gvars
integer :: maxthreads
end module gvars
program test
use gvars
use omp_lib
implicit none
maxthreads = omp_get_max_threads()
end program test
compiled with:
gfortran -fopenmp test.f90
Where gfotran -v gives:
gcc version 4.4.5 (GCC)