class A { public: int i; }; // A.h and defined in project libA.vcxproj (libA.dll)
I’m using class A in multiple places at various projects as below. Apporoximately 100 projects.
include "A.h"
class UseA { public: A *a; UseA(){ a = new A(); } ~UseA() {delete a;} }
My problem is whenever I add a member variable to class A I will have to build all the projects (~100) as the size of the class A has been changed and building 100 project is time consuming.
How to avoid building so many projects on size change of a single class? Also I have many classes like class A defined in libA.vcxproj.
1
Are you familiar with the PIMPL idiom? For certain cases, it can solve this exact problem. The short version is that you wrap all your private member variables into one opaque pointer to a type so that when you add a new private member you don’t need as much recompilation…
4
First make sure you really need this – having a central library which is reused more than 100 times works better when the public interface of that library does not change too often or only at specific points in time. Check if it is possible to split up your library in smaller parts, so that changes in one part don’t affect the dependent projects of the other parts. Check also if it is possible to develop any changes to that library first “in private”, and publish them (visibly for the majority of dependent projects) only for new “major releases” of that library.
But let’s assume your project dependencies are correct and necessary for your system, and you really need to extend the public parts of that central library (or central class “A”) very often. Then, you cannot avoid that all dependent projects have to be recompiled. But since you typically don’t make changes to all the 100 projects simultaneously, you don’t have to recompile them all on your local workstation.
What you need in this situation is a build server – a server which automatically checks out all changes from your SCCS and runs a full build of all the 100 projects in the background. For setting up such a system, you will also need a good structured automatic build process. Hopefully your 100 projects can be split up into groups of projects which can be individually compiled and tested, otherwise you have to solve that problem first.
Also a good read, though a bit outdated: Large Scale C++ Software Design by John Lakos. This book will also explain the PIMPL idiom mentioned by Jtrana in depth, though this will only help you with the private parts of your classes, not with the public ones like in your example.
In addition to the answers by Doc Brown and J Trana.
-
Doc Brown’s answer points out that whole-project rebuild is very much necessary in software development; therefore try to reduce the pain by using build automation, instead of avoiding it.
-
J Trana’s answer is a form of encapsulation or information hiding. If most of the users of class A do not need to access the new member, then these steps can be taken:
- Make the new member private
- Put the new member inside a private sub-member of class A, and initialize it in A’s constructor.
- Provide accessor methods (getter and setter) for the new member.
- Note that this still requires rebuilding the whole project, because in C++ any change in a header file will have required a rebuild.
-
My suggestion #1 (vendor specific)
- Some C++ compilers have options for improving the performance of the build process.
- Examples: “incremental build”, “build with multiple processes” etc.
-
My suggestion #2:
If you really must reduce the time spent on rebuilding while you are making many small experimental changes that involves new members, consider converting data members into property bag.- A property bag is a dictionary (std::map) from string to variant values.
- If the class A provides get/set methods for this dictionary, then the addition and removal of new keys will not require a rebuild.
- However, the drawbacks are:
- It will be a lot slower to read from and write to the values in the dictionary, compared to accessing a class member.
- The whole project will be more prone to errors, because the compiler will not be able to perform name checks and type checks on the keys and values stored in a property bag.
- Example:
A compiler can catch the bug where one tries to access a class member that does not exist.
A compiler does not automatically catch the bug where one accesses a dictionary key that does not exist. The programmer must write code to handle this situation.