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,87 @@ +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 = [ + FunctionDecl<"acos">, + FunctionDecl<"acosl">, + ]; + + let TypeDeclarations = [ + FloatT, + ]; +} + +def String : PublicAPI<"string.h"> { + let Functions = [ + FunctionDecl<"strcat">, + FunctionDecl<"strcpy"> + ]; + + let TypeDeclarations = [ + SizeT, + ]; + + let Macros = [ + NullMacro, + ]; +} + +def StdIO : PublicAPI<"stdio.h"> { + let TypeDeclarations = [ + SizeT, + ]; + + let Functions = [ + FunctionDecl< + "snprintf", + + // The function attribute below is only valid with clang and gcc. + // It is included here as an example. + "__attribute__((format(__printf__(3, 4))))", + + // The annotations below are only for illustration purpose and are valid + // under msvc I think. + // Since there are three argument annotations listed here, the function + // should take atleast 3 formal arguments including the varargs. + // The header generator will check the arg count mismatch if any. + [ArgAnn<["_Out_writes_opt_(_BufferCount)", "_Always_(_Post_z_)"], "_Buffer">, + ArgAnn<["_In_"], "_BufferCount">, + ArgAnn<["_In_z_", "_Printf_format_string_"], "_Format">] + >, + ]; +} 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,31 @@ +class Standards { + list Standards; +} + +class TypeDecl { + string Name = name; + string Decl = ""; +} + +class MacroDef { + string Name = name; + string Defn = ""; +} + +class ArgAnn annotations, string name = ""> { + list Annotations = annotations; + string Name = name; +} + +class FunctionDecl argAnnotations = []> { + string Name = name; + string Attr = attr; + list ArgAnnotations = argAnnotations; +} + +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,52 @@ +class Type {} + +class NamedType : Type { + string Name = name; +} + +class Field { + string Name = name; + Type FieldType = type; +} + +// Class to describe concrete structs specified in the standard. +class Struct : NamedType { + list Fields; +} + +class PtrType : Type { + Type PointeeType = type; +} + +class ConstType : Type { + Type UnqualifiedType = type; +} + +class RestrictedPtrType : Type { + Type PointeeType = type; +} + +// Builtin types. +def VarArgType : Type {} +def VoidType : NamedType<"void">; +def IntType : NamedType<"int">; +def FloatType : NamedType<"float">; +def DoubleType : NamedType<"double">; +def CharType : NamedType<"char">; + +class Macro { + string Name = name; +} + +class Function args> { + string Name = name; + Type ReturnType = return_type; + list Args = args; +} + +class Header { + string Name = name; + list Functions; + list Types; + list Macros; +} 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,47 @@ +include "spec/spec.td" + +def Math : Header<"math.h"> { + let Functions = [ + Function<"acos", DoubleType, [DoubleType]> + ]; + + let Types = [ + NamedType<"float_t">, + NamedType<"double_t">, + ]; +} + +def VoidPtr : PtrType; +def VoidRestrictedPtr : RestrictedPtrType; +def ConstVoidRestrictedPtr : ConstType; + +def CharPtr : PtrType; +def CharRestrictedPtr : RestrictedPtrType; +def ConstCharRestrictedPtr : ConstType; + +def SizeTType : NamedType<"size_t">; + +def String : Header<"string.h"> { + let Types = [ + SizeTType, + ]; + + let Macros = [ + Macro<"NULL">, + ]; + + let Functions = [ + Function<"strcpy", CharPtr, [CharRestrictedPtr, ConstCharRestrictedPtr]>, + Function<"memcpy", VoidPtr, [VoidRestrictedPtr, ConstVoidRestrictedPtr, SizeTType]> + ]; +} + +def StdIO : Header<"stdio.h"> { + let Types = [ + SizeTType, + ]; + + let Functions = [ + Function<"snprintf", IntType, [CharPtr, SizeTType, ConstCharRestrictedPtr, VarArgType]>, + ]; +}