Hiding contents of opaque struct when used from static lib - c++

I have a library project which contains opaque structures of different types.For example:
OpaqueTypes.h
typedef struct FooObject_t *FooObjectPtr
FooObjectPtr CreateFooObject();
OpaqueTypes.cpp
struct FooObject_t
{
uint32_t id;
uint32_t someProp;
};
FooObjectPtr CreateFooObject()
{
FooObjectPtr fooPtr = nullptr;
//Create new instance and cache it
return fooPtr;
}
I compile this code as a static library.Another project is an executable which links with that library. It has no access to definition of FooObject_t . Yet,when I run the application in debug mode, I can see all the members of FooObject_t pointer. The only setup which completely hides the internals of FooObject_t ,even from debugger, is if I compile OpaqueTypes lib as DLL.
I have two questions:
How debugger can see the implementation details of FooObject_t in main application when OpaqueTypes is compiled statically with definition hidden, but it can't see it when the lib is DLL?
Is it possible to hide the implementation details completely when working with static lib?
I am using Visual Studio 2019

It is possible because the static lib, compiled with debug on, holds the references to the source files with full object description.
I suppose that the full object is visible debugging functions inside the library, it shoul be opaque when debugging exe functions.
Try to debug using a library compiled without debug info, that is the one you are supposed to supply, and the definition should result opaque.
When using the DLL the pseudo-lib used for the dynamic linking shouldn't contain debug info, although when inside, if DLL has been compiled with debug on, you should still able to see the structure.
Last, things depend also on the compiler used, on the debugger, on which directory are used to run the test, etc...

Related

How to force include static objects from a static library in C++ (MSVC 11)

I am trying to initialize a static object in a C++ file which is trying to auto register a class to a factory in its constructor (like any standard auto-registration problem). The problem is, this is compiled to a static library, and while linking to an executable, that is optimized away. There should have been a very simple solution to that, but surprisingly, looks like it's not that simple.
Here's my class:
In Factory.h (part of static lib project)
class DummyClass : public BaseFactoryClass
{
int mDummyInt;
public:
DummyClass()
{
std::cout << "Pretending to register myself to the factory here\n";
}
};
In some cpp, let's say Circle.cpp (still part of the static lib project)
static DummyClass dum;
main.cpp (part of the executable)
//some code accessing the BaseFactoryClass of the Registered derived classes.
Now, since the static object is not 'directly' used in the executable project, it's skipped from the linked library.
I want to make it work in MS VC11 (Visual Studio 2012) (and GCC 4.8.*, but that's for later). Looking at other questions, I tried various things so far, which don't seem to work:
Looks like /WHOLEARCHIVE linker option is only supported from Visual
Studio 2015 (We're using VS 2012)
Specifying /OPT:NOREF should have worked (I tried several combination of this with other flags like /OPT:NOICF), but it doesn't work for anyone.
I tried #pragma comment (linker, "/include:symbolName") in the header file, but that gives a linker error about symbol being unrecognized. (And also that wouldn't work in GCC, but probably --whole-archive works there).
There is a flag in Visual Studio Linker Settings that allows linking all object files individually rather than the static lib, but I don't want to go that route. Also, preferably I'd just want to write something in the source (.cpp) of each individual class I want to automatically register, with all the boiler plate code and macros being in a central header like BaseFactory.h etc. Is there any way to do it (even in C++ 11 where there's a guarantee that a symbol will be initialized)? Want to make the registration of a new class as easy as possible for any new developer.
In MSVC you have a linker pragma you can use for that purpose:
#pragma comment (linker, "/export:_dum")
This way whenever the linker is run, it will force link _dum in your executable or DLL.
A better way, though, would be to consider using a DLL instead of a static library. Then you avoid this problem altogether since on each load of the DLL that static variable will be initialized.

Static variables in static lib vs dynamic dll

I'm not too sure of how to ask this, so please comment if I'm being unclear about something.
I have a project which uses a custom class called CManager. Most of my classes in this project inherit from this one and in CManager() (constructor), I add one to the count of CManager object, the count being a static variable in this class. Now, this project used to be compiled as a .dll (dynamic library), but my employer asked me to compile it as a .lib this time, while stripping away a lot of code. Now I have stripped away all the code that wasn't needed and compile it without error... But, when I am creating a .lib, I get an error when I try to execute the program saying that there is an unhandled access violation reading. Here is the code
int CManager::m_count = 0;
CManager::CManager()
{
++m_count; <- Exception here
}
I don't know why I have this error. m_count is a private static int variable declared in the .h.
Since I didn't understand why it wasn't working, I tried compiling the project as a .dll, just so I wouldn'd be doing nothing. And for some reason... it worked. It compiles AND execute (run, wtv).
Now my question is... why is this happening? What explains this?
PS: This project has to include 5 other projects' .lib (or dll), but it work either ways. This project is included by my main, and it is when I try to execute my main that I get the error. The project is just a bunch of algorithms, my main app being the GUI. My main app is an MFC app.
Thanks!
EDIT 1:
While debugging, I found out that if I import the project using a static lib, when passing from my main's function call to the .lib implementation, I loose the object: I call a function on my object, and when I'm in the function, the value of this (refering the object) is null.
If I used a dll, it works perfectly. The object keep its value when a function is called on it.
But I still want to use a .lib, so I don't really know why this happens and how to fix it.
I found it. Like Mark Ransom said in the comments, the problem was not in the code, it was in my project properties. I was creating a .lib instead of dll, but didn't change the runtime library accordingly. So in Project Properties -> C/C++ -> All Options -> Runtime Library, I started using MD and it worked.
Also make sure Runtime Library and general use of MFC are compatible, look here for details.
I'm still not to sure of how using MT created problems, but at least I can run my program now.

utilizing a static library to create an import library

I am interested in using my static lib to create a dll (implicitly linking). which means I need to (in vs2008)
create a dll project that should generate the following:
header file (which have export function declarations. These are simple wrappers to actual functions in the static lib using __declspec(dllexport) which are in the .cpp )
import lib which will be made as a result of creating the dll
the actual dll which is created.
I have made a test program that will utilize the above dll(including the import lib/header files) to test it.
in this I have included all the three items. now the exe compiles/links without issue.
however in the main.cpp when i call the exported functions (with the associated __declspec(dllimport) call it never seems to execute. I am uncertain why this is?
Its almost like the even though the exe can see the exported function in in the dll...the dll cannot call on the code that is in the static lib?
i just cannot answer why my exe can't see the code in the static lib? do i need an archiver/librarian for vs2008 to include all those obj files as part of the import lib?
I am at a loss and am not sure how to test this?
other than just making my static lib directly into a dll. I wanted to try this method. I know i am missing something...i have read all over the place and i am just stuck. There were some threads here that had some people posting something similar but i can't seem to get it. please be as detailed as possible as I am new to this. thanks again.
update 1:
ok so currently i added the extern line to the function prototype and now it sees the exported function from the dll. however, now the only issue left is that:
i can't invoke the function that this exported function (aka wrapper) is trying to call. which happens to be in the static library. how should my exe get visibility to that static library function. I know it can be done because I think there was one other person on this board who was able to make this work.
update 2: my setup is exactly like this questioner...
How to force inclusion of an object file in a static library when linking into executable?
but i am not using explicit linking. i am using implicit linking. my real issue is how to call a static lib function in my dll wrapper which is exported to the exe?
If the app and DLLs are MFC app/dlls, then make sure that the application and all dlls are either "Debug" versions or "release" versions and not a mix.

C++ wrapper DLLs to static LIBs

I have some statically compiled libraries (.lib) that I use in my project, which is written in C++ and built on both Windows and Linux. At my project's entry-point to these libraries, I use just one or two functions from the 'main' library in the static library suite, really (but I'm sure that these functions call many others in the other libraries in the suite).
I would ideally like to instead have a suite of dynamically linked libraries (DLLs) that wraps around each of the libs in the static lib suite; I've read/heard that the way to do this on Windows (e.g., Visual Studio 2005/2008/2010) is to "create a wrapper DLL" with some exposed functions calling the underlying static library functions. I would very much appreciate if someone can give me some detailed step-by-step including possibly some snippets, of how to go about doing this in MS Visual Studio 2005/2008/2010. I am sure some of you may already be doing this on a day-to-day basis; your experience is very much appreciated.
Edit:
For the benefit of others like myself, I am posting the first 'useful' link I found:
http://tom-shelton.net/index.php/2008/12/11/creating-a-managed-wrapper-for-a-lib-file/
"Convert a library to another library type" seems easy, but it is not. There is no straight-forward step-by-step way to do this because C++ and DLLs do not play well together at all, and your code will need to be adapted to support a DLL interface.
A concise way to describe the problem is this:
A .lib's interface is C++
A .dll's interface is C
Thus, a DLL's interface simply doesn't support C++ and you need to be clever to make it work - this is why the ambiguous existing answers.
One standard way is via COM, which means building an entire COM wrapper for the library, complete with class factory, interfaces, objects, and using BSTR instead of std::string. I would guess is not practical.
Another solution is to create a C interface for your C++ library which is DLL-safe. That means basically creating a winapi-style interface, which again is probably not practical or defeats the purpose of using your library at all. This is what #David Heffernan suggests. But what he doesn't address is how you must change your code to be DLL-compatible.
An important but subtle problem is you cannot pass ANY templated C++ objects across DLL boundaries. This means passing std::string in or out of a DLL function is considered unsafe. Each binary gets its own copy of the std::string code, and there's no guarantee that they will happen to play nicely with each other. Each binary (potentially) also gets its own copy of the CRT and you will mess up internal state of one module by manipulating objects from another.
Edit: You can export C++ objects in MSVC using __declspec(dllexport) and importing them using __declspec(dllimport). But there are a lot of restrictions on this and subtleties that cause problems. Basically this is a shortcut for getting the compiler to create a cheap C-style interface for your exported class or function. The problem is it doesn't warn you about how much unsafe stuff is happening. To reiterate:
If there are ANY templated symbols crossing DLL bounds, it is not safe (std::* for example).
Any objects with CRT-managed state should not cross DLL bounds (FILE* for example).
If you do not care about interface adaptation at all, you can export symbols from a static .lib to a .dll fairly easily. The trick is, you do not use Visual Studio GUI or projects at all, but just the linker (link.exe).
With this method, C symbols will remain C symbols and C++ symbols will remain C++ symbols. If you need to change that, you need to write wrapper code (e.g. extern C interfaces). This method simply presents existing symbols from the .objs in the .lib as official exports from the DLL.
Assume we have a .lib compiled from a source TestLib.c
#include <stdio.h>
void print(char* str)
{
printf("%s\n", str);
}
int add(int a, int b)
{
return a + b;
}
We compiled this into a static lib TestLib.lib. Now we wish to convert TestLib.lib to TestLibDll.dll (the base name should not be the same or you will get issues with the link output since the linker also creates DLL link .lib). To do this, we use link.exe outside Visual Studio GUI. Launch the "x64 Native Tools Command Prompt for Visual Studio xx" to get a cmd with the toolchain in path. (If you need 32 bit version, use x86 Native Tools instead). Change to the folder with TestLib.lib (e.g x64\Release). Then run:
link /DLL /EXPORT:add /EXPORT:print /OUT:TestLibDll.dll TestLib.lib
This should produce TestLibDll.dll. (The linker may complain a bit about there being no .obj, but you can ignore this.) The exports are:
dumpbin /exports TestLibDll.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file TestLibDll.dll
File Type: DLL
Section contains the following exports for TestLibDll.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 00001080 add
2 1 00001070 print
We have successfully exported the functions.
In the case there are many functions, using /EXPORT is tedious. Instead make a .def file. For our example, here is TestLibDll.def:
LIBRARY TestLibDll
EXPORTS
print #1
add #2
The linker is then run as
link /DLL /DEF:TestLibDll.def /OUT:TestLibDll.dll TestLib.lib
This example uses x64 C symbols, which makes it straightforward. If you have C++ symbols, you need to provide the mangled version of the symbol in the /EXPORT argument or in the def file. For more complex situations than a single static lib, you may need to provide more link libraries on the command line and/or /LIBPATH args to point to link library folders.
Again, this method is only for exporting symbols verbatim from a static library. I personally used it to create a DLL to be loaded in Python with ctypes for a closed source static library. The advantage is you don't need to write any wrapper code or create any additional VS projects at all.
Note: the accepted answer provides a good discussion of pitfalls regarding C++ DLL interface and why C wrappers are a good idea. I did not focus on that here, only on the mechanics of getting the symbols to be exported to the DLL. Using a C interface to DLL if possible remains good advice.
This was a little big to add as a comment to tenfour's response...
If you want to still maintain a C++ API when using the DLL wrapper, you can put C++ to C conversion functions in the header file. This ensures that only C compatible data types ever cross the DLL boundary.
As an example
//MyDLL.h
class MyDLL {
public:
...
int Add2ToValues(std::vector<int>& someValues) {
int* cValues = new int[someValues.size()];
memcpy(cValues, &someValues[0], someValues.size() * sizeof(int));
int retVal = Add2ToValues_Internal(cValues, someValues.size());
someValues.assign(std::begin(cValues), std::end(cValues));
delete [] cValues;
return retVal;
}
private:
int Add2ToValues_Internal(int* valuesOut, const int numValues);
};
//MyDLL.cpp
int MyDLL::Add2ToValues_Internal(int* values, const int numValues)
{
for(int i = 0; i < numValues; ++i) {
values[i] += 2;
}
return 0;
}
One catch I ran into when doing these wrappers is that you must allocate and deallocate any memory within the header file. Since the header file will be compiled by the application that is using your library, it will use the CRT for whatever compiler you are using to build your application. All interaction with the DLL uses C, so you won't run into any runtime mismatches and all memory is allocated and freed either entirely within the DLL or entirely within the application so you don't have any cross DLL memory management issues either. In the example, I both allocated and deallocated in the header. If you need to allocate data in the _Internal function, you'll need to also add a function that allows you to free that memory within the DLL. Once inside of the _Internal functions, you are free to use as much C++ as you want.

Not all symbols of an DLL-exported class is exported (VS9)

I'm building a DLL from a group of static libraries and I'm having a problem where only parts of classes are exported.
What I'm doing is declaring all symbols I want to export with a preprocessor definition like:
#if defined(MYPROJ_BUILD_DLL)
//Build as a DLL
# define MY_API __declspec(dllexport)
#elif defined(MYPROJ_USE_DLL)
//Use as a DLL
# define MY_API __declspec(dllimport)
#else
//Build or use as a static lib
# define MY_API
#endif
For example:
class MY_API Foo{
...
}
I then build static library with MYPROJ_BUILD_DLL & MYPROJ_USE_DLL undefined causing a static library to be built.
In another build I create a DLL from these static libraries. So I define MYPROJ_BUILD_DLL causing all symbols I want to export to be attributed with __declspec(dllexport) (this is done by including all static library headers in the DLL-project source file).
Edit:
Note on unrefenced symbols: Linker options Keep Unreferenced Data (/OPT:NOREF) and Do Not Remove Redundant COMDATs (/OPT:NOICF) is set so that no unreferenced symbols will be removed.
Ok, so now to the problem. When I use this new DLL I get unresolved externals because not all symbols of a class is exported. For example in a class like this:
class MY_API Foo{
public:
Foo(char const* );
int bar();
private:
Foo( char const*, char const* );
};
Only Foo::Foo( char const*, char const*); and int Foo::bar(); is exported. How can that be? I can understand if the entire class was missing, due to e.g. I forgot to include the header in the DLL-build. But it's only partial missing.
Also, say if Foo::Foo( char const*) was not implemented; then the DLL build would have unresolved external errors. But the build is fine (I also double checked for declarations without implementation).
Note: The combined size of the static libraries I'm combining is in the region of 30MB, and the resulting DLL is 1.2MB.
I'm using Visual Studio 9.0 (2008) to build everything. And Depends to check for exported symbols.
Edit:
For the ones who wonder why I don't just build a DLL from each of the static libraries: I can't because they cross-reference each other (that's why I need to group them together in one a single DLL). I know, it's horrible I can't really understand the logic behind it.
Remember that when you link against a static LIB, by default the linker is only pulling in the functions, classes, and data that the client (which in this case is your DLL) actually references.
So what happens is this:
You build your static LIB, and that's fine. This LIB is 100% valid.
You now build your static DLL around the original binary LIB. It pulls in only the stuff that it actually references. It doesn't pull in the entire class definition which is what it needs to do. This DLL, though it builds, is invalid.
A client then uses the DLL, and expects to see a complete binary definition for the exported class, because that's what the client sees in the accompanying header file.
However the class has only been partially imported, and this is why you're getting those link errors.
To fix:
If you're able to, don't build your DLL off your static LIB. Build your DLL off the original source code. And build your static LIB off the original source code.
Otherwise you can possibly fiddle with linker settings but I strongly recommend option 1 above. Note that OPT:NOREF won't work here as OPT:NOREF has no effect on static LIBs.
What wont't fix it:
High-level linker tweaks like OPT:NOREF, anything involving COMDATs, etc. If you want those functions present, you have to make sure they're referenced, either by referencing them, or by telling the linker explicitly, "hey, this Symbol X is referenced".
As a side note:
Anytime I build a DLL or LIB, I build both a DLL and a LIB, using exactly the technique you're using. Having a single code base that can generate either a DLL or a LIB by toggling a setting is ideal. But building a DLL off of a (binary) static LIB when you own the source code for both... I'm having a hard time imagining when such a scenario would be necessary.
The problem is surely that you use the already-built static .lib in your DLL project. That cannot work, you have to rebuild the .lib so that the functions get the __declspec(dllexport) declarator and will be exported by the linker.
At that point, it just isn't all that useful anymore to create the DLL compatible version of the .lib in the first place. Just create two projects, one that creates the static .lib, another that creates the DLL. Technically it is possible to still use the static .lib in your DLL project but you'll have to export the functions with a .def file. That can be high maintenance if the library has a lot of exports.
This is probably years too late, but OP's complaint was that a private method (the destructor) was not exported from a dllexport'd class. Isn't that normal? No external user is allowed to call a private method.