Linking problem with winxp, msvc 8.0, bindexplib limitation?

Dear Rooters,

I have a problem linking my code under windows. Usually I work with linux, where I have a makefile to create dictionaries and link my code together in shared library, that I load in the interpreter where i call my code from interactive macros.

Now I want to do same for windows using the msvc 8.0 compiler.

I managed to create a makefile for nmake (mostly by reading the discussions of Christian and Bertrand, thanks they were really helpful), which compiles and creates the dictionaries but i have a problem with the linking process.

If I understand correctly, I need to use bindexplib to create a .def file with the external symbols that the .dll will export, which are all public symbols basically.

Most of the time this works well, but i have some inline functions that use static data members for performance reasons and a class with physical constants that are kept in public-static-const data members. Those symbols don’t get exported by the dll, which is a problem for me, because i used them alot.

I also found out, by fiddling around with .def file, that when i remove the ‘data’ keyword behind those data members before calling the linker the symbols get exported and everything seems to work.
(I think i also read somewhere, that data members don’t get exportet by a dll… ?)

Is this behaviour of bindexplib intented? (Not exporting static data members?)

I attached a tar file with two visual c projects reproducing my problem. In project Linkerproblem an inline function uses a static data member of class TSimpleClass. When the object of class TUserClass calls this inline function the static data member of TSimpleClass would need to be accessed, but it is not available, therefore the linking of Linkerproblem2.dll fails.
(I know, that i could use a const data member that is initialised in the constructor to circumvent this, but for the data type that i use in my code this is no option i think, because it would mean, that the data type would need to initialize 10 variable each time the constructor is called, which is unefficient when the data type has only two data members.)

Any suggestions are welcome!

kind regards
Dirk Dodt
Linkerproblem.tar.gz (3.46 KB)

Hi,

removing the DATA keyword lets the link “succeed”, but the import won’t work - the symbol doesn’t get resolved when using it. In my example code I have a data member static int fgMember used in an inlined function. fgMember is defined and set to -1 in a dll. When linking against that dll, bindexplib (ROOT’s .def file generator) tags fgMember as “DATA” which will make the link fail due to unresolved symbols referenced by the inline function. Removing the DATA keyword from the .def file will make link succeed, but main() (the “user” of the dll) doesn’t see its value -1 but something that seems to be a random value.

So removing DATA is no solution, I’m afraid. So far, the only way out is to mark all classes by declspec dllexport (check the MSVC help for how to use it) or to not reference static variables in inline functions. Which is good practice anyway.

Cheers, Axel.

[quote=“ddodt”]If I understand correctly, I need to use bindexplib to create a .def file with the external symbols that the .dll will export, which are all public symbols basically.[/quote]Correct.[quote=“ddodt”]Is this behaviour of bindexplib intented? (Not exporting static data members?)[/quote]What you have met is not the bindexplib limitation rather the Visual C++ feature that utility is to provide the workaround of.

The original idea behind of VC approach on Windows (30 years old, I guess) is the author of the code has to explicitly specify with the special key-words which symbol should be exported. By default, no symbol is exported across of the DLL border. I wondering if that was done to conserve the main memory of IBM PC with Intel286 CPU.

The bindexplib is to eliminate the need to use the special keywords within ROOT source code.
In theory, you are supposed to apply “dllexport” ( See
msdn2.microsoft.com/en-us/library/9h658af8.aspx
msdn2.microsoft.com/en-us/library/a90k134d.aspx for details

[quote]". . .
_declspec (dllexport) is a Microsoft specific extension for the compiler to tell it to export your function “bla”, so that other DLLs and EXEs can link to it and use it. Other way to accompilsh the same is to use the DEF file and specify your exports there.
. . ."[/quote])

However, it (bindexplib) cannot remove another limitation. The VC++ compiler (with no special keyword assistance) does not create any suitable interface to access the global data across of the DLL border.

So you have to choose either add the VC++ keywords to your code to generate the access methods “implicitly” or add the access method explicitly.
I think former is better.

[quote=“ddodt”]I attached a tar file with two visual c projects reproducing my problem. In project Linkerproblem an inline function uses a static data member of class TSimpleClass. When the object of class TUserClass calls this inline function the static data member of TSimpleClass would need to be accessed, but it is not available, therefore the linking of Linkerproblem2.dll fails.[/quote] I’ll check you prpoject later to see what can be done.

Thank you both for looking into this! I managed to compile and link the toy problem i posted before using the __declspec directives.

What a pity, that this can’t be done with an .def file, but as I use static variables only here and there, this will be a working solution for my actual problem.

@Axel: What would you recommend as a good practice to implement numerical constants then? Usually I don’t use preprocessor macros, because I was told, they are not type safe…

Ah, now I understand, i could’ve implemented public inline functions returning the desired constants… Mhmm. That would at leas avoid using Microsoft specific code…

I’m attaching the working toy problem, thanks again for the advice, may the root community continue to live long and prosper :slight_smile: !

regards
Dirk
LinkerProblem.tar.gz (220 KB)

[quote=“ddodt”] . . .TAh, now I understand, i could’ve implemented public inline functions returning the desired constants… Mhmm. That would at leas avoid using Microsoft specific code…
[/quote] I think you are confused with the keyword “inline” :bulb: . Why do you insist it should be very “inline” :unamused: ?

In fact, the “inline” keyword is the recommendation to C++ compiler. This way you can express your desire that C++ compiler should take in account … if it can. However, the compiler is free to disregard :exclamation: it if the “inlining” cannot be fulfilled.

The later is very your case. To access the global data across of the DLL border one has to provide the access method (aka the real function). This function is provided either by compiler (implicitly) or by original code “explicitly”. The VC++ needs the special keyword which is the explicit request to create such function. Either way you will get the real function inside of your binary. This means your “inlined” method ought to get the embedded non-inlined global data access function and you get no performance gain that probably is your “inlining” goal.

Yes . . . but do not make it inline !!! :open_mouth: move the implementation to your TSimpleClass.C file .class TSimpleClass { public: TSimpleClass(); ~TSimpleClass(); void PrintText(); Double_t DoSomeEfficientCalculation(Double_t input); static Double_t Log2(); private: TString *fText; static const double kLog2; }; inline Double_t TSimpleClass::DoSomeEfficientCalculation(Double_t input) { return input * Log2(); }

. . . const Double_t TSimpleClass::kLog2 = log(2.0); Double_t TSimpleClass::Log2() { return kLog2; } . . . Your code will be OK for any platform / compiler with no performance penalty. The reader of your code and you yourself will see clearly what is going on.

Hi Dirk,

of course there is a performance penalty due to the outlining of the wrapper function (which btw seems to also be caused by the declspec, at least that’s what I read out of the objdump output). Probably the best you can do is class MyClass { public: static double MyConstant() { static const double myConstant = 42.; return myConstant; } };
Smart compilers should be able to convert that to your original, direct access of the static data member. And it resolves the Windows linker issue. But what do you expect from a linker that’s still compatible with .obj files from the 80ies :slight_smile:

Cheers, Axel.

[quote=“Axel”]Hi Dirk,

of course there is a performance penalty due to the outlining of the wrapper function (which btw seems to also be caused by the declspec, at least that’s what I read out of the objdump output). [/quote]
You are correct. I meant there is no extra performance penalty introduced with the extra access method.[quote=“Axel”]Probably the best you can do is class MyClass { public: static double MyConstant() { static const double myConstant = 42.; return myConstant; } };Smart compilers should be able to convert that to your original, direct access of the static data member.[/quote]
It is doubtful any smart compiler can do that alone. It can be done by smart linker / loader. At the compile time the compiler has no clue yet whether the MyConstant() implementation is to be provided from the same shared library. The only thing the smart compiler can do is to create a copy of the constant for each object file. The smart linker can realize at run-time it is going to load some global symbol for the second time and eliminate the redundant copy.
However, one should understand the trade off of the above approach.
It requires all codes those need that constant to be recompiled and all shared libraries containing those codes to be rebuilt as soon as any single constant is changed.
As soon as one moves the MyConstant() implementation to the implementation file no code has to be recompiled but the MyClass and no library has to be rebuilt but one containing the MyClass implementation.

[quote] I think you are confused with the keyword “inline” Idea . Why do you insist it should be very “inline” Rolling Eyes ?
[/quote]

Mhmm when I have member functions just returning the value of some variable, i usually make them inline and I am aware, that it is not inline-able under all circumstances (the usage of dlls seems to be such an unfortunate case, but at least i did my best…)

I still hope though, that the implementation I choose is efficient with .so shared library binding.

Funny thing, if I want to keep things efficient for linux I have to use MS compiler specific code :slight_smile: I will consider to use one of your versions to avoid that.

Thanks again
Dirk

[quote=“ddodt”][quote] I think you are confused with the keyword “inline” Idea . Why do you insist it should be very “inline” Rolling Eyes ?
[/quote]Mhmm when I have member functions just returning the value of some variable, i usually make them inline [/quote]This is correct. The only your “mistake” is the attempt to return the global constant. If your method is to return the constant then return the local one.That makes things consistent and transparent for all platforms (see below)

[quote=“ddodt”]and I am aware, that it is not inline-able under all circumstances (the usage of dlls seems to be such an unfortunate case, but at least i did my best…)

I still hope though, that the implementation I choose is efficient with .so shared library binding.

Funny thing, if I want to keep things efficient for linux I have to use MS compiler specific code :slight_smile: I will consider to use one of your versions to avoid that.[/quote]May be I should summarize

  1. Access to the global variable across of the shared library / DLL border requires the access method on either platform. gcc provides this method implicitly, Microsoft requires you to provide it explicitly. As soon as efficiency is concern, neither approach has any advantage.

  2. Fortunately, as soon as you provide the public access method you do not need the global constant anymore. You can use the local constant of the access method. That allows you to inline such method and you end up with the Axel’s solution.

  3. Unfortunately, the Axels’ solution is not “free” (as well as any “inlining”) because it introduces the redundant dependency. (see my comment from the previous post).

The choice is yours. What is your first priority, the cheaper code support or the cheaper (aka faster) code execution? Take in account in long-term the price to support the source code is supposed to grow, the price to run the code should descrease.