make a DLL with static linking?

Dear all,

I want to encapsulate several subroutines into a DLL that can be called by LabView. As far as I understand, the PGI compilers (I use Fortran) and linker can only make a DLL when all libraries are linked dynamically. As a consequence, if I want to distribute the DLL, I also have to distribute the whole dirctory REDIST with all runtime libraries of PGI. With GNU compilers I can make a DLL that has all that it needs statically linked, which is much more convenient for distribution. Is there a way to get the same with PGI?

best regards,
Bernhard

Hi Bernhard,

It should be possible, with a little extra effort. The caveat being it’s not something we’ve thoroughly tested. I’ve personally done it and it worked fine but don’t know of all the corner cases.

What I’ve done is use the PGI flag “–keeplnk” to keep the link file as well as use either “-dryrun” or “-v” to see what commands the compiler driver is executing, changed the dynamic libraries to the static ones in the link file, then called link directly. Note the difference between “-v” (verbose) and “-dryrun”, is that “-v” will show the commands as they are being executed, while “-dryrun” shows the commands but does not actually execute them.

$ pgcc -Mmakedll -dryrun --keeplnk x.obj  -fast
... cut ...
Writing to file pgi.dlllnk
-DLL -incremental:no -debug -nologo -merge:__nv_module_id=.data -merge:.nvFatBinSegment=.data x.obj -out:x.dll -pdb:./x.pdb "-libpath:C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/lib/x64" "-libpath:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/ucrt/x64" "-libpath:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64" -libpath:C:\PROGRA~1\PGI/win64/19.4/lib /DYNAMICBASE:NO -defaultlib:pgmp -nodefaultlib:libvcruntime -nodefaultlib:libucrt -nodefaultlib:libcmt -defaultlib:msvcrt -defaultlib:pgc -defaultlib:libnspgc -defaultlib:pgmath -defaultlib:legacy_stdio_definitions -defaultlib:oldnames

"C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx64/x64\link.exe" /NOLOGO @pgi.dlllnk

C:\PROGRA~1\PGI/win64/19.4/bin\pgstrp.exe ./x.dlf x.dll ./x.dwf
Keeping ./x.dlf

While it may change slightly from release to release, with 19.4, the three libraries that are dynamically linked at pgc, pgmp, and pgmath. Edit the resulting “pgi.dllnk” file, change these to use the static versions (like libpgc, libpgmp, libpgmath).

$ cat pgi.dlllnk
-DLL
-incremental:no
-debug
-nologo
-merge:__nv_module_id=.data
-merge:.nvFatBinSegment=.data
x.obj
-out:x.dll
-pdb:./x.pdb
"-libpath:C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/lib/x64"
"-libpath:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/ucrt/x64"
"-libpath:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64"
-libpath:C:\PROGRA~1\PGI/win64/19.4/lib
/DYNAMICBASE:NO
-defaultlib:pgmp    <<< change this to use libpgmp
-nodefaultlib:libvcruntime
-nodefaultlib:libucrt
-nodefaultlib:libcmt
-defaultlib:msvcrt
-defaultlib:pgc    <<< change this to use libpgc
-defaultlib:libnspgc
-defaultlib:pgmath   <<< change this to use libpgmath
-defaultlib:legacy_stdio_definitions
-defaultlib:oldnames

Then run the link.exe command as shown above with the correct path on your system.

Note that the compiler options you use will effect which libraries are included, so be sure to run the dryrun/-v command with the same options.

I’ve also added an enhancement request (TPR #27128) to see if we can add an option to do static linking of the PGI libraries within a DLL, similar to what we do on Linux with the “-Bstatic_pgi” flag.

Hope this helps,
Mat

Dear Mat,

sorry for the delay, I only now had time to test your suggestion. In summary, it worked fine! The actual libraries are somewhat different since I am using pgfortran and not pgcc. I should mention that I use Code::Blocks as an IDE. I first run the build with the additional options -v --keeplnk, then run the link.exe with the original @pgi.dlllnk just to check whether it made the same result.

Interestingly, the DLL is only 933 kB long when I use Code::Blocks, but 1000 kB when I run the linker separately. But both DLLs work fine.

Subsequently I replaced the defaultlib commands:
-defaultlib:libpgmp
-defaultlib:libpg
-defaultlib:libpgf90rtl
-defaultlib:libpgf90
-defaultlib:libpgf90_rpm1
-defaultlib:libpgf902
-defaultlib:libpgf90rtl
-defaultlib:libpgftnrtl
-defaultlib:libpgc14

Now I called the linker again. It produces a DLL of 1909 kB which works perfectly without the need of the runtime libraries of PGI.

Then I added the above defaultlib options to the “other linker options” in Code::Blocks and re-build the project. I get a DLL of 1655 kB, but the performance is exactly the same. Looking at the pgi.dlllnk from this process I see that the old -defaultlib options are still there, but the new ones are placed before, and hence the others are not called.

So my problem is solved, but I still wonder about the different sizes of the DLLs. They are shorter when they are made in a single step (compiling and linking) compared to separate linking.

many thanks!
Bernhard

Hi Bernhard,

Great! Very glad it worked for you and I hope our engineers will be able to add the RFE where using “-Bstatic_pgi” would make this easier.

but I still wonder about the different sizes of the DLLs.

I’m not sure, having not used Code::Blocks myself. My best guess is Code::Blocks is implicitly adding an object or library.

-Mat