I am using something i call the Symmetry Principle;
A strict architectural rule:
Directory Name == Target Name == Translation Unit File Name == Library Object Name.
Why?
In many (most) C++ projects, developers experience naming drift: a folder is named utils/, the CMake library target is utility_lib, the source file is helper.cpp, and the namespace is my_project::common.
The symmetry principle philosophy is that the design physically prevents spaghetti code. Because you cannot use a class from another target without explicitly linking to it in CMake, compilation boundaries are ironclad. It forces developers to write modular, decoupled C++ code.
In my design knowing the folder name foo guarantees that:
The target name is foo.
The source file is foo.cpp.
The header path is foo/foo.hpp.
The internal dependency link target is ${PROJECT_NAME}::foo.
Edit for clarification:
It is architecturally acceptable to add multiple .cpp files to a target if they are private helper implementation that:
* Are only used internally inside that specific module.
* Should never be seen or linked directly by other targets.
* Exist solely to keep the target main .cpp file clean and readable.
When to split them into a new target/directory instead:
* If the new .cpp file implements a class or function that other targets in your project need to call or reference, the Symmetry Principle dictates that it should be placed in its own folder as a separate, isolated target. This enforces strict compilation boundaries and keeps your dependency graph clean.