It is assumed all the source files exist in a single logical tree which we call the virtual tree. For example the following is part of the structure used for the CEDA libraries:
(root) └─── Ceda ├── cxCedaScript ├── cxLss ├── cxMacroExpander ├── cxMessage ├── cxMiddleware ├── cxObject ├── cxOperation ├── cxPersistStore ├── cxPython ├── cxRmi ├── cxSocket ├── cxThread ├── cxUtils └── cxWorkingSetIpc
A logical path means a path down from the root using forward slash delimiters, and without an initial slash. For example the logical path Ceda/cxRmi identifies the project directory for the cxRmi library.
Expanding this part of the tree we can see the individual source files for the cxRmi library:
(root) └── Ceda └── cxRmi <──── project directory has logical path Ceda/cxRmi ├── cxRmi.h ├── RmiConnection.h ├── Rmi.h ├── Skeleton.h ├── Stub.h └── src <──── folder for private source files ├── cxRmi.cpp ├── cxRmi.xcpj <──── project file ├── ResponseQueue.cpp ├── ResponseQueue.h ├── RmiCallee.cpp ├── RmiCallee.h ├── RmiCaller.cpp ├── RmiCaller.h ├── Skeleton.cpp ├── StdAfx.cpp ├── StdAfx.h ├── Stub.cpp ├── ThreadBlocker.cpp └── ThreadBlocker.h
In order to avoid name clashes in the virtual tree, developers should organise their project directories appropriately, e.g. making use of their company name. For example
(root) ├── Ceda ├── Apple ├── Google ├── IBM ├── Intel ├── Oracle └── Microsoft
It is common practice for build systems or source code repositories to use a directory named something like “ThirdParty” for where to place external projects. For example, company X may consider that any library created by company Y should be placed under “ThirdParty”. We reject this notion, because it leads to inconsistency in the logical placement of files, and therefore complexity in the way include and library paths are defined. More importantly it hurts the ability to share and reuse project and workspace files.
We follow the principle that a single logical directory structure holds all source code to be written. This logical structure is defined without regard for the requirements of a particular developer (or even a company). For example, the structure is independent of:
An xcpp configuration file allows for defining the virtual tree which represents the input to the build process.
For example on a Windows machine an xcpp configuration file may specify the virtual tree like this:
virtualTree =
{
"c:/dev/head"
"c:/dev/utils/v2.01"
"c:/dev/cad/v1.0"
}
Each of these paths identifies a physical tree by the physical location of its root directory on the file system. In this case there are three physical trees which together uniquely define a single virtual tree.
For a file with absolute path c:/dev/head/x/y/z, we regard this path as the concatenation of an absolute path to a physical tree (i.e. c:/dev/head) and a logical path (i.e. x/y/z which is the path relative to the root of the physical tree). Therefore we say that the logical path of the file is x/y/z.
The virtual tree is essentially the union of a set of physical trees. We call this a virtual tree because it is not directly materialised on disk. The concept of a virtual tree provides the basis for combining together source code from different sources in a well defined manner, without the need for specialised support from the file system (such as symbolic links to mount directories).
The order in which the physical paths are specified is significant in cases where a file with the same logical path exists under more than one physical root.
In the case where there are multiple candidate files with the same logical path, the winner is the file in the physical tree that appears first in the ordered sequence of physical trees. In the above example, files under c:/dev/head take precedence over files with the same relative path under the other two physical roots.
It is allowed (but not required) that each of these physical trees be working sets associated with particular branches or tagged versions stored within particular source code repositories such as git or subversion. As such it is typically possible to independently commit/update from these distinct physical trees.
Note that source code repository systems do not normally allow for “mounting” parts of physical trees of one repository into the physical tree associated with another repository (especially when it involves a different vendor). In general it’s appropriate to assume that working sets checked out of source code repositories represent distinct trees of directories and files on a developer machine.