diff --git a/libc/config/linux/header_conf.td b/libc/config/linux/header_conf.td new file mode 100644 --- /dev/null +++ b/libc/config/linux/header_conf.td @@ -0,0 +1,62 @@ +include "config/public_api.td" + +def LinuxStandards : Standards { + // On Linux, we support Public API specified by + // the C standard library and the POSIX extensions. + let Standards = [ + "stdc", + "posix", + ]; +} + +def FloatT : TypeDecl<"float_t"> { + let Decl = [{ + #if __FLT_EVAL_METHOD__ == 1 + typedef float float_t + #elseif __FLT_EVAL_METHOD__ == 2 + ... + #else + ... + #endif + }]; // This is only an example and not exactly how it will appear +} + +def SizeT : TypeDecl<"size_t"> { + let Decl = [{ + #define __need_size_t + #include + }]; +} + +def NullMacro : MacroDef<"NULL"> { + let Defn = [{ + #define __need_NULL + #include + }]; +} + +def Math : PublicAPI<"math.h"> { + let Functions = [ + "acos", + "acosl", + ]; + + let TypeDeclarations = [ + FloatT, + ]; +} + +def String : PublicAPI<"string.h"> { + let Functions = [ + "strcat", + "strcpy" + ]; + + let TypeDeclarations = [ + SizeT, + ]; + + let Macros = [ + NullMacro, + ]; +} diff --git a/libc/config/linux/headers.txt b/libc/config/linux/headers.txt new file mode 100644 --- /dev/null +++ b/libc/config/linux/headers.txt @@ -0,0 +1,6 @@ + +add_libc_headers( + llvmlibc_headers + math_h + string_h +) diff --git a/libc/lib/CMakeLists.txt b/libc/config/linux/library_targets.txt copy from libc/lib/CMakeLists.txt copy to libc/config/linux/library_targets.txt diff --git a/libc/config/public_api.td b/libc/config/public_api.td new file mode 100644 --- /dev/null +++ b/libc/config/public_api.td @@ -0,0 +1,20 @@ +class Standards { + list Standards; +} + +class TypeDecl { + string Name = name; + string Decl = ""; +} + +class MacroDef { + string Name = name; + string Defn = ""; +} + +class PublicAPI { + list Functions; + list TypeDeclarations; + list Macros; + list Structs; +} diff --git a/libc/docs/build_system.rst b/libc/docs/build_system.rst --- a/libc/docs/build_system.rst +++ b/libc/docs/build_system.rst @@ -22,3 +22,18 @@ ``add_entrypoint_library`` target takes a list of ``add_entrypoint_object`` targets and produces a static library containing the object files corresponding to the ``add_entrypoint_targets``. + +Rules for header files +====================== + +There are two rules for header files. These rules can be used for internal as +well as public header files. They are explained in detail below: + +1. ``add_hdr`` - This rule should be used for public header files whose content + is guaranteed to be platform independent and available on all platforms that + LLVM libc supports. + +2. ``gen_hdr`` - This rule should be used to generate header files from + ``.h.def`` files. The format of the ``h.def`` files is explained in the + header generation document. + diff --git a/libc/docs/ground_truth_specification.rst b/libc/docs/ground_truth_specification.rst new file mode 100644 --- /dev/null +++ b/libc/docs/ground_truth_specification.rst @@ -0,0 +1,11 @@ +The ground truth of standards +============================= + +Like any modern libc, LLVM libc also supports a wide number of standards and +extensions. To avoid developing headers, wrappers and sources in a disjointed +fashion, LLVM libc employs ground truth files. These files live under the +``spec`` directory and list ground truth corresponding the ISO C standanrd, the +POSIX extension standard, etc. For example, the path to the ground truth file +for the ISO C standard is ``spec/stdc.td``. Tools like the header generator +(described in the header generation document), docs generator, etc. use the +ground truth files to generate headers, docs etc. diff --git a/libc/docs/header_generation.rst b/libc/docs/header_generation.rst --- a/libc/docs/header_generation.rst +++ b/libc/docs/header_generation.rst @@ -96,3 +96,21 @@ The header generator will only include content starting from the line after the line on which this command is listed. + +``public_api`` +~~~~~~~~~~~~~~ + +This is a replacement command which should be listed in an input ``.h.def`` +file. The header file generator will replace this command with the public API of +the target platform. See the build system document for more information on the +relevant build rules. Also, see "Mechanics of public_api" to learn the mechanics +of how the header generator replaces this command with the public API. + +Arguments + + None. + +Action + + The header generator will replace this command with the public API to be exposed + from the generated header file. diff --git a/libc/docs/mechanics_of_public_api.rst b/libc/docs/mechanics_of_public_api.rst new file mode 100644 --- /dev/null +++ b/libc/docs/mechanics_of_public_api.rst @@ -0,0 +1,30 @@ +The mechanics of the ``public_api`` command +=========================================== + +The build system, in combination with the header generation mechanism, +facilitates the fine grained ability to pick and choose the public API one wants +to expose on their platform. The public header files are always generated from +the corresponding ``.h.def`` files. A header generation command ``%%public_api`` +is listed in these files. In the generated header file, the header generator +replaces this command with the public API relevant for the target platform. + +Under the hood +-------------- + +When the header generator sees the ``%%public_api`` command, it looks up the +header config file for the platform in the path +``config//header_config.td``. The header config file lists two kinds +of items: + +1. The list of standards from which the public entities available on the platform + are derived from. +2. For each header file exposed on the platfrom, the list of public members + provided in that header file. + +Note that, the header generator only learns the names of the public entities +from the header config file (the 2nd item from above.) The exact manner in which +the entities are to be declared is got from the standards (the 1st item from +above.) + +See the ground truth document for more information on how the standards are +formally listed in LLVM libc using LLVM table-gen files. diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt --- a/libc/lib/CMakeLists.txt +++ b/libc/lib/CMakeLists.txt @@ -1,9 +1,4 @@ +# DO NOT list targets directly in this file unless it is guaranteed to be +# platform independent. -add_entrypoint_library( - llvmlibc - DEPENDS - ### C standard library entrypoints - # string.h entrypoints - strcpy - strcat -) +include($LIBC_SOURCE_DIR/config/${LIBC_TARGET_OS}/library_targets.txt) diff --git a/libc/spec/posix.td b/libc/spec/posix.td new file mode 100644 diff --git a/libc/spec/spec.td b/libc/spec/spec.td new file mode 100644 --- /dev/null +++ b/libc/spec/spec.td @@ -0,0 +1,36 @@ +class Function args> { + string Name = name; + string ReturnType = return_type; + list Args = args; +} + +class Field { + string Name = name; + string TypeName = type; +} + +// This is for types which the standard explicitly describes as a struct. +class Struct { + string Name = name; + list Fields; +} + +// This class is for types which are declared as typedefs or +// as opaque classes in the header files. The standard merely +// gives a type name but does not prescribe how it is to be +// implemented. +class Type { + string Name = name; +} + +class Macro { + string Name = name; +} + +class Header { + string Name = name; + list Functions; + list Types; + list Macros; + list Structs; +} diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td new file mode 100644 --- /dev/null +++ b/libc/spec/stdc.td @@ -0,0 +1,31 @@ +include "spec/spec.td" + +def Math : Header<"math.h"> { + let Functions = [ + Function<"acos", "double", ["double"]> + ]; + + let Types = [ + Type<"float_t">, + Type<"double_t">, + ]; +} + +def String : Header<"string.h"> { + let Types = [ + Type<"size_t">, + ]; + + let Macros = [ + Macro<"NULL">, + ]; + + let Functions = [ + Function<"strcpy", "char *", ["char *__restrict", "const char *__restrict"]>, + Function<"memcpy", "void *", ["void *__restrict", "const void *__restrict", "size_t"]> + ]; +} + +def StdIO : Header<"stdio.h"> { + let Functions = []; +}