diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3e3ba489..56d487ad 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,51 +8,71 @@ list(APPEND tests arrays arrays_fixed arrays_in_derived_types_issue50 + auto_raise_error class_names cylinder + decoded_strings + default_i8 + derived-type-aliases derivedtypes + derivedtypes_procedure + docstring + dump_package elemental + errorbinding example2 extends + fixed_1D_derived_type_array_argument + fortran_oo + intent_out_size interface issue105_function_definition_with_empty_lines + issue206_subroutine_oldstyle + issue227_allocatable + issue235_allocatable_classes + issue254_getter + issue258_derived_type_attributes + issue261_array_shapes + issue297_ignored_abstract_classes + issue301_complex_types + issue302_pointer_warning + issue305_multiple_abstract_interfaces + issue307_logical_array issue32 + keep_single_interface + keyword_renaming_issue160 + kind_map_default + long_subroutine_name + method_optional mockderivetype mod_arg_clash + name_collision optional_args_issue53 optional_derived_arrays + optional_string + output_kind passbyreference + recursive_type_array + relative_import + remove_pointer_arg + return_array + return_bool + signature_vs_backend + string_array_input_f2py strings + subroutine_args subroutine_contains_issue101 type_bn - kind_map_default - docstring - return_array - intent_out_size - string_array_input_f2py type_check - optional_string - long_subroutine_name - output_kind - remove_pointer_arg - fortran_oo - issue254_getter - issue258_derived_type_attributes - issue206_subroutine_oldstyle - issue227_allocatable - issue235_allocatable_classes - issue297_ignored_abstract_classes - issue305_multiple_abstract_interfaces - auto_raise_error - dump_package - method_optional - relative_import - decoded_strings - keep_single_interface - return_bool - issue307_logical_array ) +# TODO: Fix these failing examples +# callback_print_function_issue93 # undefined symbol: pyfunc_print_ +# f2py_string_input # undefined symbol: string_in_array_ (linking issue) +# issue41_abstract_classes # AttributeError: 'myclass_t' object has no attribute 'get_value' +# issue299_directc_nested_functions# types.py shadows stdlib types module +# recursive_type # Error: Derived type 'node' at (1) has not been declared + foreach(test ${tests}) message(STATUS "Adding test ${test}") add_test( diff --git a/examples/Makefile b/examples/Makefile index 18ef3325..92f069aa 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,56 +1,73 @@ include make.inc -EXAMPLES = arrayderivedtypes \ - arrays \ - arrays_fixed \ - arrays_in_derived_types_issue50 \ - class_names \ - cylinder \ - derivedtypes \ - elemental \ - example2 \ - extends \ - interface \ - issue105_function_definition_with_empty_lines \ - issue32 \ - keyword_renaming_issue160 \ - mockderivetype \ - mod_arg_clash \ - name_collision \ - optional_args_issue53 \ - optional_derived_arrays \ - passbyreference \ - strings \ - subroutine_contains_issue101 \ - type_bn \ - docstring \ - type_check \ - derivedtypes_procedure \ - return_array \ - string_array_input_f2py \ - optional_string \ - long_subroutine_name \ - kind_map_default \ - intent_out_size \ - output_kind \ - remove_pointer_arg \ - fortran_oo \ - issue254_getter \ - issue258_derived_type_attributes \ - issue206_subroutine_oldstyle \ - issue227_allocatable \ - issue235_allocatable_classes \ - issue297_ignored_abstract_classes \ - issue305_multiple_abstract_interfaces \ - issue306_allocatable_realloc \ - auto_raise_error \ - dump_package \ - method_optional \ - relative_import \ - decoded_strings \ - keep_single_interface \ - return_bool \ - issue307_logical_array +EXAMPLES = \ + arrayderivedtypes \ + arrays \ + arrays_fixed \ + arrays_in_derived_types_issue50 \ + auto_raise_error \ + class_names \ + cylinder \ + decoded_strings \ + default_i8 \ + derived-type-aliases \ + derivedtypes \ + derivedtypes_procedure \ + docstring \ + dump_package \ + elemental \ + errorbinding \ + example2 \ + extends \ + fixed_1D_derived_type_array_argument \ + fortran_oo \ + intent_out_size \ + interface \ + issue105_function_definition_with_empty_lines \ + issue206_subroutine_oldstyle \ + issue227_allocatable \ + issue235_allocatable_classes \ + issue254_getter \ + issue258_derived_type_attributes \ + issue261_array_shapes \ + issue297_ignored_abstract_classes \ + issue301_complex_types \ + issue302_pointer_warning \ + issue305_multiple_abstract_interfaces \ + issue307_logical_array \ + issue32 \ + keep_single_interface \ + keyword_renaming_issue160 \ + kind_map_default \ + long_subroutine_name \ + method_optional \ + mockderivetype \ + mod_arg_clash \ + name_collision \ + optional_args_issue53 \ + optional_derived_arrays \ + optional_string \ + output_kind \ + passbyreference \ + recursive_type_array \ + relative_import \ + remove_pointer_arg \ + return_array \ + return_bool \ + signature_vs_backend \ + string_array_input_f2py \ + strings \ + subroutine_args \ + subroutine_contains_issue101 \ + type_bn \ + type_check + +# TODO: Fix these failing examples +# callback_print_function_issue93 \ # undefined symbol: pyfunc_print_ +# f2py_string_input \ # undefined symbol: string_in_array_ (linking issue) +# issue41_abstract_classes \ # AttributeError: 'myclass_t' object has no attribute 'get_value' +# issue299_directc_nested_functions \# types.py shadows stdlib types module +# recursive_type \ # Error: Derived type 'node' at (1) has not been declared DIRECTC ?= no diff --git a/examples/errorbinding/tests.py b/examples/errorbinding/tests.py new file mode 100644 index 00000000..51b99211 --- /dev/null +++ b/examples/errorbinding/tests.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Minimal test for errorbinding example - verifies the module can be imported and used.""" + +import ExampleDerivedTypes + +# Create a type with procedure +obj = ExampleDerivedTypes.Datatypes.typewithprocedure() + +# Call init method +obj.init(a=1.0, n=5) + +# Call info method (writes to stdout) +obj.info(lun=6) + +print("OK: errorbinding test passed") diff --git a/examples/errorbinding/tests_pkg.py b/examples/errorbinding/tests_pkg.py new file mode 100644 index 00000000..f9ea57da --- /dev/null +++ b/examples/errorbinding/tests_pkg.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Minimal test for errorbinding example (package mode) - verifies the module can be imported and used.""" + +import ExampleDerivedTypes_pkg + +# Create a type with procedure +obj = ExampleDerivedTypes_pkg.datatypes.typewithprocedure() + +# Call init method +obj.init(a=1.0, n=5) + +# Call info method (writes to stdout) +obj.info(lun=6) + +print("OK: errorbinding package test passed") diff --git a/examples/fixed_1D_derived_type_array_argument/Makefile b/examples/fixed_1D_derived_type_array_argument/Makefile index 14c8d739..aa1963ae 100644 --- a/examples/fixed_1D_derived_type_array_argument/Makefile +++ b/examples/fixed_1D_derived_type_array_argument/Makefile @@ -9,4 +9,5 @@ wrap : python : f2py-f90wrap $(F2PYFLAGS) -c -m _test_python f90wrap_functions.f90 *.o clean : - rm -f *.o *.mod *.so f90wrap* test_python.py build + rm -f *.o *.mod *.so f90wrap* test_python.py + rm -rf build/ diff --git a/f90wrap/f90wrapgen.py b/f90wrap/f90wrapgen.py index 92bdfa6f..707f17d6 100644 --- a/f90wrap/f90wrapgen.py +++ b/f90wrap/f90wrapgen.py @@ -765,6 +765,9 @@ def visit_Procedure(self, node): self.write("subroutine %s%s" % (sub_name, arg_names)) self.indent() self.write_uses_lines(node) + # Add iso_c_binding when we have derived type arguments (handle arrays use c_int) + if node.transfer_in or node.transfer_out: + self.write("use, intrinsic :: iso_c_binding, only: c_int") self.write("implicit none") if node.mod_name is None: @@ -881,6 +884,7 @@ def _write_sc_array_wrapper(self, t, el, dims, sizeof_fortran_t): self.write_type_or_class_lines(t.orig_name) self.write("integer(c_int), intent(in) :: this(%d)" % sizeof_fortran_t) self.write("type(%s_ptr_type) :: this_ptr" % t.orig_name) + # Module-level arrays do not need dummy_this declaration (issue #306) self.write("integer(c_int), intent(out) :: nd") self.write("integer(c_int), intent(out) :: dtype") @@ -1048,6 +1052,8 @@ def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset): owner_module = self._type_owner(el.type, getattr(t, "mod_name", getattr(t, "name", None))) self._add_extra_use(extra_uses, owner_module, None) self.write_uses_lines(el, extra_uses) + # Add iso_c_binding for handle arrays (c_int is immune to -fdefault-integer-8) + self.write("use, intrinsic :: iso_c_binding, only: c_int") self.write("implicit none") self.write() @@ -1062,7 +1068,7 @@ def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset): self.write_type_or_class_lines(el.type, same_type, pointer=True) if this is not None: - self.write("integer, intent(in) :: %s(%d)" % (this, sizeof_fortran_t)) + self.write("integer(c_int), intent(in) :: %s(%d)" % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write("type(%s_ptr_type) :: this_ptr" % t.name) array_name = self._get_type_member_array_name(t, el.name) @@ -1070,7 +1076,7 @@ def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset): array_name = shorten_long_name("%s_%s" % (t.name, el.name)) self.write("integer, intent(in) :: %s" % (safe_i)) self.write( - "integer, intent(%s) :: %s(%d)" + "integer(c_int), intent(%s) :: %s(%d)" % (inout, el.name + "item", sizeof_fortran_t) ) if not same_type: @@ -1184,6 +1190,8 @@ def _write_array_len(self, t, el, sizeof_fortran_t): owner_module = self._type_owner(el.type, getattr(t, "mod_name", getattr(t, "name", None))) self._add_extra_use(extra_uses, owner_module, None) self.write_uses_lines(el, extra_uses) + # Add iso_c_binding for handle arrays (c_int is immune to -fdefault-integer-8) + self.write("use, intrinsic :: iso_c_binding, only: c_int") self.write("implicit none") self.write() if "super-type" in t.doc: @@ -1196,7 +1204,7 @@ def _write_array_len(self, t, el, sizeof_fortran_t): self.write_type_or_class_lines(el.type, same_type) self.write("integer, intent(out) :: %s" % (safe_n)) if this is not None: - self.write("integer, intent(in) :: %s(%d)" % (this, sizeof_fortran_t)) + self.write("integer(c_int), intent(in) :: %s(%d)" % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write("type(%s_ptr_type) :: this_ptr" % t.name) self.write() @@ -1291,6 +1299,9 @@ def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): self.indent() self.write_uses_lines(el, extra_uses) + # Add iso_c_binding for handle arrays (c_int is immune to -fdefault-integer-8) + if isinstance(t, ft.Type) or ft.is_derived_type(el.type): + self.write("use, intrinsic :: iso_c_binding, only: c_int") self.write("implicit none") if isinstance(t, ft.Type): @@ -1300,7 +1311,7 @@ def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): self.write_type_or_class_lines(el.type, pointer=True) if isinstance(t, ft.Type): - self.write("integer, intent(in) :: this(%d)" % sizeof_fortran_t) + self.write("integer(c_int), intent(in) :: this(%d)" % sizeof_fortran_t) self.write("type(%s_ptr_type) :: this_ptr" % t.orig_name) # Return/set by value @@ -1313,7 +1324,7 @@ def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): if ft.is_derived_type(el.type): # For derived types elements, treat as opaque reference self.write( - "integer, intent(%s) :: %s(%d)" % (inout, localvar, sizeof_fortran_t) + "integer(c_int), intent(%s) :: %s(%d)" % (inout, localvar, sizeof_fortran_t) ) self.write( diff --git a/f90wrap/transform.py b/f90wrap/transform.py index 39856bf6..0558049d 100644 --- a/f90wrap/transform.py +++ b/f90wrap/transform.py @@ -534,7 +534,7 @@ def convert_derived_type_arguments(tree, init_lines, sizeof_fortran_t): arg.attributes if attr.startswith('intent')] typename = ft.strip_type(arg.type) - arg.wrapper_type = 'integer' + arg.wrapper_type = 'integer(c_int)' arg.wrapper_dim = sizeof_fortran_t sub.types.add(typename)