I'm going to use the ID Software engines as an example here, because all of their older engines (up to and including Doom 3) have had their source code made available under the GNU GPL, so you can read it, study it, understand it, and learn from it.
This of course comes with the caveat that these - particularly the really old engines - are not exactly shining examples of modern best practice, and you shouldn't expect them to be.
I won't go through each engine in detail, but I will instead discuss 2 engines, which provide examples of two different approaches. These are all available at the ID Software Github.
Quake 2
This is an example of having separate Engine and Tools. A file format - for example a map file - is defined via standard C/C++ structs, and two separate codebases are written using that file format. The tools build the final binary file that the engine consumes from source files, and the two codebases don't actually have much duplication of code. Excluding the Tools is simply a matter of just not shipping them, as they are completely separate executables.
Doom 3
The Tools are integrated into the Engine. This allows the Tools to be launched from a development console, and while they can share code, in practice they don't really because the Tools use some unoptimized (and simpler) code that would be unsuitable for the Engine. The Tools can also be excluded from a build via some #defines, if required.