Thread: How can I develop c++ library in header file without having multiple definition issue

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    18

    How can I develop c++ library in header file without having multiple definition issue

    Hello,

    Here is the way I want to work:

    I want to develop a library file that is a wrapper to win32 functions.
    Let's call it "win32helper.h".

    My win32helper.h is a library that I am willing to use in multiple projects and not specific only in my own project.

    So I host this source file outside of the visual studio project for reuse purposes.


    In win32helper.h I write all the logic.
    Code:
    #include "windows.h"
    
    
    bool GUICreateWindow(std::string windowName, int left, int top, int width, int height) {
    	
    	// Here I call to win32 functions such as CreateWindowEx
    
    
    	return true;
    }
    Then, I have other source files where I need to use my win32helper.

    So let's say I have 2 GUIs windows:

    MainProgramGUI.cpp
    Code:
    #include "win32helper.h"
    
    namespace MainProgramGUI {
    	int CreateMainProgramGUI() {
    		// Here I use functions from win32helper.h to easily build my GUI window
    	}
    
    
    	// .. More functions will be here about this main GUI
    }

    SettingsProgramGUI.cpp
    Code:
    #include "win32helper.h"
    
    namespace SettingsProgramGUI{
    	int CreateSettingsGUI() {
    		// Here I use functions from win32helper.h to easily build my GUI window
    	}
    
    
    	// .. More functions will be here about this main GUI
    }



    And after all of this, I also need to call these functions of SettingsProgramGUI.cpp, MainProgramGUI.cpp from the code of main.cpp

    So I create headers files:


    MainProgramGUI.h
    Code:
    namespace MainProgramGUI {
    	int someValue = 10; // Variable that I want to be global for all namespaces 
    	// .. More global variables like the above will be here
    
    
    	int CreateMainProgramGUI(); // Definition.
    	//.. More forward functions declarations like the above will be here
    }


    SettingsProgramGUI.h
    Code:
    namespace SettingsProgramGUI {
    	int someValue = 10; // Variable that I want to be global for all namespaces 
    	// .. More global variables like the above will be here
    
    
    	int CreateSettingsGUI(); // Definition.
    	//.. More forward functions declarations like the above will be here
    }

    Finally, in main.cpp:
    Code:
    #include "winl32helper.h" // I still want to include this because I may want to use it from here
    #include "MainProgramGUI.h"
    #include "SettingsProgramGUI.h"
    
    
    
    
    int main() {
    	// Here I call to functions such as
    	// MainProgramGUI::CreateMainProgramGUI() , SettingsProgramGUI::CreateSettingsGUI()
    	return 0;
    }

    My problem that I can't even get this thing to work.
    There are so many errors about it.

    All I wanted is to have some source file called win32helper.h that I can reuse where I want. but I can include it only once!

    I want to include it multiple times.
    Or at least I need to include it only in main.cpp and the compiler will see it as if I included it for all other source files.

    But nothing I tried worked for me.

    Please help me to get started.

    Thank you.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    In win32helper.h I write all the logic.
    What you meant is that you wrote the non-template function definitions in the header file. This is problematic because if the header file is included in more than one translation unit, the function would be defined more than once, and this is not allowed.

    There are two reasonable solutions:
    • Forward declare the function in the header, moving the function definition to exactly one source file. This way, the function is only defined once, but can be used anywhere by including the header.
    • Declare the function to be inline, as inline functions can be defined in multiple translation units without breaking the one definition rule. You run the risk of executable code bloat, but your compiler is probably smart enough to minimise that risk.

    Note that you should use header inclusion guards: even inline functions would break the one definition rule if defined more than once in the same translation unit.
    Last edited by laserlight; 04-13-2019 at 07:23 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    I know that if I add inline keyword before variables (will work on C++17) and functions then I can include my "win32helper.h" file multiple times.
    But what does inline means in a header file?

    From what I know, If I will inline a function with a body (this is my case in win32helper.h) then the compiler will replace every function call to the actual code in the function and this is not what I wanted. I only want that the compiler will set the definitions to be global for all source cpp files. so from any cpp file, it can access the functions in "win32helper.h"


  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    From what I know, If I will inline a function with a body (this is my case in win32helper.h) then the compiler will replace every function call to the actual code in the function and this is not what I wanted.
    You are mistaken. That is not inlining a function; that is defining a function. Declaring a function as inline requires either the use of the inline keyword, or placing a member function definition in its class definition. Either way, the compiler is free to ignore this hint to inline the code.

    The more traditional approach is the first approach I described: put the function definition in a source file. The second approach has gained some popularity with header-only libraries due to the extensive use of templates.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    The second approach has gained some popularity with header-only libraries
    I am not surprised. The first approach is complete nonsense and I never wanted to force to use the first approach even if it's a standard.
    "standard" doesn't always means a "good" way of doing things.

    I don't want to use the first approach if I have the option to use the second approach. having to build a library with a header file and source file? no thanks.

    You are mistaken. That is not inlining a function; that is defining a function. Declaring a function as inline requires either the use of the inline keyword or placing a member function definition in its class definition. Either way, the compiler is free to ignore this hint to inline the code.
    So why you said that I have "risk of executable code bloat" ? you did not mean that the compiler will place the function code where there is every function call?

    If I use in a header file:

    Code:
    inline void SomeFunction() {
    // Lot of logic 
    }
    Then you say that when I will compile code that calling to SomeFunction(), the compiler will not write the function body instead of the function call?
    Last edited by gil900; 04-13-2019 at 07:46 AM.

  6. #6
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    The second approach has gained some popularity with header-only libraries due to the extensive use of templates.
    And can you show me examples from GitHub to some header-only libraries?
    As long as I can include header-only library in multiple source cpp files then I want to see.

    Thanks

  7. #7
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    I found my solution.
    The problem begins because the way the C++ compiler works sucks.
    The whole idea to create multiple translation units per each cpp file is completely broken idea.

    My solution to the problem is to force the compiler to work with only one translation unit.

    This is my setup

    main.cpp:
    Code:
    #include "win32helper.h" // header-only library. I may want to use it from here.. 
    #include "MainGUI.cpp" // specific code for this project 
    #include "SettingsGUI.cpp" // specific code for this project 
    
    
    
    
    // Program Entry
    int main() {
    
    
    	// Here I call to functions in namespaces MainGUI, SettingsGUI
    
    
    	SettingsGUI::CreateGUI();
    	while (SettingsGUI::mainGUI != NULL) {
    		SettingsGUI::ProcessGUI();
    	}
    
    
    
    
    	MainGUI::CreateMainGUI();
    	while (MainGUI::mainGUI != NULL) {
    		MainGUI::ProcessWindow();
    	}
    
    
    	// Just I want to call directly to my helper functions
    	HWND myOtherWindow = win32helper::CreateGUI(0, 0, 100, 100);
    	if (myOtherWindow) {
    		// Do here stuff
    	}
    	
    	return 0;
    }
    You need to do the following for any cpp file other than main.cpp:

    Screenshot by Lightshot

    "excluded from build" option need to be set to "Yes" for these files.
    I including them in main.cpp (as you can see)


    win32helper.h:
    Code:
    #ifndef WIN32HELPER
    #define WIN32HELPER
    #include "windows.h"
    
    
    // This is header-only library
    
    
    namespace win32helper {
    
    
    
    
    // Definition Section (Forward functions)
    	// Global variables
    	HWND activeHwnd = NULL;
    	// More variables go here
    
    
    
    
    	// Forward functions declarations just in case some function needs to call other in this namespace
    	bool SwitchToWindow();
    	HWND CreateGUI(int x, int y, int w, int h);
    	bool DeleteGUI(HWND hwnd);
    
    
    // Implementation Section
    
    
    	// Functions
    	bool SwitchToWindow() {
    		// Some code to do stuff
    		return true;
    	}
    	HWND CreateGUI(int x, int y, int w, int h) {
    		// Some code that use win32 API
    		return NULL;
    	}
    
    
    	bool DeleteGUI(HWND hwnd) {
    		// Some logic to delete the GUI that use Win32 API
    		return true;
    	}
    	// More functions go here
    }
    
    
    #endif
    MainGUI.h:
    Code:
    #include "win32helper.h"
    
    
    namespace MainGUI {
    
    
    	// Global variables
    	enum enumGuiState {ACTIVE, NOT_ACTIVE};
    	HWND mainGUI = NULL;
    	int currentState = ACTIVE;
    
    
    	// Functions
    	bool CreateMainGUI();
    	void ProcessWindow();
    
    
    }
    MainGUI.cpp:
    Code:
    
    #include "MainGUI.h" //  Definition Section (Forward functions)
    
    
    // Implementation Section (This file is the implementation section)
    
    
    
    
    namespace MainGUI {
    
    
    	bool CreateMainGUI() {
    		// Some code that use functions from win32helper.h
    		HWND window = win32helper::CreateGUI(0, 0, 300, 300);
    		return window != NULL;
    	}
    
    
    	void ProcessWindow() {
    		if (currentState == ACTIVE) {
    			// Do something
    		}
    		else {
    			// Do something else
    		}
    	}
    
    
    }
    SettingsGUI.h:
    Code:
    #include "win32helper.h"
    
    
    namespace SettingsGUI {
    	
    	// Global variables
    	enum enumSelectedTab { GENERAL, OTHER };
    	HWND mainGUI = NULL;
    
    
    	// Functions
    	void ProcessGUI();
    	void CreateGUI();
    	void CloseGUI();
    
    
    }
    SettingsGUI.cpp:
    Code:
    #include "SettingsGUI.h" //  Definition Section (Forward functions)
    
    
    // Implementation Section (This file is the implementation section)
    
    
    
    
    namespace SettingsGUI {
    
    
    	// Functions
    	void ProcessGUI() {
    		// Do stuff
    	}
    	void CreateGUI() {
    		win32helper::CreateGUI(0, 0, 100, 100);
    	}
    	void CloseGUI() {
    		win32helper::DeleteGUI(mainGUI);
    	}
    
    
    }

    This is the way I could go with it.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    So why you said that I have "risk of executable code bloat" ? you did not mean that the compiler will place the function code where there is every function call?
    Yes, if you have a terrible compiler with no notion of examining inline functions to see if they actually are good candidates for inlining. In practice, compilers will have metrics that will prevent them from bloating the executable code.

    Quote Originally Posted by gil900
    Then you say that when I will compile code that calling to SomeFunction(), the compiler will not write the function body instead of the function call?
    Yes, unless say with whole program optimisation it can prove that the function was only called in one place.

    Quote Originally Posted by gil900
    And can you show me examples from GitHub to some header-only libraries?
    Not off the top of my head, but many libraries within the famous Boost collection are header-only.

    Quote Originally Posted by gil900
    You need to do the following for any cpp file other than main.cpp:

    Screenshot by Lightshot

    "excluded from build" option need to be set to "Yes" for these files.
    I including them in main.cpp (as you can see)
    DON'T DO THIS. You are entitled to your own opinions, and indeed the next version of the C++ standard (C++20) is expected to allow C++ programmers to do away with the header/source divide through a brand new module feature, but until that happens it is still extremely strong convention that a source file is intended to be compiled into a translation unit, whereas a header is expected to be included, and never the twain shall meet except via a #include of a header.

    Along with strong convention that a file extension (or merely just a file name ending with) ".cpp" is a source file, it means that, like it or not, you must never #include .cpp files. Failure to abide by this strong convention is a recipe for confusion, i.e., it breaks the principle of least surprise.

    That said, the Boost libraries have a convention that when you want to have a "source file" that is to included into a header, you can still do it: just name it with a .ipp ("i" for implementation) extension instead. Due to the then-unconventional file extension, it won't be recognised as a "to be translated into a translation unit" source file, both by humans and compilers. These .ipp files can then be included in headers, and in turn your source files (only one, if you wish) will include the headers.

    However, this still means that your code that goes into these .ipp files must be able to be included in multiple translation units, i.e., either they are template code or they have been declared inline.
    Last edited by laserlight; 04-13-2019 at 11:46 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    Can you explain what are the benefits of multiple translation units per each cpp file?
    How it can help me?

    It makes more problem than it solves.

    Besides that what I suggested is very against the familiar way to do it and it and it "breaks the principle of least surprise", what are the disadvantages?


    The idea is to include library.cpp file that then include it's library.h file.

    library.cpp - all code go inside here and it includes library.h.
    library.h - all declarations go inside here

    Then in main.cpp I include library.cpp
    It is so much simple. I only need to enable "excluded from build" for library.cpp

    And thanks for the inline suggestion. If you say that I should be fine with it then maybe I will go with this.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    Can you explain what are the benefits of multiple translation units per each cpp file?
    How it can help me?
    They are part of the C heritage of C++. Decades ago, they would likely have been very useful to break a large program into smaller parts, each of which could be compiled quickly, possibly by different programmers. With the advent of extensive template programming in C++, this wasn't such an advantage any more, but thankfully both computer and compiler tech has advanced such that compilation can be faster, so we're seeing more and more libraries move to be header-only.

    Related to this would be that separate translation units correspond to binary library files, so that would have been an advantage for library authors hoping to not distribute their code, but again with the move to template programming this has become less of a concern as template code generally must be kept in headers rather than hidden in compiled source files.

    Quote Originally Posted by gil900
    Besides that what I suggested is very against the familiar way to do it and it and it "breaks the principle of least surprise", what are the disadvantages?
    That is a disadvantage so strong that it overrides any advantages that you might perceive.

    Quote Originally Posted by gil900
    Then in main.cpp I include library.cpp
    It is so much simple.
    ... until someone tries using your library with multiple translation units, or someone else tries contributing to your library using say, a different setup, finds that it fails to compile, looks in horror at your code, and you get lamblasted to hell for being a bad C++ programmer playing at being a library author.

    So don't be that guy: either stick to headers and conventional file extensions for headers, making sure the code that goes in them are templates or declared inline, or use .ipp files that are included in the headers, with the code in them also templates or declared inline.

    In fact, allowing variables to be declared inline in C++17 was precisely to make developing header-only libraries easier: it doesn't make sense to hint to compilers to "inline the code" with variables as it did with functions, i.e., the inline keyword has become less of a hint to the compiler to inline code, and more of an instruction to the compiler to avoid breaking the one definition rule.
    Last edited by laserlight; 04-13-2019 at 12:34 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    I was wrong in my example. I did not mean to use this for a library (so you include library.cpp that includes library.h)
    I more meant to some component of software that is not a library. It is a logic component that is part of the component.

    So everything you wrote here
    ... until someone tries using your library with multiple translation units,
    Is irrelevant.


    You say that there are no other disadvantages of the new approach other than that it is too much non-standard.

    Then I will say that if everyone will think like this then nothing progress so the language will be stuck in the past.
    Someone needs to think differently to make progress. I have no problem being like that because I have nothing to lose

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    You say that there are no other disadvantages of the new approach other than that it is too much non-standard.
    Unconventional, not non-standard. The standard doesn't forbid including files of whatever extension you want, or of only having a single translation unit.

    Quote Originally Posted by gil900
    Then I will say that if everyone will think like this then nothing progress so the language will be stuck in the past.
    The progress with respect to the standard will be when the modules feature is introduced into the standard sometime next year. There's news that it was included in the finalised list of new features, so hopefully it'll go through this time. It remains to be seen how it will affect the current way of doing things though, but I find it hard to imagine that there won't be changes.

    Quote Originally Posted by gil900
    Someone needs to think differently to make progress. I have no problem being like that because I have nothing to lose
    So, what's wrong with using .ipp files with a single translation unit? What advantage does your proposed method of using .cpp to mean both source file and header file have over this approach?

    Basically, the idea is to use different file extensions to mean different things. Your insistence on including .cpp files is thus mind-boggling when you can use .ipp to eliminate such confusion.
    Last edited by laserlight; 04-13-2019 at 01:08 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    I did not said that it is wrong. I just did not understand it.

    You say that the idea is the same as I suggested but just use ipp extension instead of cpp ? It sound to me great.

    But is visual studio will highlight the syntax as c++ code?

    About the modules feature in c++20, it sound for me as somthing that supposed to be from the very beginning or at least not so far after year 2000.
    Why it took so long time? Anyway it is better than never

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by gil900
    You say that the idea is the same as I suggested but just use ipp extension instead of cpp ? It sound to me great.

    But is visual studio will highlight the syntax as c++ code?
    Newer versions of Visual Studio might support it out of the box, if not you can always add it to the list of file extensions recognised as containing code.

    Quote Originally Posted by gil900
    About the modules feature in c++20, it sound for me as somthing that supposed to be from the very beginning or at least not so far after year 2000.
    Why it took so long time?
    It's called "design by committee". You can end up with some pretty good stuff because of the mix of ideas, but you can also end up with committee members failing to agree on some fundamental stuff so it gets delayed version after version, especially when you already have stuff that works even if it may be clunky.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    Registered User
    Join Date
    Apr 2019
    Posts
    18
    So the deal is that i will use ipp extension
    But I am not sure I understand.

    Should I include ipp file inside header file and then in main.cpp and the ipp file I should include the header?

    I meant to include in main.cpp the ipp file and in ipp file include the header

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 05-10-2017, 06:27 AM
  2. inline function in header, multiple definition
    By cyberfish in forum C++ Programming
    Replies: 5
    Last Post: 06-14-2009, 01:21 AM
  3. using definition from header file without including it
    By amitbern in forum C Programming
    Replies: 7
    Last Post: 08-02-2007, 04:48 AM

Tags for this Thread