Skip to content

Commit 81d477d

Browse files
authored
Merge pull request #146 from swig-fortran/bindc-constants
Improve behavior of %constant
2 parents 8044e01 + a934562 commit 81d477d

24 files changed

+626
-369
lines changed

Doc/Manual/src/Fortran.md

Lines changed: 154 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ presents some equivalent concepts and names in the two languages:
9797
| arithmetic type | intrinsic type |
9898
| derived type | extended type |
9999
| function parameters | dummy arguments |
100-
| `constexpr` variable | `parameter` statement |
100+
| `constexpr` variable | named constant |
101101

102102
## Identifiers
103103

@@ -178,7 +178,7 @@ module forexample
178178
private
179179
interface
180180
function swigc_fact(farg1) &
181-
bind(C, name="swigc_fact") &
181+
bind(C, name="_wrap_fact") &
182182
result(fresult)
183183
use, intrinsic :: ISO_C_BINDING
184184
integer(C_INT) :: fresult
@@ -557,8 +557,10 @@ constants that are guaranteed to be compatible with C enumerators. Unlike C++,
557557
all enumerators in Fortran are anonymous.
558558

559559
To associate a C enumeration name with the Fortran
560-
generated wrappers, SWIG generates an integer parameter with the C enumeration
561-
name. The enumeration generated from the C code
560+
generated wrappers, SWIG generates a named constant with the C enumeration
561+
name whose value is the size of the enum that can then be used analogously to
562+
`C_INT`, which specifies the size of the native C integer type.
563+
The enumeration generated from the C code
562564
```c++
563565
enum MyEnum {
564566
RED = 0,
@@ -575,7 +577,7 @@ looks like:
575577
enumerator :: BLUE
576578
enumerator :: BLACK = -1
577579
end enum
578-
integer, parameter :: MyEnum = kind(RED)
580+
integer, parameter, public :: MyEnum = kind(RED)
579581
```
580582

581583
These enumerators are treated as standard C integers in the C wrapper code
@@ -594,9 +596,9 @@ enum MyWeirdEnum {
594596
becomes
595597
```fortran
596598
integer(C_INT), protected, public, &
597-
bind(C, name="swigc_MyWeirdEnum_FOO") :: FOO
599+
bind(C, name="_wrap_MyWeirdEnum_FOO") :: FOO
598600
integer(C_INT), protected, public, &
599-
bind(C, name="swigc_MyWeirdEnum_BAR") :: BAR
601+
bind(C, name="_wrap_MyWeirdEnum_BAR") :: BAR
600602
integer, parameter :: MyWeirdEnum = C_INT
601603
```
602604

@@ -606,10 +608,6 @@ enable treatment of a C++ `enum` as a Fortran enumerator, and the
606608
C integers. See the section on [global constants](#global-constants) for more
607609
on this directive.
608610

609-
If an enumeration type has not been defined but is used in a function
610-
signature, a placeholder `SwigUnknownEnum` enumerator will be generated and
611-
used instead.
612-
613611
Class-scoped enumerations are prefixed with the class name:
614612
```c++
615613
struct MyStruct {
@@ -638,7 +636,7 @@ becomes
638636
enum, bind(c)
639637
enumerator :: Foo_Bar = 0
640638
end enum
641-
integer, parameter :: Foo = kind(Foo_Bar)
639+
integer, parameter, public :: Foo = kind(Foo_Bar)
642640
```
643641

644642
and
@@ -655,63 +653,153 @@ becomes
655653
enum, bind(c)
656654
enumerator :: Cls_Foo_Bar = 0
657655
end enum
658-
integer, parameter :: Cls_Foo = kind(Cls_Foo_Bar)
659-
```
656+
integer, parameter, public :: Cls_Foo = kind(Cls_Foo_Bar)
657+
```
658+
659+
## Constants
660+
661+
A constant declaration can be wrapped as a Fortran *named constant*
662+
(a compile-time value defined by having the `parameter` attribute) or as
663+
an externally linked data object. Constants can be declared with:
664+
- the SWIG `%constant` directive,
665+
- simple `#define` macros,
666+
- enum values, and
667+
- `constexpr` global variables.
668+
The last item is a SWIG-Fortran extension. For an explanation of this behavior,
669+
see the "Compatibility note" under "A brief word about const" in the SWIG
670+
documentation. Note that this list does *not* include global `const` data,
671+
which is wrapped in the same way as mutable global data (though without the
672+
setter functions).
673+
674+
- Native enum values (enum is marked `%fortranconst` or was determined
675+
automatically to be native compatible) will become enumerators.
676+
- Constants marked with `%fortranconst` will be rendered as *named constants*.
677+
- Non-native enum values become C-bound external constants.
678+
- Constants marked with `%fortranbindc` also become C-bound external
679+
constants.
680+
- All other types will generate `getter` functions that return native Fortran
681+
types.
682+
683+
Some compile-time constants can have definitions that are valid C but invalid
684+
Fortran. A macro whose definition cannot be parsed by Fortran can have its
685+
value *replaced* with a simpler expression using the `%fortranconstvalue`
686+
directive.
660687

661-
## Function pointers
688+
The following example shows the behavior of the various rules above:
689+
```swig
690+
%fortranconst fortranconst_int_global;
691+
%fortranconst fortranconst_float_global;
692+
%constant int fortranconst_int_global = 4;
693+
%constant float fortranconst_float_global = 1.23f;
694+
695+
%fortranbindc constant_int_global;
696+
%constant int constant_int_global = 4;
697+
%constant float constant_float_global = 1.23f;
698+
699+
%fortranconstvalue(4) MACRO_HEX_INT;
662700
663-
It is possible to pass function pointers both from C to Fortran and from
664-
Fortran to C using SWIG. Currently, function pointer variables
665-
simply generate opaque `type(C_FUNPTR)` objects, and it is up to the user to
666-
convert to a Fortran procedure pointer using `c_f_procpointer` and an
667-
appropriate interface.
701+
%inline %{
702+
#define MACRO_INT 4
703+
const int extern_const_int = 4;
704+
#define MACRO_HEX_INT 0x4
705+
%}
706+
```
707+
will be translated to
708+
```fortran
709+
integer(C_INT), parameter, public :: fortranconst_int_global = 4_C_INT
710+
real(C_FLOAT), parameter, public :: fortranconst_float_global = 1.23_C_FLOAT
711+
integer(C_INT), protected, public, &
712+
bind(C, name="_wrap_constant_int_global") :: constant_int_global
713+
real(C_FLOAT), protected, public, &
714+
bind(C, name="_wrap_constant_float_global") :: constant_float_global
715+
integer(C_INT), protected, public, &
716+
bind(C, name="_wrap_MACRO_INT") :: MACRO_INT
717+
public :: get_extern_const_int
718+
integer(C_INT), parameter, public :: MACRO_HEX_INT = 4_C_INT
719+
```
720+
The symbols marked as `protected, public, bind(C)` have their values defined in
721+
the C wrapper code, where *any* valid expression can be parsed. The
722+
`get_extern_const_int` wrapper function is a SWIG-generated getter that returns
723+
the external value.
668724

669-
Consider the simple C SWIG input:
725+
String constants without special characters (a backslash or anything that must
726+
be escaped with a backslash) with a can generally be represented
727+
exactly in Fortran:
670728
```swig
729+
%fortranconst MSG_STRING;
671730
%inline %{
672-
typedef int (*BinaryOp)(int, int);
731+
#define MSG_STRING "This is a string"
732+
%}
733+
```
734+
will generate
735+
```fortran
736+
character(kind=C_CHAR, len=*), parameter, public :: MSG_STRING = "This is a string"
737+
```
673738

674-
int do_op(int a, int b, BinaryOp op) {
675-
return (*op)(a, b);
676-
}
739+
## Function pointers
677740

678-
int add(int a, int b) {
679-
return a + b;
680-
}
681-
%}
741+
It is possible to pass function pointers between C and Fortran using SWIG. When
742+
wrapping, SWIG will automatically generate `abstract interface` functions and
743+
subroutines for function pointers that have ISO C-compatible signatures. It
744+
then uses those interfaces in the wrapper functions as procedure pointers.
682745

683-
%constant BinaryOp ADD_FP = add;
684-
```
746+
These abstract interfaces get default names that are not very pretty, so a
747+
`%fortrancallback` feature has been introduced to explicitly generate abstract
748+
interfaces with a meaningful name and dummy argument names
685749

686-
This generates a *wrapped* function `add`, which converts integer types and
687-
passes them through SWIG wrapper functions as pointers, and a *function
688-
pointer* `add_fp`. The wrapped function pointer is defined as a constant in the
689-
C wrapper code:
690-
```c
691-
SWIGEXPORT SWIGEXTERN BinaryOp const _wrap_ADD_FP = add;
750+
The following C++ SWIG input:
751+
```swig
752+
%fortrancallback("%s") binary_op;
753+
extern "C" {
754+
int binary_op(int left, int right);
755+
}
692756
```
693-
and made accessible through the Fortran wrapper module as
694-
```fortran
695-
type(C_FUNPTR), protected, public, &
696-
bind(C, name="_wrap_ADD_FP") :: ADD_FP
757+
generates the following interface:
758+
```
759+
abstract interface
760+
function binary_op(left, right) bind(C) &
761+
result(fresult)
762+
use, intrinsic :: ISO_C_BINDING
763+
integer(C_INT), intent(in), value :: left
764+
integer(C_INT), intent(in), value :: right
765+
integer(C_INT) :: fresult
766+
end function
767+
end interface
697768
```
698769

699-
The Fortran code in the "funptr" example demonstrates:
700-
- How to pass the C function pointer to another wrapped function `do_op` that
701-
takes a function pointer,
702-
- How to translate a C function pointer into a Fortran function pointer that
703-
can be called directly (using `c_f_procpointer` and an `abstract interface`),
704-
and
705-
- How to translate a Fortran function into a C function pointer, which can then
706-
be passed to a SWIG-wrapped function.
770+
This allows C++ functions
771+
```swig
772+
%inline %{
773+
typedef int (*binary_op_cb)(int, int);
774+
int call_binary(binary_op_cb fptr, int left, int right);
775+
%}
776+
```
777+
to generate Fortran functions that take a procedure as an argument:
778+
```
779+
function call_binary(fptr, left, right) &
780+
result(swig_result)
781+
use, intrinsic :: ISO_C_BINDING
782+
integer(C_INT) :: swig_result
783+
procedure(binary_op) :: fptr
784+
integer(C_INT), intent(in) :: left
785+
integer(C_INT), intent(in) :: right
786+
! <snip>
787+
end function
788+
```
707789

708-
Currently function pointers only work with
709-
user-created C-linkage functions, but we plan to extend
710-
function callbacks so that data can be translated through wrapper functions.
790+
Note that Fortran ISO C rules require the given procedure to be defined in
791+
Fortran using the `bind(C)` qualifier, as in this module-level code:
792+
```fortran
793+
function myexp(left, right) bind(C) &
794+
result(fresult)
795+
use, intrinsic :: ISO_C_BINDING
796+
integer(C_INT), intent(in), value :: left
797+
integer(C_INT), intent(in), value :: right
798+
integer(C_INT) :: fresult
711799
712-
Another planned extension for function pointers is to automatically generate
713-
the necessary *abstract interface* code required by Fortran to interpret the
714-
function pointer. This will allow type safety for wrapped function pointers.
800+
fresult = left ** right
801+
end function
802+
```
715803

716804
## Handles and other oddities
717805

@@ -899,58 +987,6 @@ will generate a publicly accessible C-bound variable:
899987
integer(C_INT), public, bind(C, name="global_counter_c") :: global_counter_c
900988
```
901989

902-
### Global constants
903-
904-
Global constant variables (whether declared in C++ headers with `const` or in
905-
a SWIG wrapper with `%constant`) of native types can be wrapped as Fortran
906-
"parameters" (compile-time values), as externally bound constants, or as
907-
wrapper functions that return the value.
908-
909-
The default behavior is as follows:
910-
- `%constant` and macro values are wrapped as externally bound values.
911-
- Global constants are wrapped with getter functions.
912-
- A constant can be forced to be a Fortran compile-time constant `parameter`
913-
using the `%fortranconst` directive.
914-
- A macro whose definition cannot be parsed by Fortran can have its value
915-
*replaced* with a simpler expression using the `%fortranconstvalue`
916-
directive.
917-
918-
The following example shows the behavior of the various rules above:
919-
```swig
920-
%fortranconst fortranconst_int_global;
921-
%fortranconst fortranconst_float_global;
922-
%constant int fortranconst_int_global = 4;
923-
%constant float fortranconst_float_global = 1.23f;
924-
925-
%constant int constant_int_global = 4;
926-
%constant float constant_float_global = 1.23f;
927-
928-
%fortranconstvalue(4) MACRO_HEX_INT;
929-
930-
%inline %{
931-
#define MACRO_INT 4
932-
const int extern_const_int = 4;
933-
#define MACRO_HEX_INT 0x4
934-
%}
935-
```
936-
will be translated to
937-
```fortran
938-
public :: get_extern_const_int
939-
integer(C_INT), parameter, public :: fortranconst_int_global = 4_C_INT
940-
real(C_FLOAT), parameter, public :: fortranconst_float_global = 1.23_C_FLOAT
941-
integer(C_INT), protected, public, &
942-
bind(C, name="_wrap_constant_int_global") :: constant_int_global
943-
real(C_FLOAT), protected, public, &
944-
bind(C, name="_wrap_constant_float_global") :: constant_float_global
945-
integer(C_INT), protected, public, &
946-
bind(C, name="_wrap_MACRO_INT") :: MACRO_INT
947-
integer(C_INT), parameter, public :: MACRO_HEX_INT = 4_C_INT
948-
```
949-
The symbols marked as `protected, public, bind(C)` have their values defined in
950-
the C wrapper code, where *any* valid expression can be parsed. The
951-
`get_extern_const_int` wrapper function is a SWIG-generated getter that returns
952-
the external value.
953-
954990
## Classes
955991

956992
C++ classes are transformed to Fortran *derived types*. These types have
@@ -1941,6 +1977,14 @@ To bind *all* functions as native C interfaces, use
19411977
This is often useful when coupled with the `%fortranconst` directive (see
19421978
the [enumerations](#enumerations) section).
19431979

1980+
### Function pointers and callbacks
1981+
1982+
The `%callback` feature is redundant and ignored for `%fortranbindc` types: a
1983+
valid function pointer to the C function can be obtained simply with the
1984+
`c_funptr` intrinsic function. Any `%fortrancallback` directives in the code
1985+
will still generate abstract interfaces, but they will simply supplement the
1986+
direct-bound C code
1987+
19441988
### Generating C-bound Fortran types from C structs
19451989

19461990
In certain circumstances, C++ structs can be wrapped natively as Fortran
@@ -2014,7 +2058,7 @@ module thinvec
20142058
end type
20152059
interface
20162060
subroutine swigc_foo(farg1) &
2017-
bind(C, name="swigc_foo")
2061+
bind(C, name="_wrap_foo")
20182062
use, intrinsic :: ISO_C_BINDING
20192063
import :: SwigArrayWrapper ! Will not compile without this line
20202064
type(SwigArrayWrapper) :: farg1
@@ -2066,3 +2110,5 @@ void should_be_wrapped(UnknownType*);
20662110

20672111
A number of known limitations to the SWIG Fortran module are tracked [on
20682112
GitHub](https://github.com/sethrj/swig/issues/59).
2113+
2114+
<!-- vim: set tw=79: -->

Examples/fortran/bare/example.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,28 @@ void print_cmyk(CmykEnum color);
5252
/* -------------------------------------------------------------------------
5353
* Global variables
5454
* ------------------------------------------------------------------------- */
55+
#if __cplusplus >= 201103
56+
#define CONSTEXPR constexpr
57+
#elif defined(SWIG)
58+
#define CONSTEXPR %constant
59+
#else
60+
#define CONSTEXPR const
61+
#endif
5562

5663
//! An integer that is only known at link time
5764
extern const int linked_const_int;
5865

5966
//! A simple integer
60-
const int simple_int = 4;
67+
CONSTEXPR int simple_int = 4;
6168

6269
// A more complicated integer
63-
const int weird_int = (0x1337 | 0x10000);
70+
CONSTEXPR int weird_int = (0x1337 | 0x10000);
6471

6572
//! A global constant wrapped as a native parameter
66-
const double approx_pi = 3.14160000001;
73+
CONSTEXPR double approx_pi = 3.14160000001;
6774

6875
//! A global constant wrapped as a protected external variable
69-
const double approx_twopi = 2 * approx_pi;
76+
CONSTEXPR double approx_twopi = 2 * approx_pi;
7077

7178
//! A global variable
7279
namespace foo {

0 commit comments

Comments
 (0)