- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 aninteger*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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page