- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Community,
I currently have two Projects that are connected and work perfectly. There's a static library Project (exe) that calls a dynamic library project (dll). The DLL project consists of many Modules. I would like to break the DLL project into separate DLLs by compiling each module as an individual DLL.
Would you guide me where to find instructions on this? I am using Visual Studio to build the projects.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do you really want to have each module as its own DLL? That seems unnecessarily complex. It may also be impossible if you have calls between the modules in both directions.
Open the VS solution containing your DLL. Select File > Add > New Project. Select Fortran DLL as the project type. In the Solution Explorer window, drag the module source file(s) from the current project to Source Files in the new project. Repeat this for each module.
Now open the executable project that, ideally, has as dependent projects the static library and DLL. Add all of the DLL projects you created to this one. Right click on the executable project, select Dependencies > Project Dependencies. Check the boxes for each DLL project.
This will most likely fail because your modules are not independent. But maybe you'll get lucky.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I know it may sound unnecessary to break up the DLL but I'm going to experiment with separating one DLL.
I am following your instructions. The "main" DLL module is calling a subroutine that is calling another. I am trying to separate the latter subroutine as a DLL project. Then, it is called from the subroutine that is inside the "main" DLL Is that possible? Or does the separated subroutine have to be called directly from the "main" DLL? Or, does both DLLs have to be called by the static project?
Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Build a tree diagram of how your calls go. If you have a routine in DLL B that is used only by DLL A, then DLL B needs to be a dependent of DLL A.
The static library doesn't really enter into this at all, as you never link it on its own. All that matters is that all of the DLL routines it references can be found when the EXE is linked.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You said that in your current single DLL you have several modules. Do those modules contain data objects? If so, breaking up the DLLs will entail doing quite a bit of additional coding to ensure that the new sets of DLLs have a consistent view of the data. If you do not do so, each DLL may have its own copies of the variables and any pair of DLLs that are supposed to share data may end up with separate and uncoordinated copies of the data.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you all for your comments.
I have tried to separate a single module into a separate DLL B from the main DLL A. In DLL A, there's a module that uses and calls DLL B . After creating a new project for DLL B and building the projects, I can't debug the code. I set DLL A to be dependent on DLL B.
In DLL B, I used these commands to export DLL B (this is a simplified example code):
subroutine DLL_B(x,y,z) implicit none !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: DLL_B !DEC$ ATTRIBUTES ALIAS:'DLL_B' :: DLL_B !DEC$ ATTRIBUTES REFERENCE :: x,y,z real(8) :: x,y,z ! the body of the code end subroutine DLL_B
In the module that calls DLL B in the main DLL A, I added these lines:
module example !DEC$ ATTRIBUTES DLLIMPORT,ALIAS: 'DLL_B' :: DLL_B subroutine example(q) implicit none real(8)::q,x,y,z call DLL_B(x,y,z) end subroutine example end module example
During the debug I get exception thrown error at the statement {call DLL_B(x,y,z)}. I am trying to figure out why. All the lib, exp and pdb files are output to the same debug directory. What am I missing?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You didn't say STDCALL in the caller. If you used modules for everything, all the interfaces and calling method would get handled automatically.
That the program linked means your file locations are fine. I assume that the exception was either an access violation or a stack issue.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I added STDCALL to the caller as follows
module example !DEC$ ATTRIBUTES DLLIMPORT,STDCALL,ALIAS: 'DLL_B' :: DLL_B subroutine example(q) implicit none real(8)::q,x,y,z call DLL_B(x,y,z) end subroutine example end module example
I still get the same error and yes it's access violation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Since you're only showing us pseudocode here, and not your actual code, it's hard for us to provide useful help. Do you recognize that simply saying STDCALL makes the arguments pass-by-value, and thus any attempt to assign to them in the subroutine will fail?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, Steve!
It's working now. The reason was that there were a lot of pointer variables in the actual DLL_B code. I had to assign a fixed size to them. I also removed the STDCALL from the caller.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So these were POINTER dummy arguments that you passed non-pointers to? That is supported in some contexts (not yours), but only when there is an explicit interface visible, which your psuedocode did not provide.
You should always have explicit interfaces visible. /warn:interface can help identify where these are required but not used, but I might be inclined nowadays to suggest /warn:external, which will give you errors for any call where an explicit interface or EXTERNAL attribute is not provided.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
These were pointer dummies that I passed pointer dummies to. Their size is determined inside DLL_B, and they're supposed to be allocated inside DLL_B as well. Would INTERFACE solve this issue?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes - if you have a POINTER dummy, an explicit interface is required. See Doctor Fortran Gets Explicit – Again! -warn interface would likely complain to you about this, if you compiled things in the right order.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have added a reference block in the calling subroutine (DLL_A) where I added the pointer arrays and all the parameters that are called from DLL_B. I built the codes with warn:interfaces on and the solution was compiled without errors. Also, debugging is working and DLL_B is executed without errors.
However, some parameters from the caller subroutine (DLL_A) took some random values while I was debugging the code. Those parameters are not in the called subroutine (DLL_B), and they took those random values without being modified. Any idea of what to check in the code?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I tried code as above and got an error code of 6530.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Please show the actual code you used and the actual error message. Few if any of us have memorized all of the error numbers, though if I have it right this one is "The array spec for this component must be of explicit shape and each bound must be an initialization expression." Since I see no arrays in the code posted in this thread, I am perplexed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
kolber, Michael wrote:I tried code as above and got an error code of 6530.
There is no complete body of code in this thread that you can designate as "code as above". There are many combinations and variations that could be tried, and that one such variation (with modifications by you, perhaps) produced an error message is not something that one would consider to be interesting or worth investigating.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
not something that one would consider to be interesting or worth investigating.
--------------------------------------------------------------------------------------------------------------------------------------------------
I thought something was worth investigating once, but then thought better and felt much better for my failure to perform and therefore perform at the level of the average human bean on the average day. or as my Dad used to say when I asked for a beer, leave your money on the frig. By the way, by the time you are old and tall enough to leave your money on the frig, you are old enough to have earned the money mowing lawns.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>...perform at the level of the average human bean...
Just how large is a human bean? As big as a Lima bean, green bean?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Typo, intended "being", perhaps?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Ret.) (Blackbelt) wrote:Please show the actual code you used and the actual error message. Few if any of us have memorized all of the error numbers, though if I have it right this one is "The array spec for this component must be of explicit shape and each bound must be an initialization expression." Since I see no arrays in the code posted in this thread, I am perplexed.
Steve,
I have been investigating the issue and I decided to pass the arrays in a data structure (derived type) so that the memory allocation for all variables won't be interrupted during the execution of the code. I am attaching the subroutine for the dll I'm using as an experiment. The dll receives arrays x and y and return the summation of them. The dll works fine with a fortran caller. However, when C# is used to call the dll, I get an error message that an allocatable array is already allocated. I think it's the sumt array. C# wouldn't pass an array to the dll unless it was allocated. So, it was allocated before calling the dll. What should be done to pass that array without prior allocation in C#? The main objective is to get that array allocated inside the dll. I'm also attaching the C# caller.
fortran dll:
subroutine sum_type(sum_obj) !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: sum_type !DEC$ ATTRIBUTES ALIAS:'sum_type' :: sum_type !DEC$ ATTRIBUTES REFERENCE :: sum_obj implicit none type sum_data real(8),allocatable:: x(:),y(:),sumt(:) end type sum_data type(sum_data):: sum_obj integer(8) l l=size(sum_obj%x) allocate(sum_obj%sumt(l)) sum_obj%sumt=sum_obj%x+sum_obj%y open(1,file='sum_type.out') write(1,*)sum_obj%x write(1,*)sum_obj%y write(1,*)sum_obj%sumt close(1) end subroutine sum_type
C# caller:
//Here is where I define the dll: [DllImport("sum_type.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void sum_type(ref SumStruct data); //Here is where I define the struct: [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct SumStruct { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public double[] x; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public double[] y; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public double[] prod; } //Here is where I call the dll: SumStruct sum; sum.x = new double[3] { 1, 2, 3 }; sum.y = new double[3] { 2, 4, 6 }; sum.prod = new double[3]; sum_type(ref sum);
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page