PDA

View Full Version : Fixed a problem. Help me understand why :)



tescrin
27th July 2012, 21:23
Alright, so I *finally* got all my ducks in a row on getting a plugin to work both in the Qt Designer and not give any linker errors on compilation etc..

My main issue was that I get receiving linker errors when I had built it as a DLL; the only way to solve those errors was to include the .h and .cpp files directly in with the project, but that's defeating the purpose of encapsulationl! So I went ahead and finally attempted to build the plugin as a *static* library. This replaced the old .lib file and it all works now! (It's worth noting that this was more than one class. The plugin class used another custom class. The dynamic library presumably wouldn't compile my other custom class in with the plugin class and gave me linker errors.)

I guess my question is:
-Why didn't the DLL compilation compile both classes into it's .lib file but the standard library compilation did?

I investigated the issue pretty thoroughly but I have not figured it out yet. It's worth noting that I have not built .lib type files in the past. Help understanding why this fixed my issue would be much appreciated.
Thanks!

amleto
27th July 2012, 21:37
what compiler are you using?

e.g. on microsoft you have to do something like __declspec(dllexport) and have some code in .cpp file for .lib file to be made. otherwise the library is "header only" and you must include the header and not dll/lib.

Essentially, you got linker error because you either:
- had nothing in the library to link with -> build/compile problem with the dll.
- did not properly configure your project to link with the correctly built library

tescrin
30th July 2012, 18:27
Hm, well, it does export the DLL file and additionally has an "Export library file" (exp) that goes with it. I didn't add code to any .cpp files to ensure the other class would be included other than standard #include statements.

Is there anything dirty about using the static library compared to a dll? Is there a reason I should go figure this out (other than being a learning experience) over just using the Static Library?

Thanks!

amleto
30th July 2012, 18:32
I didn't add code to any .cpp files to ensure the other class
__declspec would go in the header, not the .cpp.

yes. static library means any change to a library and you need to rebuild your whole app. With dll you just rebuild the dll.


You should show your dll code and how you were trying to link it.

tescrin
30th July 2012, 22:05
Attached is the full code (plus the vs2010 solution) mostly because I'm not sure I understand what you're asking for and your signature.

I linked using the following algorithm:
-I built this in VS2010 using the ".dll" project settings, set to output at <build_location>
-In a separate program I added the <build_location> to the included libraries and added the built library to it's additional dependencies (this is all under the VS "linker" tab. Right click the project name in the solution explorer->properties->configuration properties->linker)

From browsing online it looks like I just add:
__declspec(dllexport) in front of each class I wish to include in the dll? Is Visual Studio automatically doing this at all? It might be worth noting that the .dlls work fine with/for designer, they just don't actually link for the real program :s.

EDIT: Tried that. Same link issues.

amleto
30th July 2012, 22:16
Is Visual Studio automatically doing this at all?
No.

I will have a look at the solution...


... You forgot the project files.

tescrin
30th July 2012, 22:25
I assume you mean the VS Project files; I figured you wouldn't want them (because they'll change user settings and such.) Here ya go.

EDIT: If no, I'm not using a real .pro file. VS seems to abhor them as even when I write one correctly I have to go manually include paths and a bunch of other hoopla. I wouldn't be using VS if I didn't have to lol.

amleto
30th July 2012, 22:41
compile settings and linker settings are in the project file not the solution...

Added after 10 minutes:

you can see from using depends.exe that your dll is virtually empty - this will be because you are not exporting any of your classes into the dll (__declspec...).

tescrin
30th July 2012, 22:42
I hate to be dense; but does this mean you're looking for the project I was trying to link to as well? If so, it's really not necessary if you perform the above steps (add the library location, add the library as a dependency) as I'm just doing it with a simple generated project and adding this class using the designer on the provided form (to test it.)

Further, the paths probably won't like up with your pathing meaning it's probably more work to do it that way.

Either way, thanks thus far


EDIT:After your edit
With the modified code (just adding __declspec(dllexport) to the classes) the linker still gives me the same errors.
It's also worth noting that I only get errors regarding "textspinbox" (the class being used by the plugin) and not the plugin class itself (bertspinbox)

I'll keep looking into the declspec issue.., it looks like you have to import as well (on every function that uses dll stuff?)

amleto
30th July 2012, 23:23
yes, when you include the headers in the project that needs to link against the dll, it needs to be dllimport.

this 'problem' is normally solved with #defines.


#ifdef BUILD_THIS_DLL
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif


where BUILD_THIS_DLL is only defined for the dll project and not the app using the dll.

See also http://msdn.microsoft.com/en-us/library/8fskxacy.aspx

tescrin
31st July 2012, 15:53
Thanks for the help. I'll have to go find a tut on doing this correctly as right now I'm just breaking my code :s. (it's generating multiple definitions for the same classes and such)

tescrin
1st August 2012, 18:08
I decided to put together a document that clearly explains the *every* step of the way towards doing this correctly in visual studio (in part for myself._ I figured that it might be useful for anyone else who happens upon having troubles getting stuff to work.

Might be worth pointing to, stickying, or something for future Qt users who have trouble with plugins. The information gathering on getting this all to work is really spread out and for someone just approaching it from the perspective of "this will be quick and easy" it required finding, asking, and experimenting with a lot of different things. Maybe creator does some of these steps for you and I just didn't mess with it enough. At any rate; for visual studio:



Paths below are based on a standard install of the QT SDK (as of 8/1/2012) with a base directory
named "Qt" directly located in C:\. Adjust accordingly.
It also assumes an install of the Qt Visual Studio addin

QT_PATH => C:\Qt\Desktop\Qt
QT_DIR => %QT_PATH%\4.8.1\msvc2010
QT_PLUGINS_DESIGNER => %QT_DIR%\plugins\designer\


*****FOR DESIGNER******
//Auto-load qt libraries you'll reference and some other convenient settings
Create a Qt Designer Plugin project in visual studio (file, new, project, ..)

//This makes the dll usable by designer
In the <PLUGIN_PROJECT_NAME> -> Properties -> Configuration Properties -> General ->
set output directory to QT_PLUGINS_DESIGNER
set configuration type to "Dynamic Library (.dll)" //if it isn't already
--optionally you may also build it a second time with another output directory.
Either way, the below "Your_desired_lib_folder" references the output directory of
this plugin. If you use multiple directories, be sure to build to each one each time.


*****FOR USE IN PROJECTS*****
//This makes the dll usable by other executables/code
If (the following steps are confusing, refer to "Reference 1"){

For each class in this <PLUGIN_PROJECT_NAME> you'll need to add __declspec(dllimport)
(in the header file)
--E.G. "class foo" becomes "class __declspec(dllimport) foo"

For each member function of said class NOT DEFINED IN THE HEADER FILE you'll need to
add __declspec(dllexport) before the function in the source file.
--E.G. "void bar(){}" becomes "__declspec(dllexport) void bar(){}"
}

//Tells the project which library you'll be using (in addition to what is already loaded)
In the <PLUGIN_USER_PROJECT_NAME> -> Properties -> Configuration Properties -> Linker -> Input
Add that <Your_Plugin_Name>.lib to your "Additional Dependencies"

//Allows your project to find the .lib file
In the <PLUGIN_USER_PROJECT_NAME> -> Properties -> Configuration Properties -> Linker -> General
Add that <Your_Desired_Lib_Folder> to your "Additional Library Directories"

//Allows project to find your .dll
In the <PLUGIN_USER_PROJECT_NAME> -> Properties -> Configuration Properties -> Debugging
Add your <Your_desired_lib_folder> to your PATH variable. Seperate it via a semicolon:
--E.G.<CURRPATH> would now be <CURRPATH>;<Your_Desired_Lib_folder>








References:
1 - http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/DLL-Tutorial-For-Beginners.htm

amleto
1st August 2012, 18:42
"For each member function of said class NOT DEFINED IN THE HEADER FILE"

How can a member function not be declared in the header?

tescrin
1st August 2012, 21:12
It says "defined", not declared.


//Header_file.h
class foo{
//stuff..
//function that is declared and DEFINED in the header file
void bar() {return 0;}

//function that is declared but DEFINED in a cpp file
void derp();
};

amleto
1st August 2012, 21:18
fair point, but your example uses a method that IS defined in the class...

If you export the class then I don't think you need to export any members explicitly.

tescrin
1st August 2012, 22:02
The example function is referring to a function that wasn't in a class. I.E.


//Header.h

class __declspec(dllimport) foo
{
void glarc() {}; //!!<-this is not what the comment is referring to
void bar()
}


//source.cpp
__declspec(dllexport) void foo::bar() {} //!!<- this is what the comment is referring to

amleto
1st August 2012, 22:40
In that case, no, that is wrong. You do not need to use the __declspec modifier in the source.

tescrin
1st August 2012, 22:54
Just like the link in my file:
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/DLL-Tutorial-For-Beginners.htm

I'm unsure where else you'd but the modifiers. You put one at the top of the class but that's not enough; I've tried doing that. I'm happy to make the document correct, but it seems to be according to the above (and my experience thus far.)

amleto
1st August 2012, 22:57
In that case, no, that is wrong. You do not need to use the __declspec modifier in the source (cpp) file.

I think your terminology is confusing. All members are 'in the class' by definition. They may not be implemented in the class definition, though. ;)



e:
There're no classes in your link so it doens't really help on this issue...

And I know you do not need modifiers in the source because I have hundreds of working examples at work ;)


This would tend to agree with me (or I with it...)
http://msdn.microsoft.com/en-us/library/81h27t8c(v=vs.80).aspx

tescrin
1st August 2012, 23:21
huh... I swear that didn't work the first time I tried it. I hate to continue being dense, but then what does dllimport do!?

I have a plugin that works just fine without using "dllimport" at all.. I think. I'm sorry, but I really just don't follow that darn MSDN page (or we probably wouldn't be having this discussion.) Do I dllimport on some class that's in a dll that I'm trying to use? If so, why do I have an example that works without doing that :s

amleto
2nd August 2012, 09:33
you need dllimport if you #include something where the implementation is inside a dll.

You say you have something that works without dllimport - have you only included the header, and not the cpp in that example? I would expect you to receive linker errors.

tescrin
2nd August 2012, 20:04
As per the other thread, (now that I get it), I believe I had the #if defined "guards" importing/exporting it correctly. Difference being that the included directories were probably current versus non current. Time to correct my instructions. Thanks again!