Difference between revisions of "H2O"
Ivan denisov (talk | contribs) |
(→Linux: removed /usr/bin from calling oo2c and added sudo (did not work on a recent Debian 9 otherwise)) |
||
(19 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
H2O — is the tool for making [[Oberon]] and [[Component Pascal]] import modules from C header files. | H2O — is the tool for making [[Oberon]] and [[Component Pascal]] import modules from C header files. | ||
= Intro and Credits = | |||
H2O (Header to Oberon) is a tool for creating Oberon interface modules from C-Header files for foreign libraries. It has been created by Stewart Greenhill around 2001 for use with the Optimizing Oberon Compiler OOC/oo2c, which in turn has been created by Michael van Acken end of the 1990. Ability to create interface modules for Component Pascal has been implemented by Bernhard Treutwein end of 2006 and fed back into the cvs tree at sourceforge by Stewart Greenhill in March, 2007. | |||
= Installation = | = Installation = | ||
H2O sources distributed with [[oo2c]] compiler. | The H2O sources are distributed with [[oo2c]] compiler. The oo2c compiler is/must be used for building H2O. | ||
== Linux == | == Linux == | ||
1. Download | 1. Download binary distribution and install it: https://sourceforge.net/projects/ooc/files/ooc2/2.1.11/ | ||
./configure | |||
sudo make install | |||
2. Download last sources from: https://github.com/Spirit-of-Oberon/oo2c | |||
git clone https://github.com/Spirit-of-Oberon/oo2c | |||
3. Compile last version of '''oo2c''' from repository: | |||
cd oo2c | cd oo2c | ||
make cvsclean | |||
./configure | |||
./ | . ENV | ||
make $OOC_DEV_ROOT/oo2crc-install.xml | |||
sudo make install | oo2c -M --config oo2crc-install.xml oo2c | ||
sudo make install BOOTSTRAP_COMPILER=bin/oo2c | |||
4. Compilation of H2O | |||
oo2c -M src/TestH2O.Mod | oo2c -M src/TestH2O.Mod | ||
Line 36: | Line 46: | ||
There are a couple of modes in which H2O can work. | There are a couple of modes in which H2O can work. | ||
* With arguments "-cp" it is producing Component Pascal output. | |||
* With arguments "--preprocess" it just preprocesses source, outputting tokenised symbols (not very useful). | * With arguments "--preprocess" it just preprocesses source, outputting tokenised symbols (not very useful). | ||
* With arguments "--preprocess --text" it preprocesses source, outputting text. | * With arguments "--preprocess --text" it preprocesses source, outputting text. | ||
* Without arguments, it translates "C" definitions, producing Oberon-2 output. | * Without arguments, it translates "C" definitions, producing Oberon-2 output. | ||
== Processing C source code == | == Processing C source code == | ||
There are few C files ready for trial usage in the folder with [[ | There are few C files ready for trial usage in the folder with [[oo2c]] sources. | ||
cd tests/h2o | cd tests/h2o | ||
Line 51: | Line 62: | ||
{| class="wikitable" style="width: 100%; text-valign: top" | {| class="wikitable" style="width: 100%; text-valign: top" | ||
! | ! Name | ||
! C | ! C (sources) | ||
! Oberon | ! Oberon-2 (output) | ||
|- valign="top" | |- valign="top" | ||
| width=" | | width="6%" | mod.h | ||
| width=" | | width="47%" | | ||
typedef int T; | typedef int T; | ||
typedef int * pT; | typedef int * pT; | ||
| width=" | | width="47%" | | ||
MODULE mod [ INTERFACE "C" ]; | MODULE mod [ INTERFACE "C" ]; | ||
Line 68: | Line 79: | ||
END mod. | END mod. | ||
|- valign="top" | |- valign="top" | ||
| test | | test.c | ||
| | | | ||
#include "mod.h" | #include "mod.h" | ||
Line 173: | Line 184: | ||
== Processing with outer H2O directive == | == Processing with outer H2O directive == | ||
Directive file have structure: | |||
H2O { | |||
... translation options here ... | |||
} | |||
#include "topLevelFile" | |||
If we want to translate '''test.c''' from previous example we would make '''test.h2o''' that looks like this: | |||
H2O { | H2O { | ||
.. | OPTIONS { | ||
MapChar = "SHORTCHAR"; | |||
MapShort = "SHORTINT"; | |||
MapLong = "INTEGER"; | |||
MapLongLong = "LONGINT"; | |||
MapFloat = "SHORTREAL"; | |||
MapDouble = "REAL"; | |||
MapPointer = "ANYPTR"; | |||
} | |||
MODULE "test" { | |||
LinkLib = "libtest.so"; | |||
} | |||
MODULE "mod" { | |||
LinkLib = "libmod.so"; | |||
} | |||
} | } | ||
#include "test.c" | #include "test.c" | ||
To initiate the translation you would do: | To initiate the translation you would do: | ||
TestH2O test.h2o | TestH2O misc/test.h2o | ||
For making of Component Pascal import modules we can use key '''-cp'''. | |||
TestH2O -cp misc/test.h2o | |||
{| class="wikitable" style="width: 100%; text-valign: top" | |||
! Name | |||
! C (sources) | |||
! Component Pascal (output) | |||
|- valign="top" | |||
| width="6%" | mod.h | |||
| width="47%" | | |||
typedef int T; | |||
typedef int * pT; | |||
| width="47%" | | |||
MODULE mod [ "libmod.so" ]; | |||
IMPORT SYSTEM; | |||
TYPE | |||
T* = INTEGER; | |||
pT* = POINTER TO ARRAY [untagged] OF INTEGER; | |||
END mod. | |||
|- valign="top" | |||
| test.c | |||
| | |||
#include "mod.h" | |||
typedef T t1; | |||
pT pt1; | |||
int i1; | |||
short int i2; | |||
long int i3; | |||
unsigned int i4; | |||
unsigned short int i5; | |||
unsigned long int i6; | |||
unsigned u; | |||
short s; | |||
long l; | |||
char c; | |||
int * pi; | |||
int ** ppi; | |||
int f1(int x, int y); | |||
int * f2(int x, int y); | |||
int (* f3)(int x, int y); | |||
void f4 (void); | |||
void f5 (int, int, ...); | |||
int ai []; | |||
int * aai1 [3][3]; | |||
int (* aai2) [3][3]; | |||
struct A { | |||
int a:1; | |||
int b; | |||
} sA1; | |||
struct A sA2; | |||
struct A * psA; | |||
struct A * (* next)(struct A * p); | |||
enum B { a=1, b, c } e1; | |||
typedef unsigned long long I; | |||
I i7; | |||
volatile I i8; | |||
volatile I i9, * const i10; | |||
int a[sizeof(int)]; | |||
| | |||
MODULE test [ "libtest.so" ]; | |||
IMPORT SYSTEM, mod; | |||
CONST | |||
(* Constants occurring in enumeration 'B' *) | |||
a* = 1; | |||
b* = 2; | |||
c* = 3; | |||
TYPE | |||
A_tag* = RECORD [untagged] | |||
a* : INTEGER; | |||
b* : INTEGER; | |||
END; | |||
B_tag* = INTEGER (* enumerated type *); | |||
AutoPtrA_tag* = POINTER TO A_tag; | |||
t1* = mod.T; | |||
I* = HUGEINT; | |||
VAR | |||
pt1* : mod.pT; | |||
i1* : INTEGER; | |||
i2* : SHORTINT; | |||
i3* : INTEGER; | |||
i4* : INTEGER; | |||
i5* : INTEGER; | |||
i6* : INTEGER; | |||
u* : INTEGER; | |||
s* : SHORTINT; | |||
l* : INTEGER; | |||
c* : SHORTCHAR; | |||
pi* : POINTER TO ARRAY [untagged] OF INTEGER; | |||
ppi* : POINTER TO ARRAY [untagged] OF | |||
POINTER TO ARRAY [untagged] OF INTEGER; | |||
f3* : PROCEDURE(x : INTEGER; y : INTEGER) : INTEGER; | |||
ai* : ARRAY [untagged] OF INTEGER; | |||
aai1* : ARRAY [untagged] 3 OF ARRAY [untagged] 3 OF | |||
POINTER TO ARRAY [untagged] OF INTEGER; | |||
aai2* : POINTER TO ARRAY [untagged] 3 OF | |||
ARRAY [untagged] 3 OF INTEGER; | |||
sA1* : A_tag; | |||
sA2* : A_tag; | |||
psA* : POINTER TO A_tag; | |||
next* : PROCEDURE(p : AutoPtrA_tag) : AutoPtrA_tag; | |||
e1* : B_tag; | |||
i7* : I; | |||
i8* : I; | |||
i9* : I; | |||
i10* : POINTER TO ARRAY [untagged] OF I; | |||
a* : ARRAY [untagged] 4 OF INTEGER; | |||
PROCEDURE f1* (x : INTEGER; y : INTEGER) : INTEGER; | |||
PROCEDURE f2* (x : INTEGER; y : INTEGER) : mod.pT; | |||
PROCEDURE f4* (); | |||
PROCEDURE f5* (p0 : INTEGER; p1 : INTEGER); | |||
END test. | |||
|} | |||
For included modules, the | For included modules, the behavior depends on the type of include. If you do: | ||
#include <mod.h> | #include <mod.h> | ||
it looks in the search path specified by the Include option. If you do: | it looks in the search path specified by the Include option. If you do: | ||
Line 234: | Line 396: | ||
Each "VARIANT" directive specifies how to translate particular symbols. As you would know, there are many ways of interpreting C declarations, and the default rules don't always work. For example: | Each "VARIANT" directive specifies how to translate particular symbols. As you would know, there are many ways of interpreting C declarations, and the default rules don't always work. For example: | ||
f(char * arg); | |||
could be: | could be: | ||
PROCEDURE f (arg : POINTER TO ARRAY OF CHAR); | |||
PROCEDURE f (arg : ARRAY OF CHAR); | |||
PROCEDURE f (VAR arg : ARRAY OF CHAR); | |||
PROCEDURE f (VAR arg : CHAR); | |||
So VARIANT directives allow you to place particular interpretations on the "C" declarations. Normally, you can see some specific patterns, but it varies from API to API. | So VARIANT directives allow you to place particular interpretations on the "C" declarations. Normally, you can see some specific patterns, but it varies from API to API. | ||
Line 251: | Line 413: | ||
Strings or symbols use OOC's regexp string format. Basically, ".*" matches an string of characters, "$" matches the end of a string, and "[]" matches one of a set of characters. | Strings or symbols use OOC's regexp string format. Basically, ".*" matches an string of characters, "$" matches the end of a string, and "[]" matches one of a set of characters. | ||
Examples: | ===Examples:=== | ||
"gl.*v$".params : ARRAY; | |||
This means any symbol (here, procedure) starting with "gl" and ending with "v" has its "params" parameter interpreted as an array. | This means any symbol (here, procedure) starting with "gl" and ending with "v" has its "params" parameter interpreted as an array. | ||
"gl.*Matrix[fd]$"[0] : ARRAY; | |||
This means any symbol starting with "gl" and ending with "Matrixf" or "Matrixd" has its first parameter interpreted as an array. | This means any symbol starting with "gl" and ending with "Matrixf" or "Matrixd" has its first parameter interpreted as an array. | ||
"String$" : CSTRING POINTER; | |||
This means that the type "String" is to be interpreted as a POINTER to a C string (in OOC, it assigns the "CSTRING" attribute to the pointer, which means that you can use a string literal or CHAR array for this type). | This means that the type "String" is to be interpreted as a POINTER to a C string (in OOC, it assigns the "CSTRING" attribute to the pointer, which means that you can use a string literal or CHAR array for this type). | ||
"glutInit$".argcp : VAR; | |||
This means that the "argcp" parameter of function "glutInit" is to be treated as a VAR parameter. | This means that the "argcp" parameter of function "glutInit" is to be treated as a VAR parameter. | ||
"cvRelease[^D].*$"[0] : VAR; | |||
This means that symbols starting "cvRelease" followed by any character EXCEPT "D" has its first parameter interpreted as a VAR parameter. | This means that symbols starting "cvRelease" followed by any character EXCEPT "D" has its first parameter interpreted as a VAR parameter. | ||
== Complex examples == | |||
[[Media:Interfaces.tar.gz]] |
Latest revision as of 16:26, 5 November 2019
H2O — is the tool for making Oberon and Component Pascal import modules from C header files.
Intro and Credits
H2O (Header to Oberon) is a tool for creating Oberon interface modules from C-Header files for foreign libraries. It has been created by Stewart Greenhill around 2001 for use with the Optimizing Oberon Compiler OOC/oo2c, which in turn has been created by Michael van Acken end of the 1990. Ability to create interface modules for Component Pascal has been implemented by Bernhard Treutwein end of 2006 and fed back into the cvs tree at sourceforge by Stewart Greenhill in March, 2007.
Installation
The H2O sources are distributed with oo2c compiler. The oo2c compiler is/must be used for building H2O.
Linux
1. Download binary distribution and install it: https://sourceforge.net/projects/ooc/files/ooc2/2.1.11/
./configure sudo make install
2. Download last sources from: https://github.com/Spirit-of-Oberon/oo2c
git clone https://github.com/Spirit-of-Oberon/oo2c
3. Compile last version of oo2c from repository:
cd oo2c make cvsclean ./configure . ENV make $OOC_DEV_ROOT/oo2crc-install.xml oo2c -M --config oo2crc-install.xml oo2c sudo make install BOOTSTRAP_COMPILER=bin/oo2c
4. Compilation of H2O
oo2c -M src/TestH2O.Mod sudo cp bin/TestH2O /usr/bin/TestH2O
Windows
H2O can be run on windows with Cygwin.
The example of built distribution you can find here.
Usage
There are a couple of modes in which H2O can work.
- With arguments "-cp" it is producing Component Pascal output.
- With arguments "--preprocess" it just preprocesses source, outputting tokenised symbols (not very useful).
- With arguments "--preprocess --text" it preprocesses source, outputting text.
- Without arguments, it translates "C" definitions, producing Oberon-2 output.
Processing C source code
There are few C files ready for trial usage in the folder with oo2c sources.
cd tests/h2o TestH2O misc/test.c
The results will be two files: mod.Mod and test.Mod.
Name | C (sources) | Oberon-2 (output) |
---|---|---|
mod.h |
typedef int T; typedef int * pT; |
MODULE mod [ INTERFACE "C" ]; IMPORT SYSTEM; TYPE T* = LONGINT; pT* = POINTER TO ARRAY OF LONGINT; END mod. |
test.c |
#include "mod.h" typedef T t1; pT pt1; int i1; short int i2; long int i3; unsigned int i4; unsigned short int i5; unsigned long int i6; unsigned u; short s; long l; char c; int * pi; int ** ppi; int f1(int x, int y); int * f2(int x, int y); int (* f3)(int x, int y); void f4 (void); void f5 (int, int, ...); int ai []; int * aai1 [3][3]; int (* aai2) [3][3]; struct A { int a:1; int b; } sA1; struct A sA2; struct A * psA; struct A * (* next)(struct A * p); enum B { a=1, b, c } e1; typedef unsigned long long I; I i7; volatile I i8; volatile I i9, * const i10; int a[sizeof(int)]; |
MODULE test [ INTERFACE "C" ]; IMPORT SYSTEM, mod; CONST (* Constants occurring in enumeration 'B' *) a* = 1; b* = 2; c* = 3; TYPE A_tag* = RECORD a* : LONGINT; b* : LONGINT; END; B_tag* = LONGINT (* enumerated type *); AutoPtrA_tag* = POINTER TO A_tag; t1* = mod.T; I* = HUGEINT; VAR pt1* : mod.pT; i1* : LONGINT; i2* : INTEGER; i3* : LONGINT; i4* : LONGINT; i5* : INTEGER; i6* : LONGINT; u* : LONGINT; s* : INTEGER; l* : LONGINT; c* : CHAR; pi* : POINTER TO ARRAY OF LONGINT; ppi* : POINTER TO ARRAY OF POINTER TO ARRAY OF LONGINT; f3* : PROCEDURE(x : LONGINT; y : LONGINT) : LONGINT; ai* : ARRAY OF LONGINT; aai1* : ARRAY 3 OF ARRAY 3 OF POINTER TO ARRAY OF LONGINT; aai2* : POINTER TO ARRAY 3 OF ARRAY 3 OF LONGINT; sA1* : A_tag; sA2* : A_tag; psA* : POINTER TO A_tag; next* : PROCEDURE(p : AutoPtrA_tag) : AutoPtrA_tag; e1* : B_tag; i7* : I; i8* : I; i9* : I; i10* : POINTER TO ARRAY OF I; a* : ARRAY 4 OF LONGINT; PROCEDURE f1* (x : LONGINT; y : LONGINT) : LONGINT; PROCEDURE f2* (x : LONGINT; y : LONGINT) : mod.pT; PROCEDURE f4* (); PROCEDURE f5* (p0 : LONGINT; p1 : LONGINT); END test. |
Processing with outer H2O directive
Directive file have structure:
H2O { ... translation options here ... } #include "topLevelFile"
If we want to translate test.c from previous example we would make test.h2o that looks like this:
H2O { OPTIONS { MapChar = "SHORTCHAR"; MapShort = "SHORTINT"; MapLong = "INTEGER"; MapLongLong = "LONGINT"; MapFloat = "SHORTREAL"; MapDouble = "REAL"; MapPointer = "ANYPTR"; } MODULE "test" { LinkLib = "libtest.so"; } MODULE "mod" { LinkLib = "libmod.so"; } } #include "test.c"
To initiate the translation you would do:
TestH2O misc/test.h2o
For making of Component Pascal import modules we can use key -cp.
TestH2O -cp misc/test.h2o
Name | C (sources) | Component Pascal (output) |
---|---|---|
mod.h |
typedef int T; typedef int * pT; |
MODULE mod [ "libmod.so" ]; IMPORT SYSTEM; TYPE T* = INTEGER; pT* = POINTER TO ARRAY [untagged] OF INTEGER; END mod. |
test.c |
#include "mod.h" typedef T t1; pT pt1; int i1; short int i2; long int i3; unsigned int i4; unsigned short int i5; unsigned long int i6; unsigned u; short s; long l; char c; int * pi; int ** ppi; int f1(int x, int y); int * f2(int x, int y); int (* f3)(int x, int y); void f4 (void); void f5 (int, int, ...); int ai []; int * aai1 [3][3]; int (* aai2) [3][3]; struct A { int a:1; int b; } sA1; struct A sA2; struct A * psA; struct A * (* next)(struct A * p); enum B { a=1, b, c } e1; typedef unsigned long long I; I i7; volatile I i8; volatile I i9, * const i10; int a[sizeof(int)]; |
MODULE test [ "libtest.so" ]; IMPORT SYSTEM, mod; CONST (* Constants occurring in enumeration 'B' *) a* = 1; b* = 2; c* = 3; TYPE A_tag* = RECORD [untagged] a* : INTEGER; b* : INTEGER; END; B_tag* = INTEGER (* enumerated type *); AutoPtrA_tag* = POINTER TO A_tag; t1* = mod.T; I* = HUGEINT; VAR pt1* : mod.pT; i1* : INTEGER; i2* : SHORTINT; i3* : INTEGER; i4* : INTEGER; i5* : INTEGER; i6* : INTEGER; u* : INTEGER; s* : SHORTINT; l* : INTEGER; c* : SHORTCHAR; pi* : POINTER TO ARRAY [untagged] OF INTEGER; ppi* : POINTER TO ARRAY [untagged] OF POINTER TO ARRAY [untagged] OF INTEGER; f3* : PROCEDURE(x : INTEGER; y : INTEGER) : INTEGER; ai* : ARRAY [untagged] OF INTEGER; aai1* : ARRAY [untagged] 3 OF ARRAY [untagged] 3 OF POINTER TO ARRAY [untagged] OF INTEGER; aai2* : POINTER TO ARRAY [untagged] 3 OF ARRAY [untagged] 3 OF INTEGER; sA1* : A_tag; sA2* : A_tag; psA* : POINTER TO A_tag; next* : PROCEDURE(p : AutoPtrA_tag) : AutoPtrA_tag; e1* : B_tag; i7* : I; i8* : I; i9* : I; i10* : POINTER TO ARRAY [untagged] OF I; a* : ARRAY [untagged] 4 OF INTEGER; PROCEDURE f1* (x : INTEGER; y : INTEGER) : INTEGER; PROCEDURE f2* (x : INTEGER; y : INTEGER) : mod.pT; PROCEDURE f4* (); PROCEDURE f5* (p0 : INTEGER; p1 : INTEGER); END test. |
For included modules, the behavior depends on the type of include. If you do:
#include <mod.h>
it looks in the search path specified by the Include option. If you do:
#include "mod.h"
it looks in the same directory as the file that does the #include.
The "OPTIONS" directive is global to the translation, and includes things like:
- OutputDirectory — where to put the generated module files
- Include — list of paths to get include files
- Exclude — list of files to not include (#include ignored)
- AutoPrefix — prefix for auto-generated type names (default "Auto")
- TagSuffix — suffix to be added to structure tags (default "_tag")
- RenameProcedures — when set to "1" (the default) renames procedures using module "StripPrefix" specification.
- RenameVariables — when set to "1" (default is "0", since this is unsupported in OOC V2) renames variables using module "StripPrefix" specification.
- ModuleSuffix — suffix for module file names (default "Mod").
In this section, you can also specify the type mappings for scalar types:
OPTION symbol C type Default output type ---------------------------------------------------------------- MapChar "char" "CHAR" MapUnsignedChar "unsigned char" "CHAR" MapShort "short" "INTEGER" MapUnsignedShort "unsigned short" "INTEGER" MapLong "long" "LONGINT" MapUnsignedLong "unsigned long" "LONGINT" MapLongLong "long long" "HUGEINT" MapUnsignedLongLong "unsigned long long" "HUGEINT" MapFloat "float" "REAL" MapDouble "double" "LONGREAL" MapLongDouble "long double" "LONGDOUBLE" MapPointer "void *" "SYSTEM.PTR" MapEnum "enum ..." "LONGINT" MapVoid "void" "C_VOID"
Each "MODULE" directive controls how to treat the named module. The base module name comes from the name of the corresponding ".h" file. Options per module include:
- OutputName — Output name for this module (defaults to header name)
- StripPrefix — list of prefixes to be removed from symbol names
- LinkLib, LinkFile, LinkFramework — specifies libraries, files and frameworks to link to this module (OOC-specific directive)
- Prolog — "C" definitions to be processed at the start of this module
- Epilog — "C" definitions to be processed at the end of this module
- Merge — when set to "1", causes all files included by this module to be declared within this module, rather than in separate modules.
Each "VARIANT" directive specifies how to translate particular symbols. As you would know, there are many ways of interpreting C declarations, and the default rules don't always work. For example:
f(char * arg);
could be:
PROCEDURE f (arg : POINTER TO ARRAY OF CHAR); PROCEDURE f (arg : ARRAY OF CHAR); PROCEDURE f (VAR arg : ARRAY OF CHAR); PROCEDURE f (VAR arg : CHAR);
So VARIANT directives allow you to place particular interpretations on the "C" declarations. Normally, you can see some specific patterns, but it varies from API to API.
The format of variants is a form of designator. The designators are composed of:
- strings — which match the names of globally declared objects
- [n] — which matches item <n> in a compound type or parameter list
- ^ — which matches the item referenced by a pointer type
- .symbol — which matches a named item in a type or paramter list
Strings or symbols use OOC's regexp string format. Basically, ".*" matches an string of characters, "$" matches the end of a string, and "[]" matches one of a set of characters.
Examples:
"gl.*v$".params : ARRAY;
This means any symbol (here, procedure) starting with "gl" and ending with "v" has its "params" parameter interpreted as an array.
"gl.*Matrix[fd]$"[0] : ARRAY;
This means any symbol starting with "gl" and ending with "Matrixf" or "Matrixd" has its first parameter interpreted as an array.
"String$" : CSTRING POINTER;
This means that the type "String" is to be interpreted as a POINTER to a C string (in OOC, it assigns the "CSTRING" attribute to the pointer, which means that you can use a string literal or CHAR array for this type).
"glutInit$".argcp : VAR;
This means that the "argcp" parameter of function "glutInit" is to be treated as a VAR parameter.
"cvRelease[^D].*$"[0] : VAR;
This means that symbols starting "cvRelease" followed by any character EXCEPT "D" has its first parameter interpreted as a VAR parameter.