Reid Spencer | 5179f05 | 2004-08-26 07:41:41 +0000 | [diff] [blame^] | 1 | Design Of lib/System |
| 2 | ==================== |
| 3 | |
| 4 | The software in this directory is designed to completely shield LLVM from any |
| 5 | and all operating system specific functionality. It is not intended to be a |
| 6 | complete operating system wrapper (such as ACE), but only to provide the |
| 7 | functionality necessary to support LLVM. |
| 8 | |
| 9 | The software located here, of necessity, has very specific and stringent design |
| 10 | rules. Violation of these rules means that cracks in the shield could form and |
| 11 | the primary goal of the library is defeated. By consistently using this library, |
| 12 | LLVM becomes more easily ported to new platforms since (hopefully) the only thing |
| 13 | requiring porting is this library. |
| 14 | |
| 15 | Complete documentation for the library can be found in the file: |
| 16 | llvm/docs/SystemLibrary.html |
| 17 | or at this URL: |
| 18 | http://llvm.org/docs/SystemLibrary.html |
| 19 | |
| 20 | However, for the impatient, here's a high level summary of the design rules: |
| 21 | |
| 22 | 1. No functions are declared with throw specifications. This is on purpose to |
| 23 | make sure that additional exception handling code is not introduced by the |
| 24 | compiler. |
| 25 | |
| 26 | 2. On error only an instance of std::string that explains the error and possibly |
| 27 | the context of the error may be thrown. |
| 28 | |
| 29 | 3. Error messages should do whatever is necessary to get a readable message from |
| 30 | the operating system about the error. For example, on UNIX the strerror_r |
| 31 | function ought to be used. |
| 32 | |
| 33 | 4. Entry points into the library should be fairly high level and aimed at |
| 34 | completing some task needed by LLVM. There should *not* be a 1-to-1 |
| 35 | relationship between operating system calls and the library's interface. |
| 36 | Certain implementations of the |
| 37 | |
| 38 | 5. The implementation of an lib/System interface can vary drastically between |
| 39 | platforms. That's okay as long as the end result of the interface function is |
| 40 | the same. For example, a function to create a directory is pretty straight |
| 41 | forward on all operating system. System V IPC on the other hand isn't even |
| 42 | supported on all platforms. Instead of "supporting" System V IPC, lib/System |
| 43 | should provide an interface to the basic concept of inter-process |
| 44 | communications. The implementations might use System V IPC if that was |
| 45 | available or named pipes, or whatever gets the job done effectively for a |
| 46 | given operating system. |
| 47 | |
| 48 | 6. Implementations are separated first by the general class of operating system |
| 49 | as provided by the configure script's $build variable. This variable is used |
| 50 | to create a link from $BUILD_OBJ_ROOT/lib/System/platform to a directory in |
| 51 | $BUILD_SRC_ROOT/lib/System directory with the same name as the $build |
| 52 | variable. This provides a retargetable include mechanism. By using the link's |
| 53 | name (platform) we can actually include the operating specific |
| 54 | implementation. For example, support $build is "Darwin" for MacOS X. If we |
| 55 | place: |
| 56 | #include "platform/File.cpp" |
| 57 | into a a file in lib/System, it will actually include |
| 58 | lib/System/Darwin/File.cpp. What this does is quickly differentiate the basic |
| 59 | class of operating system that will provide the implementation. |
| 60 | |
| 61 | 7. Implementation files in lib/System need may only do two things: (1) define |
| 62 | functions and data that is *TRULY* generic (completely platform agnostic) and |
| 63 | (2) #include the platform specific implementation with: |
| 64 | |
| 65 | #include "platform/Impl.cpp" |
| 66 | |
| 67 | where Impl is the name of the implementation files. |
| 68 | |
| 69 | 8. Platform specific implementation files (platform/Impl.cpp) may only #include |
| 70 | other Impl.cpp files found in directories under lib/System. The order of |
| 71 | inclusion is very important (from most generic to most specific) so that we |
| 72 | don't inadvertently place an implementation in the wrong place. For example, |
| 73 | consider a fictitious implementation file named DoIt.cpp. Here's how the |
| 74 | #includes should work for a Linux platform |
| 75 | |
| 76 | lib/System/DoIt.cpp |
| 77 | #include "platform/DoIt.cpp" // platform specific impl. of Doit |
| 78 | DoIt |
| 79 | |
| 80 | lib/System/Linux/DoIt.cpp // impl that works on all Linux |
| 81 | #include "../Unix/DoIt.cpp" // generic Unix impl. of DoIt |
| 82 | #include "../Unix/SUS/DoIt.cpp // SUS specific impl. of DoIt |
| 83 | #include "../Unix/SUS/v3/DoIt.cpp // SUSv3 specific impl. of DoIt |
| 84 | |
| 85 | Note that the #includes in lib/System/Linux/DoIt.cpp are all optional but |
| 86 | should be used where the implementation of some functionality can be shared |
| 87 | across some set of Unix variants. We don't want to duplicate code across |
| 88 | variants if their implementation could be shared. |
| 89 | |
| 90 | 9. The library does not attempt to shield LLVM from the C++ standard library or |
| 91 | standard template library. These libraries are considered to be platform |
| 92 | agnostic already. |
| 93 | |
| 94 | 10. LLVM should not include *any* system headers anywhere except in lib/System. |
| 95 | |
| 96 | 11. lib/System must *not* expose *any* system headers through its interface. |