Skip to content

Commit b8170d5

Browse files
committed
Clean up, simplify, improve %constant usage
Make it more consistent with other swig languages
1 parent 6f200f9 commit b8170d5

File tree

7 files changed

+197
-150
lines changed

7 files changed

+197
-150
lines changed

Doc/Manual/src/Fortran.md

Lines changed: 80 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,86 @@ end enum
656656
integer, parameter, public :: Cls_Foo = kind(Cls_Foo_Bar)
657657
```
658658

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.
687+
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;
700+
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.
724+
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:
728+
```swig
729+
%fortranconst MSG_STRING;
730+
%inline %{
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+
```
738+
659739
## Function pointers
660740

661741
It is possible to pass function pointers between C and Fortran using SWIG. When
@@ -907,69 +987,6 @@ will generate a publicly accessible C-bound variable:
907987
integer(C_INT), public, bind(C, name="global_counter_c") :: global_counter_c
908988
```
909989

910-
### Constants
911-
912-
A constant declaration can be wrapped as a Fortran *named constant*
913-
(a compile-time value defined by having the `parameter` attribute), as
914-
an externally linked data object, or as a wrapper function that returns the
915-
value as a native Fortran datatype. Constants can be declared with:
916-
- The SWIG `%constant` directive,
917-
- Simple `#define` macros, and
918-
- `constexpr` global variables.
919-
The last item is a SWIG-Fortran extension. For an explanation of this behavior,
920-
see the "Compatibility note" under "A brief word about const" in the SWIG
921-
documentation.
922-
923-
All global `const` variables will be treated as regular global variables: they
924-
will be wrapped with getter functions. SWIG-declared `%constant`s whose
925-
data types cannot be [directly represented](#direct-c-binding) will be wrapped
926-
with getter functions. Constants marked with the `%fortranconst` directive are
927-
wrapped as Fortran module-level named constants. If declaring a C-linkage
928-
`%constant`, it is directly exposed to Fortran using `bind(C)`. Otherwise, a
929-
const global wrapper variable will be created in the C wrapper code and `bound`
930-
in the Fortran module.
931-
932-
Some compile-time constants can have definitions that are valid C but invalid
933-
Fortran. A macro whose definition cannot be parsed by Fortran can have its
934-
value *replaced* with a simpler expression using the `%fortranconstvalue`
935-
directive.
936-
937-
The following example shows the behavior of the various rules above:
938-
```swig
939-
%fortranconst fortranconst_int_global;
940-
%fortranconst fortranconst_float_global;
941-
%constant int fortranconst_int_global = 4;
942-
%constant float fortranconst_float_global = 1.23f;
943-
944-
%constant int constant_int_global = 4;
945-
%constant float constant_float_global = 1.23f;
946-
947-
%fortranconstvalue(4) MACRO_HEX_INT;
948-
949-
%inline %{
950-
#define MACRO_INT 4
951-
const int extern_const_int = 4;
952-
#define MACRO_HEX_INT 0x4
953-
%}
954-
```
955-
will be translated to
956-
```fortran
957-
integer(C_INT), parameter, public :: fortranconst_int_global = 4_C_INT
958-
real(C_FLOAT), parameter, public :: fortranconst_float_global = 1.23_C_FLOAT
959-
integer(C_INT), protected, public, &
960-
bind(C, name="_wrap_constant_int_global") :: constant_int_global
961-
real(C_FLOAT), protected, public, &
962-
bind(C, name="_wrap_constant_float_global") :: constant_float_global
963-
integer(C_INT), protected, public, &
964-
bind(C, name="_wrap_MACRO_INT") :: MACRO_INT
965-
public :: get_extern_const_int
966-
integer(C_INT), parameter, public :: MACRO_HEX_INT = 4_C_INT
967-
```
968-
The symbols marked as `protected, public, bind(C)` have their values defined in
969-
the C wrapper code, where *any* valid expression can be parsed. The
970-
`get_extern_const_int` wrapper function is a SWIG-generated getter that returns
971-
the external value.
972-
973990
## Classes
974991

975992
C++ classes are transformed to Fortran *derived types*. These types have

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 {

Examples/fortran/bare/example.i

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,29 @@
55
#include "example.h"
66
%}
77

8-
//! A const integer
9-
// const int param_int = 4;
10-
// const int wrapped_int = 0x1337;
8+
#ifdef SWIGFORTRAN
9+
// Force constants to be a compile-time native fortran parameter
10+
%fortranconst param_const;
11+
%fortranconst MY_SPECIAL_NUMBERS;
12+
%fortranconst approx_pi;
13+
%fortranconst so_excited;
14+
// Force constants to be defined in C++ but can be directly referenced in Fortran as link-time immutable variables
15+
%fortranbindc octal_const;
16+
%fortranbindc wrapped_const;
17+
%fortranbindc weird_int;
18+
#endif
1119

20+
21+
// Compile-time/link-time constants
1222
#define MY_SPECIAL_NUMBERS 5
1323
%constant int param_const = 911;
1424
%constant int octal_const = 0777;
1525
%constant int wrapped_const = 0xdeadbeef;
16-
17-
// Force a constant to be a compile-time native fortran parameter
18-
%fortranconst approx_pi;
19-
20-
#ifdef SWIGFORTRAN
26+
%constant so_excited = "wheee";
2127

2228
// Ignore one of the functions that can't be overloaded correctly
2329
%ignore cannot_overload(int);
2430

25-
#endif
26-
2731
%include "example.h"
2832

2933

Examples/fortran/bare/runme.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ subroutine test_consts()
5353
write(STDOUT, *) "pi is approximately ", approx_pi
5454
write(STDOUT, *) "2pi is approximately ", get_approx_twopi()
5555
write(STDOUT, *) "extern const int is ", get_linked_const_int()
56+
write(STDOUT, *) so_excited
5657
! Can't assign these
5758
! wrapped_const = 2
5859
! MY_SPECIAL_NUMBERS = 4

Examples/fortran/funcptr/runme.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ program fortran_funptr_runme
3131
integer(C_INT) :: b = 3
3232
procedure(binary_op), pointer :: fptr => null()
3333

34-
call c_f_procpointer(add, fptr)
34+
fptr => get_ADD()
3535
write(STDOUT,*) "SWIG-wrapped C function pointer:", do_op(a, b, fptr)
36-
call c_f_procpointer(sub, fptr)
36+
fptr => get_SUB()
3737
write(STDOUT,*) "SWIG-wrapped C function pointer:", do_op(a, b, fptr)
38-
call c_f_procpointer(mul, fptr)
38+
fptr => get_MUL()
3939
write(STDOUT,*) "SWIG-wrapped C function pointer:", do_op(a, b, fptr)
4040

4141
! Convert Fortran function to C function pointer

Examples/test-suite/fortran/fortran_callback_runme.F90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ subroutine test_callback
6161
bin_op_ptr => get_a_callback("mul")
6262
ASSERT(associated(bin_op_ptr))
6363
ASSERT(bin_op_ptr(2, 5) == 10)
64+
! Get from the %callback-generated wrapper
65+
bin_op_ptr => get_mul_cb()
66+
ASSERT(associated(bin_op_ptr))
67+
ASSERT(bin_op_ptr(2, 5) == 10)
6468

6569
bin_op_ptr => get_a_callback("add")
6670
ASSERT(associated(bin_op_ptr))

0 commit comments

Comments
 (0)