Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The document describes how to generate a LinkableComponent on Linux:

  • how to compile a shared library for a Fortran engine named <engine>
  • how to port a C# wrapper for this shared library from Windows to Linux. The wrapper contains a class for accessing the Fortran Dll <engine>DllAccess and two outer classes <engine>DotNetAccess and <engine>Wrapper.

...

Panel
bgColor#F7D6C1
borderStyledashed

ifort -c -fPIC -convert big_endian -fpp *.f90
-c : compile to object (.o) only, do not link
-fPIC : generate position independent code (for shared libs)
-convert big_endian: the order in which a sequence of bytes is stored in a computer's memory,
here: most significant bytes first;
used, e.g. on mainframes and supercomputers.
-fpp : run Fortran preprocessor on source files prior to compilation

...

Panel
bgColor#F7D6C1
borderStyledashed

ifort -shared *.o -o <sharedLibrary.so>

...

Panel
bgColor#F7D6C1
borderStyledashed

export LD_LIBRARY_PATH=/opt/intel/fce/9.1.051/lib:. // on 64bit systems
export LD_LIBRARY_PATH=/opt/intel/fc/9.1.051/lib:. // on 32bit systems

2.2. Ifort parameter bug

...

The ifort compiler v. 9.1.051 has a bug with public character parameters in modules.
Example:

...


...

CHARACTER (LEN=40), PUBLIC, PARAMETER :: c_att_name(2)= &
/ 'title ', &
'history '/

The ifort compiler v. 9.1.051 has a bug with public character parameters in modules.

Panel
bgColor#F7D6C1
borderStyledashed

The parameter c_att_name can not be accessed from outside the module. The solution is a function that exports the parameter as a return value. Now the values can be accessed from outside.

Panel
bgColor#F7D6C1
borderStyledashed

PUBLIC FUNCTION get_c_att_name ( idx ) &
   RESULT(res)
...
CHARACTER (LEN=40) :: res
res = c_att_name(idx)
END FUNCTION get_c_att_name

...

  • <engine>DllAccess.cs is the inner layer;
  • <engine>DotNetAccess.cs;
  • <engine>Wrapper.cs is a LinkableComponent and the outer layer.

Compilation of the two inner layers:

Panel
bgColor#F7D6C1
borderStyledashed

gmcs -target:library -out: <engine>DotNetAccess.dll <engine>DllAccess.cs
<engine>DotNetAccess.cs

Compilation of the outer layer:

Panel
bgColor#F7D6C1
borderStyledashed

gmcs -target:library -out:<engine>Wrapper.dll -pkg:baw-geidotnet.pc,
openmi-backbone.pc,openmi-devsupport.pc,openmi-spatial.pc,
openmi-standard.pc,openmi-wrapper.pc *.cs
-pkg: <name>.pc file (path and name) with information about a referenced shared library

3.2. Changes from Windows to Linux

Fortunately, the original Windows C#-Code can remain nearly as it is.

3.2.1. Changes in <engine>DllAccess.cs

Most part of the original Windows code remains unchanged, as displayed in the example, where the Fortran method component_id_len returns
comp_id_len.

Panel
bgColor#F7D6C1
borderStyledashed

[DllImport(
@"gei.xe.so",
EntryPoint = "gei_ui_mp_gei_component_id_len_",
SetLastError=true,
ExactSpelling = true,
CallingConvention=CallingConvention.Cdecl) ]
public static extern bool gei_component_id_len(
ref int comp_id_len );

  • changed shared library name "gei.xe.so"
  • EntryPoint method has lower cases and a final underscore:
    "gei_ui_mp_gei_out_exch_quant_id_"

Some more adjustments are necessary, if a Fortran method returns a character string:

Panel
bgColor#F7D6C1
borderStyledashed

[ DllImport( @"gei.xe.so",
EntryPoint = "gei_ui_mp_gei_out_exch_quant_id_",
SetLastError=true,
ExactSpelling = true,
CallingConvention=CallingConvention.Cdecl) ]
public static extern bool gei_out_exch_quant_id(
ref int compIdx,
ref int outExchangeItemN,
Out byte[] quantId,
uint lengthId);

  • Out byte[] quantId

The return of Fortran character strings (unmanaged code) to C# (managed Code) may cause a problem. Several guidelines recommend to marshall a variable of type StringBuilder:

Panel
bgColor#F7D6C1
borderStyledashed

MarshalAs(UnmanagedType.LPStr) StringBuilder quantId

But StringBuilder may very rarely lead to variables with undefined return values. It is not clear why this happens. The Mono guidelines display a slightly different case, where the Fortran part frees memory to early, http://www.mono-project.com/Interop_with_Native_LibrariesImage Added, paragraph "GC-Safe P/Invoke code"
However, during the tests the byte variables were always returned correctly.

3.2.2.Changes in <engine>DotNetAccess.cs

The example displays that the byte array from 3.2.1. is externally encoded to the string str:

Panel
bgColor#F7D6C1
borderStyledashed

public string OutputExchangeQuantityId(int compIdx, int outputExchangeN)
{
byte[] quantId = new byte[ QuantityIdLen()];
// increment counter because array indices start in C# with 0
// whereas in Fortran with 1
int n1 = outputExchangeN + 1;
if(!(GEIDllAccess.gei_out_exch_quant_id
(ref compIdx,
ref n1,
quantId,
(uint) QuantityIdLen() )))
{
CreateAndThrowException ( );
}
string str = Encoding.ASCII.GetString (quantId);
return str.Trim();
}

Furthermore the Initialize method of this class is a good place for a check, whether the dll is running on Mono or not:

Panel
bgColor#F7D6C1
borderStyledashed

if ( Type.GetType ("Mono.Runtime") == null )
{
throw new Exception("this version of BAW.OpenMI.GEIDotNet.dll is only meant for use on Linux and Mono");
}