I have multiple compiled Fortran libraries (.lib and .obj files) that have conflicting subroutine names. They all use a subroutine call WEX. Is there a way to incorporate them into my code such that I can call the subroutine I want? I want to be able to call WEX from a specific library, then the next time I run the code call WEX from another library. For what it's worth, I only want to use one specific library each time the code is called. It doesn't need to change definitions mid-way through. I do not have access to the source code for these libraries or subroutines, and getting it is not an option.
Our current work-around is to actually recompile different versions of our code for each different library and version of WEX that we have. It's not the best solution....
I tried to create a module for each library that only looks at that library. Then I compiled those modules and tried to pass them to my main code. However, it seems that the linker is still looking "through" those modules and seeing the duplicate subroutine names.
The linker will pull in all symbols defined by an object module that satisfies a reference it is looking for. If you have one module that defines symbols A and WEX, and a second that defines B and WEX, and your program calls A and B, then you'll get an error for the duplicate WEX. If WEX is in its own module, not defining other symbols used elsewhere, then whichever one the linker finds first will win. But if the library has its own references to WEX, even if you want the other one, you're stuck.
I'm not entirely sure I understand the structure of your program. You say you have .lib and .obj - where is this MEX defined and is it referenced in other parts of the set of compiled objects you are using?
I am having the first issue. Because the libraries have some different subroutines, but the 'main' one is always present, I get a linker error for duplicate WEX.
The structure is that we were delivered a compiled library from another company. The WEX routine contains information about their product. Over the years, they've delivered different libraries that contain information about different products, but they used the same format to do it. So WEX is defined in the .obj file for both libraries. It is meant for us to be able to call it from our own Fortran codes, and it is not referenced in any other pre-compiled objects.
One option is to place WEX into a .dll or .so., one instance in different folders for each variation of WEX. Then prior to running (or via shell script) set the PATH to include the desired library.
Alternatively, at least on Windows, you can load(and unload) the desired .dll under program control. And then obtain the entry point for WEX.
Is there a way to turn a static library into a dll? I do not have (and cannot get) the source code for any version of WEX.
One of my thoughts is to create an intermediate layer dll. Each dll would point to a single static library, then we could do something like what you suggested to pick the correct dll on program start-up.
Thanks for the ideas!
Your description is rather vague, and you did not distinguish between clashes at compile time, link time and run time. However, I think that I can offer a possible solution to what I understand to be the main source of difficulty.
The solution depends on a utility to rename external symbols in OBJ and LIB files, namely, Agner Fog's OBJCONV.
In the example code below, we have two source files, lib1.f90 and lib2.f90. We build object file LIB1.OBJ from the source file lib1.f90 and object file LIB2.OBJ from source file lib2.f90. Each source file contains subroutines SUBA and SUBB. We cannot include both LIB1.OBJ and LIB2.OBJ in a link command because SUBA and SUBB are each defined more than once. To resolve the multiplicity, we rename the public subroutine names in the OBJ files using OBJCONV, producing modified versions LIB1m.obj and LIB2m.obj. We then link our main program with LIB1m.obj and LIB2m.obj.
First, the source file LIB1.F90:
!source codes of routines for lib1.lib subroutine suba(i,j,k) k = i+j call wex('suba',i,j,k) return end subroutine suba subroutine subb(i,j,k) k=i*j call wex('subb',i,j,k) return end subroutine subb
Next, the source file LIB2.F90:
!source codes of routines for lib2.lib subroutine suba(i,j,k) k = i-j call wex('suba',i,j,k) return end subroutine suba subroutine subb(i,j,k) k=i/j call wex('subb',i,j,k) return end subroutine subb
Compile the two source files:
ifort /Od /c lib1.f90 lib2.f90
Replace the subroutine names and produce modified OBJ files:
objconv.exe -nr:SUBA:LIB1_SUBA -nr:SUBB:LIB1_SUBB lib1.obj lib1m.obj objconv.exe -nr:SUBA:LIB2_SUBA -nr:SUBB:LIB2_SUBB lib2.obj lib2m.obj
A test program, file muldef.f90, that calls routines in LIB1M.obj and LIB2M.obj:
program muldef i = 23 j = 44 print *,'Calling routines in LIB1' call lib1_suba(i,j,k) call lib1_subb(i,j,k) print *,'Calling routines in LIB2' call lib2_suba(i,j,k) call lib2_subb(i,j,k) end program subroutine wex(string,i,j,k) character(*) string print '(1x,A,2x,3i6)',string,i,j,k return end subroutine
Compile the program and link:
ifort muldef.f90 lib1m.obj lib2m.obj
Running the resulting program produces the output:
Calling routines in LIB1 suba 23 44 67 subb 23 44 1012 Calling routines in LIB2 suba 23 44 -21 subb 23 44 0
Some important points to note:
- The EXE contains the renamed subroutines from lib1m.obj and lib2m.obj. The corresponding EXE in a large application may be rather bloated, containing a lot of code that will never be used in each run, but that is the price to pay for wanting a single EXE. The program may take longer to load and consume more memory.
- You have to document the new names introduced while renaming, and the user code that calls the multiple libraries will have to call these distinct names rather than the original clashing names.
- Note that in the example, there is only one subroutine with the name WEX. If you have multiple files with different subroutines with the same name WEX, you will have to devise and implement a disambiguation scheme for that as well.
The problem I'm having is when linking. Because I'm trying to use multiple libraries that contain some different subroutines, but all have WEX, I get a duplicate definition error for WEX when I link.
That looks extremely promising! If I can modify the name of WEX each version of the library, that should work perfectly. Thank you so much!
You do not need the source code for WEX. Simply rename the various instances of WEX in the various libraries as LIB1_WEX, LIB2_WEX, etc. In your client program, you have to make sure to call whichever version of WEX you wish to call, i.e., select only one from LIB1_WEX, LIB2_WEX, etc.
I can generalize this recommendation. If you have the source for a routine, rename in the source by adding a disambiguating suffix or prefix. If you do not have the source, do the renaming in the OBJ or LIB file.
It is certainly possible to build DLLs from static libraries, but I advise postponing that idea for now. Once you have a working solution using static libraries, you can consider moving to DLLs, which have pros and cons.