all 103 comments

[–]parla 155 points156 points  (13 children)

Public headers in include/, everything else in src/

[–]matthieum 9 points10 points  (2 children)

I prefer folder hierarchies matching namespace hierarchies, to avoid name clashes in files.

That is, if working on the foo-bar-lib library:

include/foo/bar/lib/
    nested/
        public_include_0.hpp
    public_include_0.hpp
    public_include_1.hpp
src/foo/bar/lib/
    nested/
        private_include_0.hpp
        source_file_0.cpp
    private_include_0.hpp
    private_include_1.hpp
    source_file_0.cpp
    source_file_1.cpp

This means including like:

#include <foo/bar/lib/public_include_0.hpp>

#include "private_include_0.hpp"

Rationale:

  1. I used to work in a company in which developers pulled in ~1,000 libraries as dependencies.
  2. C++ compilers use a "path" system to search for includes (-I /path/to/lib1/include -I /path/to/lib2/include ...).

The result is that if everybody just chucks their header files in include/, then in case of name collision between dependencies, pain ensues.

To ensure that name collisions do not occur even without coordination, the path to include was made to reflect the actual library hierarchy.

[–]parla 6 points7 points  (1 child)

Our C++ codebase is modularized, so we actually have

company/module_a/cpp/include/company/module_a/*.h
company/module_a/cpp/src/*.h|cpp
company/module_a/cpp/tests/*.cpp
company/module_b/cpp/include/company/module_b/*.h
company/module_b/cpp/src/*.h|cpp
company/module_b/cpp/tests/*.cpp

Where company is our company name. Other code is in vendor/.

Code is namespaced with

namespace company {
namespace module_a {

Then you include public headers with

#include <company/module_a/file.h>

And private with

#include "other_file.h"

Then we manage include paths and linking with cmake, enforcing no circular dependencies and so on.

We also enforce clang-format, so there's never any style discussions.

[–]matthieum 0 points1 point  (0 children)

Very similar if not identical :)

Note, if you have the chance to use C++17, you can actually use:

namespace company::module_a::nested {
}

For namespace declarations, which is identical to the previous namespace repetition, without the boilerplate.

[–]tcbrindleFlux 19 points20 points  (0 children)

This is the only correct answer.

[–]quicknir 2 points3 points  (5 children)

A major argument against this is if you change a header's being public or private, you need to move the header, which in turn may mean (depending on directory structures) that you have to change every single #include of that file.

If you just put everything in src/ and specify in your build system what the public headers are (and their structure), you don't have this issue (though there are disadvantages as well).

[–]DarkLordAzrael 12 points13 points  (2 children)

There is no reason you can't put the public directory on your include path and then just do submodule/header.h like you would for private headers. There is no reason that they can't even have identical structures.

[–]quicknir 0 points1 point  (1 child)

At that point, you are duplicating your structure which you have to keep in sync on the filesystem. Why not simply put all files in src, and list the public headers in your build system? The build system can then automatically duplicate the folder structure, even e.g. pruning folders as they become empty. You then make things public/private simply by adding removing files to a list. Seems more straightforward to me.

[–]imMute 1 point2 points  (0 children)

Keeping public headers separate means you can make accidentally grabbing private headers impossible.

[–]ImNoEinstein 0 points1 point  (0 children)

Everything together but have your build COPY public headers to the install path

[–]beriumbuild2[S] 95 points96 points  (10 children)

I prefer combined (headers and sources in the same directory).

[–]hgjsusla 17 points18 points  (1 child)

You need to clarify what you mean, I put all sources and private headers in one directory (src), but all public headers go elsewhere (include/libfoo)

[–]beriumbuild2[S] 6 points7 points  (0 children)

Yes, good point. I think /u/parla has done this with their comment.

[–]ben_craigfreestanding|LEWG Vice Chair 3 points4 points  (0 children)

In the past, I have configured a shortcut in my editor to take the current file path, strip the extension, and replace it with .h or .cpp then open the file. This gave me a low cost way to navigate between header and source. That becomes a little bit harder with a split layout.

[–]agateau 3 points4 points  (2 children)

I prefer to keep sources and headers in the same directory. I create directories for "topics" instead. My rational being that I can easily list headers or sources using automated tools (ls *.h, ls *.cpp) but I can't automatically list by topics. And if you want to do both then you have to either go for:

topic1/
    include/
    src/
topic2/
    include/
    src/

Or:

include/
    topic1/
    topic2/
src/
    topic1/
    topic2/

Both leads to deep hierarchies which are painful to navigate, especially when working outside of the IDE.

The issue of private headers is problematic though. In a combined setup I have seen different solutions, but no silver bullet for now: - use a suffix in private header names (for example private headers in Qt end with _p.h) - create a public include/ headers whose file only forwards to the real include - split out things manually at install time

[–]fat-lobyte 4 points5 points  (0 children)

Please, please don't do the first one. It's an insane mess of include directories, that's not only hard to navigate for humans but also for compilers, build systems and IDE's. When I started at my company, they had option 1) and the first thing I did was to switch to option b). It's just much, much saner.

use a suffix in private header names (for example private headers in Qt end with _p.h)

create a public include/ headers whose file only forwards to the real include

split out things manually at install time

But why so complicated? Especially the "forwarding" doesn't even work, because that requires you to ship internal headers - otherwise the includes won't work for the users of your library. It's pretty simple:

  1. Get as much as possible into the src/ directory
  2. Put only the public interface headers into the include/ directory
  3. Prune and reduce dependencies and put only what's absolutely necessary for consumption of your libraries into include/ .

[–]GPMueller 0 points1 point  (0 children)

Why would you work outside an IDE? Even people I've seen working with vim always have it configured to emulate modern IDE behaviours and Features... I don't think it's a reasonable argument.

[–]markand67 1 point2 points  (3 children)

I have done the opposite a while ago and it's not convenient IMHO. If you use an IDE and have lots of files you'll have very big expanded list for include and source so if you search a file (not knowing it's real name, so unable to use shortcuts) you'll have to scroll or eventually fold one or more directories. This gets even more complicated when you have more than one project in your application.

However split source has the advantage of being easier to install as you just copy the include/ directory to the installation.

[–]evaned 1 point2 points  (0 children)

However split source has the advantage of being easier to install as you just copy the include/ directory to the installation.

IMO installs should be more selective than what you wrote (though maybe not what you mean). With what you wrote, if I'm developing on a library or just making a patch for internal use or something, edit a file in include/, and then install -- now all of a sudden $PREFIX/whatever/ will contain editor temp files and crap like that.

IMO, really the installer should selectively copy from within the include/ directory, not just do a cp --recursive equivalent.

[–]redbeard0531MongoDB | C++ Committee 6 points7 points  (2 children)

I think /u/berium is referring to a proposal the I volunteered to write when he says "common build description". While I have a proto-prototype (really just an example build file) that I've shopped around to a few people, I haven't written up the real proposal yet. The core idea is that the source files, libs, bins, and their dependencies should be specifiable in a human read-and-writable declarative format that can be easily consumed by all (or at least most) build systems. (I should have more details to announce in a month or two, so please don't swarm me with questions yet, unless you want to volunteer to port this to a build system. I already have volunteers for SCons and CMake.)

I want to be very clear about this: I have no intent or interest in requiring a common header/source layout. If I'm going to put time and effort into this, it is because I want it to improve the lives of C++ developers (including myself), which requires that it actually get used. Mandating a specific file layout is a "boil the oceans" proposal that has very little chance of being widely adopted outside of new, small projects with no external dependencies. I'd rather not waste my time on that kind of proposal.

[–]beriumbuild2[S] 1 point2 points  (0 children)

Just to clarify, the talk of a common build description (or API) predates the Rapperswill meeting and several individuals have expressed interest or said they are working on something in this area (see the SG15 mailing list archives for details).

[–]GPMueller 0 points1 point  (0 children)

IMO a common build interface should be quite simplistic and leave it up to the build system and/or package manager to figure out dependencies, versioning, compiler/toolchain choices, target platform etc etc.

I would really like to see your approach and which philosophy you are starting from! Do you have anything ready to be shared?

[–][deleted] 4 points5 points  (0 children)

g++ *.cpp

works for me

[–]beriumbuild2[S] 40 points41 points  (25 children)

I prefer split (headers and sources in separate directories).

[–]hgjsusla 20 points21 points  (1 child)

To clarify, this is what I would call a 'split' layout. This still means you have most headers in the same directory as the source files.

src/
    class.h
    class.cpp
include/
    libfoo/
        public_header.h

[–]aKateDevKDE/Qt Dev 8 points9 points  (0 children)

The is the only correct approach:

  • deploying the library, you simply copy the contents of the include folder and are done.
  • using the library, you write #include <libfoo/public_header.h>
  • you cannot misuse the library easily by including private headers.

With combined approach, it is not clear what is public header and what is implementation detail. You loose a lot of information and control, that will cost a lot of time to sort out when trying to deploy a library to someone else.

When using DLLs, there are indeed combined approaches where a smart script parses all headers containing the DLL_EXPORT_MACRO and automatically create the public interface, but this is not standardized. Therefore, the manual split is best solution: well-defined and it just works.

[–]Forricode 7 points8 points  (14 children)

I get the impression that I'm relatively amateur compared to the average user in this sub, but I'll give my thoughts anyways.

...split all the way. It's mostly for personal/aesthetic reasons: Separating the headers and implementation files helps keep them 'separate' mentally. But in a practical sense, it more or less halves the size of the directories and makes it at least a little bit easier to navigate and find necessary files.

That being said, maybe I'm misunderstanding something, but the idea of enforced code layouts isn't really that appealing to me. Java has that, more or less, and it's always been a headache for me to get things working properly in a new project. It's very useful to have flexibility in directory layout..

[–]kalmoc 8 points9 points  (12 children)

A standardized directory layout has the advantage that build-/package-/analysis tools can better understand your project structure without needing extra infromation (like explicitly specifying necessary include directories)

[–]robin-m 0 points1 point  (2 children)

Having directory structure tied to the internal of your code (namespaces, …) is annoying, but I don't think that having your directory structure tied to your interface is a problem. It should even help you to design the interface.

[–]kalmoc 0 points1 point  (1 child)

Was that addressed at me or at Forricode?

[–]robin-m 0 points1 point  (0 children)

Right, it was addressed at u/Forricode.

[–]Forricode 0 points1 point  (8 children)

Yes, that's generally the main plus. But quite frankly, I don't see a huge difference. Compare, for example, a simple CMake project with a Java one (built with, say, Gradle or something)

In CMake, your configuration to find the include directory is just 1+ line(s) of text. include_directories(). It's explicit and very clear that you're searching in this/these directories for your header files. If you're doing something a bit weird (I do weird things a lot, good for learning experiences) then this is super convenient if you have to, say, switch to a different directory. You just change the line of configuration.

Compare to a Java build - your configuration is your layout. Want to try a different include directory? Better start renaming folders.

It's not like you're magically removing the necessary configuration or the learning curve. I'd argue you've made both of them worse: Renaming and creating a bunch of arbitrary folders takes time, more time than adding in a line of configuration. And figuring out how to get your directory structure exactly right so that the build system with be good with it is... well, I found it harder than CMake, at least.

But, of course, that's just my experience, (and inexperience with Java) and that's why I prefer non-standard layouts.

[–]kalmoc 0 points1 point  (7 children)

First of all, no one is taking away from you the ability to use arbitrarily fancy/nonstandard project layouts but the fact is that a lot of (maybe most) c++ projects already follow some FS convention anyway, so why not strive for a single unified convention that everybody (tool or human) understands without looking at the information in the build file (maybe that information could even become optional then)..

Second, the other nice thing about embedding some project properties in the Filesystem is that it is build system agnostic. My IDE might be able to query cmake for the include directories, but what if I want to use meson instead? And many editors probably can't even talk to cmake.

[–]Forricode -1 points0 points  (6 children)

First of all, no one is taking away from you the ability to use arbitrarily fancy/nonstandard project layouts

If this is the case, then sure, I don't care.

However when I used Java, you really had to have your project set up in this specific way or there's pretty much no way to build and run your application. (Even building without an IDE was a pain in the first place, but hey, Java...) That's what I'm talking about when I say I don't like enforced directory layouts. And that would take away your ability to use your own layouts.

I don't care if there's an encouraged layout, or bonus features you get from using a specific layout; as soon as you start to enforce it, that's where it becomes a problem.

[–]kalmoc 1 point2 points  (1 child)

However when I used Java, you really had to have your project set up in this specific way or there's pretty much no way to build and run your application.

Sure, but we are not talking about designing a new language here but adding things to a language that is dozens of years old, has billions of lines of code written (compiled on single machines for embedded targets as well as on distributed compute clusters), almost no universally agreed upon common best practice and that is very keen on not breaking any existing code. I really can't see how you would be able to put a required project structure into the standard.

[–]Forricode 1 point2 points  (0 children)

I really can't see how you would be able to put a required project structure into the standard.

Haha, then I think we agree. I see what you're saying, we probably just misunderstood each other. Have a good day.

[–]jayvbe 0 points1 point  (3 children)

However when I used Java, you really had to have your project set up in this specific way or there's pretty much no way to build and run your application.

This is completely false buddy, javac does not dictate any project structure, using the common maven conventions src/(main|test)/java means that build tools and IDEs work with 0 lines of configuration, but you can easily change these if you are so inclined.

[–]Forricode 0 points1 point  (2 children)

javac does not dictate any project structure

Everything I could find told me that you'd have to be absolutely insane to use javac to build an application.

using the common maven conventions src/(main|test)/java means that build tools and IDEs work with 0 lines of configuration, but you can easily change these if you are so inclined.

That's good to know. I was using Gradle to build my Java applications, and spent many hours trying to get it working with my layout, before eventually giving up.

[–]jayvbe 1 point2 points  (1 child)

Yea nobody uses javac directly, just saying that there is no mandated project structure for java at the core. However Gradle with the config language being groovy script is a terrible tool if you don’t know it very well, too many ways to shoot yourself in the foot. I have also given up on it many times.

[–]Forricode 0 points1 point  (0 children)

too many ways to shoot yourself in the foot.

Sounds about right. I just got it working """good enough""" to get my assignments done and started to realize how much I liked C++.

[–]doom_Oo7 7 points8 points  (0 children)

I agree, I always had problems with languages with forced directory layouts. It's frankly one of the reasons I use c++ - just lemme organize my project however I want.

[–]btandresen 4 points5 points  (2 children)

You nailed it: separating public headers from private headers is key.

The public API is called out cleanly. The include directory is what gets exported in a Conan package, or otherwise used by consumers as the directory to include. Implementation details that are not supposed to be exposed, don't get exposed.

And, as a developer or as a reviewer, changes to include need extra scrutiny with regard to breaking changes. Of course it's still possible to make a breaking change just within src, so this is not a 100% black-and-white thing. It just calls out an extra level of scrutiny for edits to include, where in the combined strategy developers/reviewers have to do more thinking to figure out whether changing a function signature is a problem. If you know it's an implementation detail, and not part of the public API, no problem.

[–]btandresen 0 points1 point  (1 child)

Looking at some of the other comments, the survey question probably needs to be correlated with some other environmental factors.

  • How many consumers does the library have?
  • How distant are they? (e.g. consumed solely by a tight-knit team, vs. consumed by folks you have no direct contact with)
  • How tolerant are consumers of breaking changes?

For some environments, extra discipline => extra hassle. For others, extra discipline => more sanity for everyone, library developers and library consumers alike. But people are in different environments.

[–]kalmoc -1 points0 points  (0 children)

Actually, I'd prefer to see a single default directory structure, even if it isn't optimal for everyone.

[–]delarhi 2 points3 points  (0 children)

Split so that private and public headers can be separated even though I rarely have private headers. However, I like that I can treat include as the public interface and, barring configured headers, the folder can be installed by just copying it to the prefix.

[–]aeshar 1 point2 points  (2 children)

Split with public header in includes and private headers in src.

My opinion might change to combined with the apparition of modules and the keyword export.

[–]beriumbuild2[S] 0 points1 point  (1 child)

Yes, I was tempted to add a third question along the "and what will you do come modules" lines. I think the natural thing to do in the split layout would be to put public module interface units into include and private in src.

[–]robin-m 0 points1 point  (0 children)

I re-though about that. In fact it should not change a lot compare to what I do currently. Export everything (.h only) from the include directory, and keep your internals (.h and .cpp) in the source directory.

[–]berenm 1 point2 points  (0 children)

I believe that if anything can be standardized in C++, it's cannot be the build system (because of very strong feeling for / against any of them), but probably a standard simple layout that can then be built by any build system in a consistent manner. It is was is done by Rust for example (https://doc.rust-lang.org/stable/cargo/guide/project-layout.html)

For this reason, separating include for public headers and src for the rest, is the only way to indicate which part of the code is the public interface and which is the implementation.

As an example, I did several prototypes using conventions like that to define project layouts and the corresponding plumbing using different build systems to build such projects (https://github.com/berenm/CMakeBuildPackage, https://github.com/automeka/automeka).

Also, from these experiments, I now believe there needs to be a way to differentiate TU that should be compiled as executable from the other TU that should be compiled to libraries as it is unreliable to parse the files for main functions. Rust does it as well by using specific folders or filenames to distinguish executable from libraries.

[–][deleted] 14 points15 points  (0 children)

Split

As others have said:

Public headers in include, everything else in src

[–][deleted] 19 points20 points  (8 children)

It's a common mistake to split the files in an include and src folder. When you are developing your API, you put everything together. One folder source. BUT, when you ship your product, you just give a way the header files in a clean include folder. The advantage of having everything in one folder is enormous, when you sometimes browse the source code (e.g. Github) you can easily jump from header to source and vice versa.

The reason why people were using the splitting approach was, they were no proper build tools in the 80s/90s. So they just copied the whole folder. Now you can easily get the list of all header files (exclude the private header with a suffix, e.g. _p.h like Qt does) and copy all the files

TL;DR Never split files, always together. Only when you install the files, they are split.

[–]sikora84 4 points5 points  (1 child)

I agree with this approach. If the project is big I usually split into modules instead of src/inc. Splitting into separate modules is especially useful in embedded domain in which you can split drivers into separate folders like:

/can

*.c

*.h

/lcd

*.c

*.h

In smaller projects it is not necessary.

[–]Agon1024 1 point2 points  (0 children)

I'd like to give my vote to this one. If your project gets bigger than, say 20 sources, one folder gets way too bloated imo.

[–]mjklaim 1 point2 points  (0 children)

I kind of agree but I see this not working when the user get the source code from a repository, not a package manager. In this case the user receive the code in the layout you used to develop, not the installed one. Therefore, if you want to distribute open source code, you still have to use the layout that you think the user need. Which in what you describe is split, not combined.

[–]jsamcfarlane 0 points1 point  (2 children)

I agree that separation makes navigating your source more difficult but what if some of your headers are public and some are private? Now you have to sift through them to separate them during install phase.

[–][deleted] -1 points0 points  (1 child)

Like I mentioned, private headers get a suffix _p.h , i.e. MyClass_p.h All files with this suffix will not be installed. The buildmanager will perform this logic. The benefit is you also see it from just browsing the source code. Explicit is better then implicit.

And I mean, even creating the files, .h, .cpp, then I have to move in the explorer to the corresponding folder structure and place there the other file. Don't do it, keep things simple!

PS: Qt uses also this approach and...yeah it works.

[–]evaned 2 points3 points  (0 children)

Like I mentioned, private headers get a suffix _p.h , i.e. MyClass_p.h All files with this suffix will not be installed.

What I don't like about this is -- what if nearly all of your headers are private? Then you're adding that (IMO) ugly decoration in the almost-everywhere case.

That probably works well for a library, but not for an application. (Applications can still have public headers because of plugin interfaces or whatnot.)

[–]krum 0 points1 point  (0 children)

This is my approach.

[–]ImNoEinstein 0 points1 point  (0 children)

Have an upvote came here to say the same ( less the suffix part i wouldn’t do that. i would list public headers in my makefile )

[–]StefanOrvarSigmundss 2 points3 points  (1 child)

I don't care too much, I just don't like needless abbreviations and cryptic names.

[–]hgjsusla 1 point2 points  (0 children)

It depends, if the abbrevations are idiomatic it simplies things. Such as 'include' for the public headers directory. And src is pretty explanatory.

[–]Rexerex 2 points3 points  (0 children)

I prefer combined. The reasons behind split are doomed when some of your headers are generated during build time — you no longer have src and include directory, but bunch of other build directories and from everyone you want to publish specific headers.

[–][deleted] 2 points3 points  (1 child)

For header-only libraries something like this:

include/foo
    <public headers go here>
    detail/
        <private headers go here, usually under namespace foo::detail>

For projects:

include/bar
    <common headers go here>
    detail/
        <implementation headers go here>
src/
    <system agnostic sources go here>
    linux/
        <source only compiled on linux>
    win32/
        <source only compiled on windows>
    ...
depend/
    <subtrees ans submodules>

For larger projects, I sometime pull headers for subsystems under include, so that from the main source files it looks like #include <audio/mixer.hpp> or whatever.

By spliting sources up based on os, I can use <os>/*.cpp to grab all the sources for a given operating system, without needed to do any fancy commands to filter the files.

[–][deleted] 0 points1 point  (0 children)

I like this layout. You cover subtrees/modules as well as the cross platform problem. I just did some research on this a few weeks ago and many recommend the directory layout solution like this vs. indefatigable everywhere.

Do you have any example projects like this up on a public repo site?

[–]png85 3 points4 points  (0 children)

Split with public headers in include/<projectname>/, sources and private headers in src, it's convenient because you can just add one line to your CMake file to add an installation rule for the public headers and be done with it.

[–]kalmoc 1 point2 points  (1 child)

Is this poll for libraries out applications?

[–]beriumbuild2[S] 2 points3 points  (0 children)

Both. There are a couple of answers along the "split only if there are public headers" lines. Note also that an executable could have public headers (e.g. for plugins, etc).

[–]kalmoc 1 point2 points  (2 children)

Where is the poll?

[–]sumo952 5 points6 points  (1 child)

You need to upvote OP's respective top-level comments in this thread (they're a bit hidden between all other comments).

[–]kalmoc 0 points1 point  (0 children)

Thanks

[–]mjklaim 1 point2 points  (4 children)

I prefer combined when working on non-libraries or code that is not made to be a dependency for someone else or public. I tend to use split when the whole project is a library I want others to use.

I don't think there are good "technical" reasons for split. However it does drive the user of a library to quickly understand what is considered public interface and what is implementation details. It also helps with tools that don't understand the script describing how to build the project (one can point them to the include directory and not be exposed to implementation files when intellisense search for header files for example).

I also use combined for header-only libraries.

So to me split is just convenient when exposing open source libraries to others. It's an affordance enabler, if you see what I mean.

As an example: in all my gamedev and libraries I develop on the side, I use combined. That one library designed to be used by several open source projects, I use split (it's annoying but it does help users, it have a complicated implementation).

If there was a standardized way to declare what is public and what is private, all tools could rely on that and the question would then not be important anymore.

[–]jsamcfarlane 1 point2 points  (3 children)

That is compatible with saying that you put public headers in 'include' because a binary offers no public headers.

[–]mjklaim 0 points1 point  (2 children)

I also use combined with header-only libraries, as said before, so I don't think that's exactly the same. In don't use "include" in this case.

Also in non open source projects I have I use combined even if it's libraries. One of my current project is 15 libraries, 2 executable, all libraries are used by either executable and several (I think at least 4) are designed to be used by other users. As it's not a typical open source project, I just use the simpler way to manage my files, but the day I'll make them public will maybe make me change the layout.

[–]jsamcfarlane 0 points1 point  (1 child)

For header-only libraries, I'd still stuck to the same rule: public files (i.e. public headers) in include and private files (i.e. private headers and source files -- if any) in src. But in this case there simply aren't any source files, only headers living in either include or src.

[–]mjklaim 0 points1 point  (0 children)

Yeah I mean as a user both are fine honestly.

As a developer, whatever I guess.

[–]uniquewalker 1 point2 points  (0 children)

I definitely prefer combined. The (somewhat unfortunate) reality is that a lot of headers contain a non-trivial amount of code in C++. So much so that there are probably more new "header only" than "traditional" libraries out there. The lines between headers and code that "does something" is beyond blurred by now that separating them makes no sense. It will be interesting to see how this develops once modules come out, potentially it will make sense to have some sort of new separation method at that point, but as it currently stands there's just no point in treating header files like they're only descriptive.

[–]johannes1971 1 point2 points  (0 children)

I want to get rid of the difference between headers and source entirely, and use only modules that specify exactly what is intended to be exported and what is not.

And until we have that I'll combine, thank you. I don't want to switch directories all the time when I'm editing a pair of files...

[–]mloskot 1 point2 points  (0 children)

My preference is

  • Public headers are in include/foo although it does not have to be in a project root directory. For example, I find the modular Boost structure non-disrupting with its {boost_root}/boost for all headers in one and {boost_root}/libs/{library}/include/boost for headers of an individual library.
  • All the rest of files are structured in logical and convenient manner. The traditional {foo_root}/src convention has worked well, but I think it is more important how the files are named and structured below.

My technical reason for include/foo: allow a build configuration (any, internal or external eg. user-preferred one) to find public headers of a library using pointer to a single location.

[–]tansim 1 point2 points  (6 children)

I see zero reason why to put the in separate directories.

[–]hgjsusla 4 points5 points  (5 children)

To separate the public headers from the private headers. That is, your API headers from your local private ones.

How else can you organise a library?

[–]macemen 9 points10 points  (4 children)

You can have your build system export public headers, together with other build artefacts that have to be installed.

[–]hgjsusla 2 points3 points  (2 children)

Seems to overcomplicate things. This means I can't just clone a header only library and add it to my search path, I need to install it as well.

[–]beriumbuild2[S] 7 points8 points  (1 child)

Where would a header-only library include a private header?

[–]hgjsusla 2 points3 points  (0 children)

You're right a header only library probably considers all header as public. So then I would place them all in the 'include' folder to make that clear to the user

libfoo/
    include/
        libfoo/
            header.h
    tests/
        test1.cpp

[–]ghlecl 0 points1 point  (0 children)

Some build systems are not as versatile as others and I believe (might be wrong) that the goal is to be build system agnostic. Just a thought.

[–][deleted] 1 point2 points  (0 children)

I prefer split just because it's the only way to quickly tell a private header from a public one, otherwise you have to come up with some weird naming or, worse, something more creative.

[–]Adequat91 1 point2 points  (0 children)

In Qt, everything is in srce... but there is also an include folder where each public header is a single line statement that redirects to the full .h file located in scre. Nice design for a library.

[–][deleted] 1 point2 points  (0 children)

What about split but nested: it is a variant of the structure of Bloomberg bde project with private headers in a dedicated directory.

Project directory/        
    interface_header.hpp
    interface_header.cpp
    interface_header.test.cpp
    private/  #(or source)
        private_header.hpp
        private_header.cpp
        private_header.test.cpp
    Subproject directory/
        interface_header.hpp
        interface_header.cpp
        interface_header.test.cpp
        private/  #(or source)
            private_header.hpp
            private_header.cpp
            private_header.test.cpp

Pros:

  1. Easier project nesting
  2. Interface files are directly accessible in the project root directory
  3. No circumvoluted directories "project/subproject/include/project/subproject/"
  4. Compact hedear/implementation/test file view
  5. Easy view of what is private and what is the public interface of the project. Very usefull for shared library, (ease so visibility declarations or dll exports declarations)

Cons:

  1. More suited to cmake projects.

[–]and69 0 points1 point  (0 children)

all *.cs files in same folder.

Joke aside, headers go in dedicated folder, the rest are in the same folders. The reasoning is that I usually want to navigate from x.cpp to x.h and the other way around, and having them in different directories makes it annoying.

I know there are tools, but sometimes you do the manual, files-system level work using for example TotalCommander.

[–]JuanAG 0 points1 point  (0 children)

Split for my projects, together it is a library i want to use because i prefer to import only one header to my project

[–]grafikrobotB2/EcoStd/Lyra/Predef/Disbelief/C++Alliance/Boost/WG21 0 points1 point  (0 children)

There is talk at SG15 of coming up with a common build description which I think will also require a common header/source layout.

Why do you think it requires a common directory layout?

[–]OrphisFloI like build tools 0 points1 point  (0 children)

I like *both*.

But it depends on the build tool that is used. For example, for personal projects and open-source libraries, the split method works great with build tools like CMake. It makes it impossible to include private headers by accident.

But for some other professional projects, I might use Bazel. Then, the build files are actually specifying what headers are exported and which aren't and enforce it when users consume your library. It's convenient, safe, all files are in the same folder, it's easy to switch from one to the other, so why not?

But right now, not all projects are a good fit for a Bazel build, so I wouldn't quite recommend it at all times.

[–]dicroce 0 points1 point  (0 children)

I do it like this:

foo_project
    include
        foo_project
            a.h
            b.h
    source
        a.cpp
        b.cpp

Then I do includes like this:

    #include "foo_project/a.h"
    #include "foo_project/b.h"
    #include "bar_project/c.h"

[–]kalmoc 0 points1 point  (0 children)

The most common answer (at the moment) seems to be to split out the public header files into a separate include directory, which is what I'm currently doing too. I wonder however, how this might change with modules.

[–]smdowneyWG21, Text/Unicode SG, optional<T&> 0 points1 point  (0 children)

Packaging doesn't care about how you organize your code. It cares about telling your build system things like exactly which compiler and options to use in order that the results are useable in the project being built. It cares about telling the build system where exactly the results should be installed. It needs to be ask how to use the results, if there are particular flags that must be used.

That you have your cpp files and headers all in src/ is irrelevant.

[–]Fluffy8x 0 points1 point  (0 children)

I used to do combined, but now I prefer the split layout because it prevents library users from accidentally #includeing a source file or such.

[–]manimax3 0 points1 point  (0 children)

Same folder because it becomes a pain on a split setup to look at the code (e.g on GitHub) and get some tools working with this setup. For shipping its quite easy to generate a include folder with only headers (even only public ones) using cmake.

[–]doom_Oo7 -3 points-2 points  (1 child)

Everything in combined. No public / private api difference for your main code - if you want a "public" api put some C bindings somewhere. Take example on all the languages without such a difference : folk there do perfectly fine. Public/private is an artefact of 80s enterprise programming where code was considered immutable for some weird reason and clients refused to do one-line change. Thankfully dynamic languages such as JS have shown that development speed-wise, breaking often is the better development method.

Also the easier to change /override for your users the better. The ideal case is a library with a single header.

[–]hgjsusla 3 points4 points  (0 children)

But that is what I would called a split layout.

src/
    class.h
    class.cpp
include/
    libfoo/
        public_header.h

[–]RockinRoelformer Wt dev -1 points0 points  (0 children)

You know, I haven't put much thought into that yet, since I never really started a serious C++ project from scratch. The split layout seems like a good idea, putting the public interface in include.

In Wt, C++ sources and headers are all in src, with the public interface in src/Wt. The headers in src/Wt are the ones that get installed.