Best practice on C++ distribution of headers, lib, and dll files

Started by
7 comments, last by the_edd 15 years, 11 months ago
I'm developing a library that I would like to distribute eventually. Currently I have stuck all my header information in one massive header (1100 lines, not much comment). When I build my project, I am then presented with: mylib.h mylib.lib mylib.pdb mylib.dll This is what I would like to distribute to the end user. But, I do not necessarily care for them to see all the private members. So, my question is two part: 1. In the distribution copy of mylib.h, do I need to even include the private member declarations? 2. If not, what is best practice to avoid duplicating efforts and increasing chances of copy-paste, out of sync, and typo bugs. For now, the only option I see for #2 is to keep two header files, one internal, the other for distribution.
Advertisement
Hi azherdev. I have a few comments that will hopefully help. First, is I think you know better than to have one massive header. Really, you should have one header file per class. The classes that are not used externally would then simply not get shipped with your distribution. As far as the private members, I assume you mean private members of a class. If so, I agree that private members, as well as private methods should not be in the header. However, diverging your code base is a bad idea and will be hard to keep in sync. One way to absolve this is to use the Pimpl idiom:

Compilation Firewalls
The Fast Pimpl Idiom

If you use the pimpl idiom, then the private members and private methods would exist in the pimpl in your cpp file, rather than in the header.

Finally, I would advise against distributing your pdb or a debug version of your library.

Hope this was clear and it helped. If not, I will try to explain further. [smile]
Why not distribute the source? You're distributing the pdb, anyway...

Also, I agree with Rydinare that you should try to make a distinction between internal (implementation) and external (client-accessible) headers.

When I'm writing a library, I have two folders (minimally), 'src' and 'include'. src contains .cpp files and headers that are not needed by clients. include only contains those headers that clients need to use the library. This helps in both keeping dependencies down and prevents you from inadvertently polluting the clients working area (namespaces).
Thanks for the feedback, couple of points:

1. pdb is only for the debug version

2. although this is intended to be an MIT licensed open source project, I know of a lot of people that want to include a header, link to a lib, copy the dll and go. They don't want to include source files and dependancies.

3. all of my internal classes and functions are included in a seperate file altready. My problem is for classes that I do want users to use. The private members and functions of those classes are currently in the released header file which I would like to avoid.

I am thinking of possibly having all classes inherit from an internal class that is a friend and therefore allows access to internal methods and members. ie.

class CButtonInternal
{
friend CButton;

private:
float x;
float y;
}

class CButton : private CButtonInternal
{
public:
float getX() { return x; }
// etc.
protected:
// ...
}

I just want to keep inheritance to a minimum.
Quote:Original post by azherdev
Thanks for the feedback, couple of points:

1. pdb is only for the debug version

2. although this is intended to be an MIT licensed open source project, I know of a lot of people that want to include a header, link to a lib, copy the dll and go. They don't want to include source files and dependancies.

3. all of my internal classes and functions are included in a seperate file altready. My problem is for classes that I do want users to use. The private members and functions of those classes are currently in the released header file which I would like to avoid.

I am thinking of possibly having all classes inherit from an internal class that is a friend and therefore allows access to internal methods and members. ie.

class CButtonInternal
{
friend CButton;

private:
float x;
float y;
}

class CButton : private CButtonInternal
{
public:
float getX() { return x; }
// etc.
protected:
// ...
}

I just want to keep inheritance to a minimum.


Gotcha. It definitely sounds like the pimpl idiom is the way to go for your case. The pimpl will allow you to move all private entities into implementation.

An alternate approach would be to provide Button interfaces (base class with all pure virtuals) which hold no implementation and factory methods that they could use to create concrete objects. Many component architectures use a flavor of this method. The advantage is that all of the concrete classes would be hidden internally and the only thing known would be the interface.

I don't think the solution you provided would do much, since you'd have to ship the interface to the CButtonInternal class, as well.
Thanks Rydinare.

From your posts and link and few of my own researched material, it seems that what I want to achieve requires hoops, which I do not wish to jump.

Ultimately this is an open source project and I am not "hiding" anything. Just wanted to provide a cleaner interface.

I don't want factories. This is a UI library and I want users to easily inherit from a class and extend it, override paint functions, etc. I like the .net WinForms model and how you can extend UI classes by inheriting and overriding or by creating composite controls or custom control from base control.

I know, c++ is not c#, but darn it...
Quote:Original post by azherdev
Thanks Rydinare.

From your posts and link and few of my own researched material, it seems that what I want to achieve requires hoops, which I do not wish to jump.

Ultimately this is an open source project and I am not "hiding" anything. Just wanted to provide a cleaner interface.

I don't want factories. This is a UI library and I want users to easily inherit from a class and extend it, override paint functions, etc. I like the .net WinForms model and how you can extend UI classes by inheriting and overriding or by creating composite controls or custom control from base control.

I know, c++ is not c#, but darn it...


I see. Well, the private member declarations are required, unless you use some sort of mechanism to hide them. If hiding isn't what you desire, then they need to be there.

Now, IMHO, the methods I suggested shouldn't be seen as jumping through hoops. They're actually generally seen as good design practices. The reality is that private members and methods are really implementation details and so they shouldn't be in the interface. The main reason for this is resistance to change and not giving too much detail to the clients.

That being said, to reiterate and address your original question, if implementing some design to hide more implementation details isn't what you're looking for, then the private member variables will need to be visible to clients who use the header.
Quote:Original post by Rydinare
As far as the private members, I assume you mean private members of a class. If so, I agree that private members, as well as private methods should not be in the header.


I don't know if you think of this as obvious or not, but if you have the following:

1. private/implementation header:

class foo{private:   int v1;public:   int v2;};


2. matching stripped public/client header for redistribution:

class foo{public:   int v2;};


Then you're getting problems since layouts of the structures don't match when the client tries to use the code, and will result in program crashes. So you need to at least make the client structure layout match the implementation one somehow, and perhaps easiest is to just have the private members be present in the client header.

Member functions naturally don't have this problem since leaving out a declaration of a function will just hide it from the client.
Quote:Original post by clb
Member functions naturally don't have this problem since leaving out a declaration of a function will just hide it from the client.


No, this will cause an ODR violation and the program is subject to undefined behavior. You might get away with it sometimes, but trying to omit virtual functions in particular will lead you in to all kinds of trouble very quickly.

To the O.P: you really want the pimpl idiom as others have suggested. It's not a big deal (as far as C++ goes) and you should practice using it. It's a very useful thing to know.

This topic is closed to new replies.

Advertisement