Table of contents
Table of Contents |
---|
1. Introduction
The document describes how to generate a LinkableComponent on Linux:
- how to compile a shared library for a Fortran 90 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
...
2. Technical prerequisites
2.1. Machine and OS of the test system
- workstation with an Intel Xeon processor
- 64bit Suse Linux Edition Desktop SLED 10.3 on the machine with the Fortran compiler
- 64bit openSUSE 11.0 on the machine with the C# compiler
2.2. Mono for multi platform C#
- Mono v. 1.9.1. for openSUSE 11.0 in 64 bit mode. V. 1.9.1. is the concrete term, but it is also referred to as Mono 2.0.
- compiler gmcs 2.0.
2.3. Fortran 90 Compiler
- Intel 64 bit Fortran Compiler v. 9.1.051
...
3. How to generate a shared library for a Fortran engine
...
3.1. General
During runtime the C# wrapper could refers only reference one Fortran shared library. All Fortran sources were compiled to one shared library with the following compiler options <fortranEngine>.so: Compilation:
Panel | ||||
---|---|---|---|---|
| ||||
ifort -c -fPIC -convert big_endian -fpp *.f90 |
...
Panel | ||||
---|---|---|---|---|
| ||||
ifort -shared *.o -o <sharedLibrary<fortranEngine.so>*.o |
During runtime some fortran libraries must be accessible via the environment variable LD_LIBRARY_PATH. In the following examples they are provided by the ifort compiler:.
Panel | ||||
---|---|---|---|---|
| ||||
export LD_LIBRARY_PATH=/opt/intel/fce/9.1.051/lib:. // on 64bit systems |
...
3.2. Ifort parameter bug
The ifort compiler v. 9.1.051 has a bug with public character parameters in modules.
Example:
Panel | ||||
---|---|---|---|---|
| ||||
CHARACTER (LEN=40), PUBLIC, PARAMETER :: c_att_name(2)= & |
The ifort compiler v. 9.1.051 has a bug with public character parameters in modules.
...
bgColor | #F7D6C1 |
---|---|
borderStyle | dashed |
The parameter c_att_name can not easily be accessed from outside the modulean external Fortran method. But if a Mono C# application calls a Fortran method, that accesses c_att_name, it will crash without error message. The solution is a Fortran function, that exports the parameter as a return value. Now the values can be accessed from outsideC#.
Panel | ||||
---|---|---|---|---|
| ||||
PUBLIC FUNCTION get_c_att_name ( idx ) & |
3.3. Fortran interface functions
The <fortranEngine>.so interface functions are the same as in Windows Fortran. The two example functions are part of the module gei_ui and will be accessed from C# in 4.2.1.. The first one returns the integer comp_id_len.
Panel | ||||
---|---|---|---|---|
| ||||
FUNCTION gei_component_id_len ( comp_id_len ) RESULT( ok ) |
The second example returns the character string comp_id.
Panel | ||||
---|---|---|---|---|
| ||||
FUNCTION gei_component_id ( comp_idx, comp_id ) RESULT( ok ) |
4. How to port a C# wrapper from Windows to Linux
...
4.1. General
The Mono Guidelines Interop with Native Libaries gives general information about the interface between managed and unmanaged code.
The wrapper has three layers:
- <engine>DllAccess.cs is the inner
...
- class for accessing the Fortran dll;
- <engine>DotNetAccess.cs references <engine>DllAccess.cs;
- <engine>Wrapper.cs is a LinkableComponent and the outer layer.
Compilation of the two inner layers:
Panel | ||||
---|---|---|---|---|
| ||||
gmcs -target:library -out: <engine>DotNetAccess.dll <engine>DllAccess.cs |
Compilation of the outer layer:
Panel | ||||
---|---|---|---|---|
| ||||
gmcs -target:library -out:<engine>Wrapper.dll -pkg:baw-geidotnet.pc, |
...
4.2.
...
How to port the individual layers
Fortunately, the original Windows C# -Code code can nearly remain nearly as it is.
...
4.2.1.
...
<engine>DllAccess.cs
Most part of the original Windows code remains unchanged, as displayed in the example, where the Fortran method <engine>DllAccess offers access to the Fortran shared library, e.g. @"gei.xe.so". The most of the Windows C# code remains unchanged and is displayed in black colour in the following example. The Fortran module gei_ui, method gei_component_id_len returns
the integer comp_id_len.
Panel | ||||
---|---|---|---|---|
| ||||
[DllImport(
|
Some more adjustments are necessary, if a Fortran method returns a the character string quantId:
Panel | ||||
---|---|---|---|---|
| ||||
[ DllImport( |
[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 in order to return a Fortran character string:
Panel | ||||
---|---|---|---|---|
| ||||
[MarshalAs(UnmanagedType.LPStr)] StringBuilder quantId |
But on Linux systems StringBuilder may can 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 Mono garbage collector frees memory to early, http://www.mono-project.com/Interop_with_Native_Libraries, before the character string is returned, s. paragraph "GC-Safe P/Invoke code".
However, during the tests the byte variables the variables of type [Out] byte[ ] were always returned correctly and it is recommended to use them on Linux. The StringBuilder remains the better solution for Windows .NET. Developers are invited to find a solution that works on Windows as well as on Linux, e.g.
...
an additional C / C++ wrapper or a SWIG generated wrapper.
4.2.2.
...
<engine>DotNetAccess.cs
...
Methods accessing int variables, e.g. ComponentIdLen(), remain unchanged from Windows:
Panel | ||||
---|---|---|---|---|
| ||||
public int ComponentIdLen() return compIdLen; |
This The example displays that the variable of type byte array [ ] from 34.2.1. is externally encoded to the string str:
Panel | ||||
---|---|---|---|---|
| ||||
public string OutputExchangeQuantityId(int compIdx, int outputExchangeN) } |
Furthermore, the Initialize method of this class is a good place for a check, whether the dll is running on Mono or not:
Panel | ||||
---|---|---|---|---|
| ||||
if ( Type.GetType ("Mono.Runtime") == null ) |
4.2.3. <engine>Wrapper.cs
There are no changes compared to Windows C#.
5. Use of the LinkableComponent
Before using the LinkableComponent its location must be known by Linux. It is recommended to put all shared libraries <fortranEngine>.so, <engine>DotNetAccess.dll and <engine>Wrapper.dll in one directory <componentDir>.
Panel | ||||
---|---|---|---|---|
| ||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<componentDir> |
Now the generated LinkableComponent can be connected to any other LinkableComponent. Adding it as a model to the Linux version of the ConfigurationEditor is an easy test, s. How to port the OpenMI from Windows to Linux.