Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

How to solve using different types of name-mangling

Hewei_S_
New Contributor I
1,378 Views

I am trying to use IMSL library and NLopt library in the same program written in Fortran. However, the names of the subroutines in the IMSL library are written in upper case letters and the names of the subroutines in NLopt are written with lower case letters. 

So I tried the following:

1. Compile with /names:lowercase

2. Compile with /names:uppercase

If I use option 1, then the subroutines in IMSL cannot be linked properly. Similarly, if I use option 2, then the subroutines in NLopt cannot be linked. I searched around and people say that this can be solved with ISO C BINDING. However, I still cannot figure this out after a few tries. Can you please help me resolve this issue? 

Thank you!

0 Kudos
1 Solution
mecej4
Honored Contributor III
1,378 Views

The NLopt DLL was built to be used with the MINGW version of Gfortran under Windows. Below I give information on how you can build an IFort-compatible import library for the DLL. I tested the example problem with the the 32-bit IFort compiler, and it ran fine. However, you may run into (i) more problems when you build code that calls IMSL in addition (ii) calling convention mismatches between IFort and GFortran.

  • Using the DEF file that is provided with the NLopt DLL as a basis, build a modified version with the pattern below:
  • Build the import library using the modified DEF file rather than the original DEF file
  • Make a copy of the DLL and call the copy NLOPT32.DLL

The contents of the DEF file:

LIBRARY nlopt32.dll
EXPORTS
NLO_ADD_EQUALITY_CONSTRAINT=nlo_add_equality_constraint
NLO_ADD_EQUALITY_MCONSTRAINT=nlo_add_equality_mconstraint
NLO_ADD_INEQUALITY_CONSTRAINT=nlo_add_inequality_constraint
NLO_ADD_INEQUALITY_MCONSTRAINT=nlo_add_inequality_mconstraint
NLO_COPY=nlo_copy
NLO_CREATE=nlo_create
NLO_DESTROY=nlo_destroy

---etc.---

The commands to use in an IFort command window:

lib /def:nlopt32.def /machine:i386
copy libnlopt-0.dll nlopt32.dll
ifort example.f funcs.f nlopt32.lib

 

View solution in original post

0 Kudos
8 Replies
mecej4
Honored Contributor III
1,379 Views

The NLopt DLL was built to be used with the MINGW version of Gfortran under Windows. Below I give information on how you can build an IFort-compatible import library for the DLL. I tested the example problem with the the 32-bit IFort compiler, and it ran fine. However, you may run into (i) more problems when you build code that calls IMSL in addition (ii) calling convention mismatches between IFort and GFortran.

  • Using the DEF file that is provided with the NLopt DLL as a basis, build a modified version with the pattern below:
  • Build the import library using the modified DEF file rather than the original DEF file
  • Make a copy of the DLL and call the copy NLOPT32.DLL

The contents of the DEF file:

LIBRARY nlopt32.dll
EXPORTS
NLO_ADD_EQUALITY_CONSTRAINT=nlo_add_equality_constraint
NLO_ADD_EQUALITY_MCONSTRAINT=nlo_add_equality_mconstraint
NLO_ADD_INEQUALITY_CONSTRAINT=nlo_add_inequality_constraint
NLO_ADD_INEQUALITY_MCONSTRAINT=nlo_add_inequality_mconstraint
NLO_COPY=nlo_copy
NLO_CREATE=nlo_create
NLO_DESTROY=nlo_destroy

---etc.---

The commands to use in an IFort command window:

lib /def:nlopt32.def /machine:i386
copy libnlopt-0.dll nlopt32.dll
ifort example.f funcs.f nlopt32.lib

 

0 Kudos
Hewei_S_
New Contributor I
1,378 Views

Hi mecej4 thank you for your reply! I rebuilt the .lib file according to your way to modify the .def. file. The new .lib file works fine in a program that only uses NLopt and I do not need to add compiler option /names:lowercase anymore. However, when I am using both IMSL and NLopt, the program compiles without any problem but it cannot run. When I run the program, it will give an "access violation" error and then stops. I think maybe there is some conflict between two libraries or there is a bug in my code. But thank you anyway!

 

mecej4 wrote:

The NLopt DLL was built to be used with the MINGW version of Gfortran under Windows. Below I give information on how you can build an IFort-compatible import library for the DLL. I tested the example problem with the the 32-bit IFort compiler, and it ran fine. However, you may run into (i) more problems when you build code that calls IMSL in addition (ii) calling convention mismatches between IFort and GFortran.

  • Using the DEF file that is provided with the NLopt DLL as a basis, build a modified version with the pattern below:
  • Build the import library using the modified DEF file rather than the original DEF file
  • Make a copy of the DLL and call the copy NLOPT32.DLL

The contents of the DEF file:

LIBRARY nlopt32.dll
EXPORTS
NLO_ADD_EQUALITY_CONSTRAINT=nlo_add_equality_constraint
NLO_ADD_EQUALITY_MCONSTRAINT=nlo_add_equality_mconstraint
NLO_ADD_INEQUALITY_CONSTRAINT=nlo_add_inequality_constraint
NLO_ADD_INEQUALITY_MCONSTRAINT=nlo_add_inequality_mconstraint
NLO_COPY=nlo_copy
NLO_CREATE=nlo_create
NLO_DESTROY=nlo_destroy

---etc.---

The commands to use in an IFort command window:

lib /def:nlopt32.def /machine:i386
copy libnlopt-0.dll nlopt32.dll
ifort example.f funcs.f nlopt32.lib

 

0 Kudos
mecej4
Honored Contributor III
1,378 Views

I don't see why there should be a problem. I took the NLOPT example, and added a few lines of code to solve the problem again using IMSL NNLPF. The code is given below. Compiling and linking with the command

ifort /Qimsl nlofnl.f funcs.f nlopt32.lib %link_fnl%

worked fine, and running the program gave normal results. Thus, there is no conflict between libraries, at least for this example. If you post your test source code, or give more details regarding the access violation, it would help.

Here is the test source code.

!
      program main
      use nnlpf_int
 
      implicit none
      external myfunc, myconstraint, fcn
      integer    ibtype, m, me
      parameter  (ibtype=0, m=2, me=0)
!
      double precision fvalue, xguess(2), xlb(2), xub(2)
      integer*8 opt
      double precision d1(2), d2(2), x(2), minf
      integer ires
      include 'nlopt.f'
 
      call nlo_create(opt, NLOPT_LD_MMA, 2)
      call nlo_get_lower_bounds(ires, opt, xlb)
      xlb(2) = 0.0
      call nlo_set_lower_bounds(ires, opt, xlb)
      call nlo_set_min_objective(ires, opt, myfunc, 0)
 
      d1 = [2.d0, 0d0]
      call nlo_add_inequality_constraint(ires, opt,                     &
     &     myconstraint, d1, 1.D-8)
      d2 = [-1.d0, 1.d0]
      call nlo_add_inequality_constraint(ires, opt,                     &
     &     myconstraint, d2, 1.D-8)
 
      call nlo_set_xtol_rel(ires, opt, 1.D-4)
 
      x = [1.234d0, 5.678d0]
      call nlo_optimize(ires, opt, x, minf)
      if (ires.lt.0) then
         write(*,*) 'nlopt failed!'
      else
         write(*,10) 'NLOPT found min = ',minf,' at ', x(1), x(2)
      endif
 
      call nlo_destroy(opt)
!
!     solve again, using IMSL NNLPF
!
      xguess = [1.234d0, 5.678d0]
!
      xlb = [-huge(x(1)), 0d0]
      xub(1:2) = huge(x(1))
!
      call nnlpf (fcn, m, me, ibtype, xlb, xub, x, xguess=xguess,       &
     &      fvalue=minf)
!
      write(*,10) 'NNLPF found min = ',minf,' at ', x(1), x(2)
   10 format(A,F10.7,A,2F10.7)
      end program
!
      subroutine fcn(x, iact, result, ierr) 
      implicit none
      integer iact
      double precision result, x(*)
      logical  :: ierr 
      integer, parameter :: a1 = 2, b1 = 0, a2 = -1, b2 = 1 
!
      ierr = .false.
      select case (iact)  
      case (0)  
         result = sqrt(x(2)) 
      case (1)  
         result = x(2) - (a1*x(1)+b1)**3 
      case (2)  
         result = x(2) - (a2*x(1)+b2)**3 
      end select 
      return  
      end subroutine fcn 

 

0 Kudos
Hewei_S_
New Contributor I
1,378 Views

Hi mecej4 thank you very much! I have been checking my code and I found out  a small bug in my code.  In order to use NLopt, I should declare the variavle opt as integer(8) instead if just integer ( integer(4) by default). After chaning this, the code runs flawlessly. Thank you!

 

mecej4 wrote:

I don't see why there should be a problem. I took the NLOPT example, and added a few lines of code to solve the problem again using IMSL NNLPF. The code is given below. Compiling and linking with the command

ifort /Qimsl nlofnl.f funcs.f nlopt32.lib %link_fnl%

worked fine, and running the program gave normal results. Thus, there is no conflict between libraries, at least for this example. If you post your test source code, or give more details regarding the access violation, it would help.

Here is the test source code.

!
      program main
      use nnlpf_int
 
      implicit none
      external myfunc, myconstraint, fcn
      integer    ibtype, m, me
      parameter  (ibtype=0, m=2, me=0)
!
      double precision fvalue, xguess(2), xlb(2), xub(2)
      integer*8 opt
      double precision d1(2), d2(2), x(2), minf
      integer ires
      include 'nlopt.f'
 
      call nlo_create(opt, NLOPT_LD_MMA, 2)
      call nlo_get_lower_bounds(ires, opt, xlb)
      xlb(2) = 0.0
      call nlo_set_lower_bounds(ires, opt, xlb)
      call nlo_set_min_objective(ires, opt, myfunc, 0)
 
      d1 = [2.d0, 0d0]
      call nlo_add_inequality_constraint(ires, opt,                     &
     &     myconstraint, d1, 1.D-8)
      d2 = [-1.d0, 1.d0]
      call nlo_add_inequality_constraint(ires, opt,                     &
     &     myconstraint, d2, 1.D-8)
 
      call nlo_set_xtol_rel(ires, opt, 1.D-4)
 
      x = [1.234d0, 5.678d0]
      call nlo_optimize(ires, opt, x, minf)
      if (ires.lt.0) then
         write(*,*) 'nlopt failed!'
      else
         write(*,10) 'NLOPT found min = ',minf,' at ', x(1), x(2)
      endif
 
      call nlo_destroy(opt)
!
!     solve again, using IMSL NNLPF
!
      xguess = [1.234d0, 5.678d0]
!
      xlb = [-huge(x(1)), 0d0]
      xub(1:2) = huge(x(1))
!
      call nnlpf (fcn, m, me, ibtype, xlb, xub, x, xguess=xguess,       &
     &      fvalue=minf)
!
      write(*,10) 'NNLPF found min = ',minf,' at ', x(1), x(2)
   10 format(A,F10.7,A,2F10.7)
      end program
!
      subroutine fcn(x, iact, result, ierr) 
      implicit none
      integer iact
      double precision result, x(*)
      logical  :: ierr 
      integer, parameter :: a1 = 2, b1 = 0, a2 = -1, b2 = 1 
!
      ierr = .false.
      select case (iact)  
      case (0)  
         result = sqrt(x(2)) 
      case (1)  
         result = x(2) - (a1*x(1)+b1)**3 
      case (2)  
         result = x(2) - (a2*x(1)+b2)**3 
      end select 
      return  
      end subroutine fcn 

 

0 Kudos
mecej4
Honored Contributor III
1,378 Views

Indeed, the NLopt Fortran Reference says:

The NLopt API revolves around an "object" corresponding to the C type nlopt_opt. This object is internally a pointer, so it should be declared as an integer*8 in Fortran

It would have been nice if they provided an interface module for using the NLopt C routines in Fortran. However, if you were compiling for 32-bit targets, even INTEGER*4 should have been enough.

0 Kudos
Steve_Lionel
Honored Contributor III
1,378 Views

Neither "integer*4" nor "integer*8" is correct. What should be used is INTEGER(C_INTPTR_T) (USE ISO_C_BINDING to get that constant.) 

I also would strongly advise against using /names to handle name-mangling. Best is to declare an interface with BIND(C) and use NAME= if you need mixed-case. 

0 Kudos
Hewei_S_
New Contributor I
1,378 Views

Hi Steve, thank you for your reply and I want to ask you about the ISO_C_BINDING. I am very new to this and so please forgive me for silly questions. I understand that I can write an interface with BIND(C) to specify the case of the routine when I call it, but I am not sure how I can do it when I am calling an external library where I do not know how the subroutine in the library is written. If I do not know the exact form the subroutine, can I still write an interface for the subroutine with BIND(C).  Also, is there a good reference page that I can learn how to use ISO_C_BINDING? I want to learn more about it. Thank you!

 

Steve Lionel (Ret.) wrote:

Neither "integer*4" nor "integer*8" is correct. What should be used is INTEGER(C_INTPTR_T) (USE ISO_C_BINDING to get that constant.) 

I also would strongly advise against using /names to handle name-mangling. Best is to declare an interface with BIND(C) and use NAME= if you need mixed-case. 

0 Kudos
Steve_Lionel
Honored Contributor III
1,378 Views

First of all, ISO_C_BINDING and BIND(C) are only indirectly related. The first is a module that declares various constants, types and procedures, where the latter is an attribute that specifies that the thing you used it with is "interoperable" with C. There is no specific requirement that the thing you're calling be actually written in C, only that it uses the same conventions. Since this library is not written in Fortran, it makes some assumptions about global names, hence your use of /names:lowercase. 

A while back I wrote a Doctor Fortran post about C interoperability. I had meant to write a follow-up, but got distracted. It's still worth a read.

My suggestion for use of C_INTPTR_T was mainly to give you an implementation-independent way of declaring an address-sized integer. Intel Fortran has an intrinsic function INT_PTR_KIND() that returns the kind of an integer pointer, but that's an extension.

0 Kudos
Reply