forked from OSchip/llvm-project
Add few docs and implementation of strcpy and strcat.
Summary: This patch illustrates some of the features like modularity we want in the new libc. Few other ideas like different kinds of testing, redirectors etc are not yet present. Reviewers: dlj, hfinkel, theraven, jfb, alexshap, jdoerfert Subscribers: mgorny, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67867 llvm-svn: 373764
This commit is contained in:
parent
717e540f7e
commit
4380647e79
|
@ -0,0 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.4.3)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
# The top-level source directory of libc.
|
||||
set(LIBC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# The top-level directory in which libc is being built.
|
||||
set(LIBC_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Path libc/scripts directory.
|
||||
set(LIBC_BUILD_SCRIPTS_DIR "${LIBC_SOURCE_DIR}/utils/build_scripts")
|
||||
|
||||
|
||||
set(LIBC_TARGET_OS ${CMAKE_SYSTEM_NAME})
|
||||
string(TOLOWER ${LIBC_TARGET_OS} LIBC_TARGET_OS)
|
||||
|
||||
set(LIBC_TARGET_MACHINE ${CMAKE_SYSTEM_PROCESSOR})
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include(LLVMLibCRules)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(lib)
|
|
@ -0,0 +1,280 @@
|
|||
|
||||
# A rule for self contained header file targets.
|
||||
# This rule merely copies the header file from the current source directory to
|
||||
# the current binary directory.
|
||||
# Usage:
|
||||
# add_header(
|
||||
# <target name>
|
||||
# HDR <header file>
|
||||
# )
|
||||
function(add_header target_name)
|
||||
cmake_parse_arguments(
|
||||
"ADD_HEADER"
|
||||
"" # No optional arguments
|
||||
"HDR" # Single value arguments
|
||||
"DEPENDS" # No multi value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT ADD_HEADER_HDR)
|
||||
message(FATAL_ERROR "'add_header' rules requires the HDR argument specifying a headef file.")
|
||||
endif()
|
||||
|
||||
set(dest_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_HEADER_HDR})
|
||||
set(src_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_HEADER_HDR})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${dest_file}
|
||||
COMMAND cp ${src_file} ${dest_file}
|
||||
DEPENDS ${src_file}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
${target_name}
|
||||
DEPENDS ${dest_file}
|
||||
)
|
||||
|
||||
if(ADD_HEADER_DEPENDS)
|
||||
add_dependencies(
|
||||
${target_name} ${ADD_HEADER_DEPENDS}
|
||||
)
|
||||
endif()
|
||||
endfunction(add_header)
|
||||
|
||||
# A rule for generated header file targets.
|
||||
# Usage:
|
||||
# add_gen_header(
|
||||
# <target name>
|
||||
# DEF_FILE <.h.def file>
|
||||
# GEN_HDR <generated header file name>
|
||||
# PARAMS <list of name=value pairs>
|
||||
# DATA_FILES <list input data files>
|
||||
# )
|
||||
function(add_gen_header target_name)
|
||||
cmake_parse_arguments(
|
||||
"ADD_GEN_HDR"
|
||||
"" # No optional arguments
|
||||
"DEF_FILE;GEN_HDR" # Single value arguments
|
||||
"PARAMS;DATA_FILES" # Multi value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT ADD_GEN_HDR_DEF_FILE)
|
||||
message(FATAL_ERROR "`add_gen_hdr` rule requires DEF_FILE to be specified.")
|
||||
endif()
|
||||
if(NOT ADD_GEN_HDR_GEN_HDR)
|
||||
message(FATAL_ERROR "`add_gen_hdr` rule requires GEN_HDR to be specified.")
|
||||
endif()
|
||||
|
||||
set(out_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_GEN_HDR_GEN_HDR})
|
||||
set(in_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_GEN_HDR_DEF_FILE})
|
||||
|
||||
set(fq_data_files "")
|
||||
if(ADD_GEN_HDR_DATA_FILES)
|
||||
foreach(data_file IN LISTS ADD_GEN_HDR_DATA_FILES)
|
||||
list(APPEND fq_data_files "${CMAKE_CURRENT_SOURCE_DIR}/${data_file}")
|
||||
endforeach(data_file)
|
||||
endif()
|
||||
|
||||
set(replacement_params "")
|
||||
if(ADD_GEN_HDR_PARAMS)
|
||||
list(APPEND replacement_params "-P" ${ADD_GEN_HDR_PARAMS})
|
||||
endif()
|
||||
|
||||
set(gen_hdr_script "${LIBC_BUILD_SCRIPTS_DIR}/gen_hdr.py")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${out_file}
|
||||
COMMAND ${gen_hdr_script} -o ${out_file} ${in_file} ${replacement_params}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${in_file} ${fq_data_files} ${gen_hdr_script}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
${target_name}
|
||||
DEPENDS ${out_file}
|
||||
)
|
||||
endfunction(add_gen_header)
|
||||
|
||||
set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
|
||||
|
||||
# A rule for entrypoint object targets.
|
||||
# Usage:
|
||||
# add_entrypoint_object(
|
||||
# <target_name>
|
||||
# SRCS <list of .cpp files>
|
||||
# HDRS <list of .h files>
|
||||
# DEPENDS <list of dependencies>
|
||||
# )
|
||||
function(add_entrypoint_object target_name)
|
||||
cmake_parse_arguments(
|
||||
"ADD_ENTRYPOINT_OBJ"
|
||||
"" # No optional arguments
|
||||
"" # No single value arguments
|
||||
"SRCS;HDRS;DEPENDS" # Multi value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
|
||||
message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
|
||||
endif()
|
||||
if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
|
||||
message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
"${target_name}_objects"
|
||||
# We want an object library as the objects will eventually get packaged into
|
||||
# an archive (like libc.a).
|
||||
OBJECT
|
||||
${ADD_ENTRYPOINT_OBJ_SRCS}
|
||||
${ADD_ENTRYPOINT_OBJ_HDRS}
|
||||
)
|
||||
target_compile_options(
|
||||
${target_name}_objects
|
||||
BEFORE
|
||||
PRIVATE
|
||||
-fpie -std=${LLVM_CXX_STD_default}
|
||||
)
|
||||
target_include_directories(
|
||||
${target_name}_objects
|
||||
PRIVATE
|
||||
"${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
|
||||
)
|
||||
add_dependencies(
|
||||
${target_name}_objects
|
||||
support_common_h
|
||||
)
|
||||
if(ADD_ENTRYPOINT_OBJ_DEPENDS)
|
||||
add_dependencies(
|
||||
${target_name}_objects
|
||||
${ADD_ENTRYPOINT_OBJ_DEPENDS}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
|
||||
set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${object_file_raw}
|
||||
DEPENDS $<TARGET_OBJECTS:${target_name}_objects>
|
||||
COMMAND ${CMAKE_LINKER} -r $<TARGET_OBJECTS:${target_name}_objects> -o ${object_file_raw}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${object_file}
|
||||
DEPENDS ${object_file_raw}
|
||||
COMMAND ${CMAKE_OBJCOPY} --add-symbol "${target_name}=.llvm.libc.entrypoint.${target_name}:0,function,weak,global" ${object_file_raw} ${object_file}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
${target_name}
|
||||
ALL
|
||||
DEPENDS ${object_file}
|
||||
)
|
||||
set_target_properties(
|
||||
${target_name}
|
||||
PROPERTIES
|
||||
"TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
|
||||
"OBJECT_FILE" ${object_file}
|
||||
"OBJECT_FILE_RAW" ${object_file_raw}
|
||||
)
|
||||
endfunction(add_entrypoint_object)
|
||||
|
||||
# A rule to build a library from a collection of entrypoint objects.
|
||||
# Usage:
|
||||
# add_entrypoint_library(
|
||||
# DEPENDS <list of add_entrypoint_object targets>
|
||||
# )
|
||||
function(add_entrypoint_library target_name)
|
||||
cmake_parse_arguments(
|
||||
"ENTRYPOINT_LIBRARY"
|
||||
"" # No optional arguments
|
||||
"" # No single value arguments
|
||||
"DEPENDS" # Multi-value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
|
||||
message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
|
||||
endif()
|
||||
|
||||
set(obj_list "")
|
||||
foreach(dep IN LISTS ENTRYPOINT_LIBRARY_DEPENDS)
|
||||
get_target_property(dep_type ${dep} "TARGET_TYPE")
|
||||
string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
|
||||
if(NOT dep_is_entrypoint)
|
||||
message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is not an 'add_entrypoint_object' target.")
|
||||
endif()
|
||||
get_target_property(target_obj_file ${dep} "OBJECT_FILE")
|
||||
list(APPEND obj_list "${target_obj_file}")
|
||||
endforeach(dep)
|
||||
|
||||
set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
add_custom_command(
|
||||
OUTPUT ${library_file}
|
||||
COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
|
||||
DEPENDS ${obj_list}
|
||||
)
|
||||
add_custom_target(
|
||||
${target_name}
|
||||
ALL
|
||||
DEPENDS ${library_file}
|
||||
)
|
||||
endfunction(add_entrypoint_library)
|
||||
|
||||
function(add_libc_unittest target_name)
|
||||
cmake_parse_arguments(
|
||||
"LIBC_UNITTEST"
|
||||
"" # No optional arguments
|
||||
"SUITE" # Single value arguments
|
||||
"SRCS;HDRS;DEPENDS" # Multi-value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT LIBC_UNITTEST_SRCS)
|
||||
message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp files.")
|
||||
endif()
|
||||
if(NOT LIBC_UNITTEST_DEPENDS)
|
||||
message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
|
||||
endif()
|
||||
|
||||
set(entrypoint_objects "")
|
||||
foreach(dep IN LISTS LIBC_UNITTEST_DEPENDS)
|
||||
get_target_property(dep_type ${dep} "TARGET_TYPE")
|
||||
string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
|
||||
if(NOT dep_is_entrypoint)
|
||||
message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_unittest' is not an 'add_entrypoint_object' target.")
|
||||
endif()
|
||||
get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
|
||||
list(APPEND entrypoint_objects "${obj_file}")
|
||||
endforeach(dep)
|
||||
|
||||
add_executable(
|
||||
${target_name}
|
||||
EXCLUDE_FROM_ALL
|
||||
${LIBC_UNITTEST_SRCS}
|
||||
${LIBC_UNITTEST_HDRS}
|
||||
)
|
||||
target_include_directories(
|
||||
${target_name}
|
||||
PRIVATE
|
||||
${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include
|
||||
${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include
|
||||
${LIBC_SOURCE_DIR}
|
||||
)
|
||||
target_link_libraries(${target_name} PRIVATE ${entrypoint_objects} gtest_main gtest)
|
||||
set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_dependencies(
|
||||
${target_name}
|
||||
${LIBC_UNITTEST_DEPENDS}
|
||||
gtest
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${target_name}
|
||||
POST_BUILD
|
||||
COMMAND $<TARGET_FILE:${target_name}>
|
||||
)
|
||||
if(LIBC_UNITTEST_SUITE)
|
||||
add_dependencies(
|
||||
${LIBC_UNITTEST_SUITE}
|
||||
${target_name}
|
||||
)
|
||||
endif()
|
||||
endfunction(add_libc_unittest)
|
|
@ -0,0 +1,24 @@
|
|||
LLVM libc build rules
|
||||
=====================
|
||||
|
||||
At the cost of verbosity, we want to keep the build system of LLVM libc
|
||||
as simple as possible. We also want to be highly modular with our build
|
||||
targets. This makes picking and choosing desired pieces a straighforward
|
||||
task.
|
||||
|
||||
Targets for entrypoints
|
||||
-----------------------
|
||||
|
||||
Every entrypoint in LLVM-libc has its own build target. This target is listed
|
||||
using the ``add_entrypoint_object`` rule. This rule generates a single object
|
||||
file containing the implementation of the entrypoint.
|
||||
|
||||
Targets for entrypoint libraries
|
||||
--------------------------------
|
||||
|
||||
Standards like POSIX require that a libc provide certain library files like
|
||||
``libc.a``, ``libm.a``, etc. The targets for such library files are listed in
|
||||
the ``lib`` directory as ``add_entrypoint_library`` targets. An
|
||||
``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``.
|
|
@ -0,0 +1,6 @@
|
|||
Entrypoints in LLVM libc
|
||||
------------------------
|
||||
|
||||
A public function or a global variable provided by LLVM-libc is called an
|
||||
entrypoint. The notion of entrypoints is ingrained in LLVM-libc's
|
||||
source layout, build system and source code.
|
|
@ -0,0 +1,98 @@
|
|||
Generating Public and Internal headers
|
||||
======================================
|
||||
|
||||
Other libc implementations make use of preprocessor macro tricks to make header
|
||||
files platform agnostic. When macros aren't suitable, they rely on build
|
||||
system tricks to pick the right set of files to compile and export. While these
|
||||
approaches have served them well, parts of their systems have become extremely
|
||||
complicated making it hard to modify, extend or maintain. To avoid these
|
||||
problems in llvm-libc, we use a header generation mechanism. The mechanism is
|
||||
driven by a *header configuration language*.
|
||||
|
||||
Header Configuration Language
|
||||
-----------------------------
|
||||
|
||||
Header configuration language consists of few special *commands*. The header
|
||||
generation mechanism takes a an input file, which has an extension of
|
||||
``.h.def``, and produces a header file with ``.h`` extension. The header
|
||||
configuration language commands are listed in the input ``.h.def`` file. While
|
||||
reading a ``.h.def`` file, the header generation tool does two things:
|
||||
|
||||
1. Copy the lines not containing commands as is into the output ``.h`` file.
|
||||
2. Replace the line on which a command occurs with some other text as directed
|
||||
by the command. The replacment text can span multiple lines.
|
||||
|
||||
Command syntax
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
A command should be listed on a line by itself, and should not span more than
|
||||
one line. The first token to appear on the line is the command name prefixed
|
||||
with ``%%``. For example, a line with the ``include_file`` command should start
|
||||
with ``%%include_file``. There can be indentation spaces before the ``%%``
|
||||
prefix.
|
||||
|
||||
Most commands typically take arguments. They are listed as a comma separated
|
||||
list of named identifiers within parenthesis, similar to the C function call
|
||||
syntax. Before performing the action corresponding to the command, the header
|
||||
generator replaces the arguments with concrete values.
|
||||
|
||||
Argument Syntax
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Arguments are named indentifiers but prefixed with ``$`` and enclosed in ``{``
|
||||
and ``}``. For example, ``${path_to_constants}``.
|
||||
|
||||
Comments
|
||||
~~~~~~~~
|
||||
|
||||
There can be cases wherein one wants to add comments in the .h.def file but
|
||||
does not want them to be copied into the generated header file. Such comments
|
||||
can be added by beginning the comment lines with the ``<!>`` prefix. Currently,
|
||||
comments have to be on lines of their own. That is, they cannot be suffixes like
|
||||
this:
|
||||
|
||||
```
|
||||
%%include_file(a/b/c) <!> Path to c in b of a. !!! WRONG SYNTAX
|
||||
```
|
||||
|
||||
Available Commands
|
||||
------------------
|
||||
|
||||
Sub-sections below describe the commands currently available. Under each command
|
||||
is the discription of the arugments to the command, and the action taken by the
|
||||
header generation tool when processing a command.
|
||||
|
||||
``include_file``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a replacement command which should be listed in an input ``.h.def``
|
||||
file.
|
||||
|
||||
Arguments
|
||||
|
||||
* **path argument** - An argument representing a path to a file. The file
|
||||
should have an extension of ``.h.inc``.
|
||||
|
||||
Action
|
||||
|
||||
This command instructs that the line on which the command appears should be
|
||||
replaced by the contents of the file whose path is passed as argument to the
|
||||
command.
|
||||
|
||||
``begin``
|
||||
~~~~~~~~~
|
||||
|
||||
This is not a replacement command. It is an error to list it in the input
|
||||
``.h.def`` file. It is normally listed in the files included by the
|
||||
``include_file`` command (the ``.h.inc`` files). A common use of this command it
|
||||
mark the beginning of what is to be included. This prevents copying items like
|
||||
license headers into the generated header file.
|
||||
|
||||
Arguments
|
||||
|
||||
None.
|
||||
|
||||
Action
|
||||
|
||||
The header generator will only include content starting from the line after the
|
||||
line on which this command is listed.
|
|
@ -0,0 +1,85 @@
|
|||
Convention for implementing entrypoints
|
||||
=======================================
|
||||
|
||||
LLVM-libc entrypoints are defined in the entrypoints document. In this document,
|
||||
we explain how the entrypoints are implemented. The source layout document
|
||||
explains that, within the high level ``src`` directory, there exists one
|
||||
directory for every public header file provided by LLVM-libc. The
|
||||
implementations of related group of entrypoints will also live in a directory of
|
||||
their own. This directory will have a name indicative of the related group of
|
||||
entrypoints, and will be under the directory corresponding to the header file of
|
||||
the entrypoints. For example, functions like ``fopen`` and ``fclose`` cannot be
|
||||
tested independent of each other and hence will live in a directory named
|
||||
``src/stdio/file_operations``. On the other hand, the implementation of the
|
||||
``round`` function from ``math.h`` can be tested by itself, so it will live in
|
||||
the directory of its own named ``src/math/round/``.
|
||||
|
||||
Implementation of entrypoints can span multiple ``.cpp`` and ``.h`` files, but
|
||||
there will be atleast one header file with name of the form
|
||||
``<entrypoint name>.h`` for every entrypoint. This header file is called as the
|
||||
implementation header file. For the ``round`` function, the path to the
|
||||
implementation header file will be ``src/math/round/round.h``. The rest of this
|
||||
document explains the structure of implementation header files and ``.cpp``
|
||||
files.
|
||||
|
||||
Implementaion Header File Structure
|
||||
-----------------------------------
|
||||
|
||||
We will use the ``round`` function from the public ``math.h`` header file as an
|
||||
example. The ``round`` function will be declared in an internal header file
|
||||
``src/math/round/round.h`` as follows::
|
||||
|
||||
// --- round.h --- //
|
||||
#ifndef LLVM_LIBC_SRC_MATH_ROUND_ROUND_H
|
||||
#define LLVM_LIBC_SRC_MATH_ROUND_ROUND_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
double round(double);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif LLVM_LIBC_SRC_MATH_ROUND_ROUND_H
|
||||
|
||||
Notice that the ``round`` function declaration is nested inside the namespace
|
||||
``__llvm_libc``. All implementation constructs in LLVM-libc are declared within
|
||||
the namespace ``__llvm_libc``.
|
||||
|
||||
``.cpp`` File Structure
|
||||
-----------------------
|
||||
|
||||
The implementation can span multiple ``.cpp`` files. However, the signature of
|
||||
the entrypoint function should make use of a special macro. For example, the
|
||||
``round`` function from ``math.h`` should be defined as follows, say in the file
|
||||
``src/math/math/round.cpp``::
|
||||
|
||||
// --- round.cpp --- //
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
double LLVM_LIBC_ENTRYPOINT(round)(double d) {
|
||||
// ... implementation goes here.
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
Notice the use of the macro ``LLVM_LIBC_ENTRYPOINT``. This macro helps us define
|
||||
an C alias symbol for the C++ implementation. The C alias need not be added by
|
||||
the macro by itself. For example, for ELF targets, the macro is defined as
|
||||
follows::
|
||||
|
||||
#define ENTRYPOINT_SECTION_ATTRIBUTE(name) \
|
||||
__attribute__((section(".llvm.libc.entrypoint."#name)))
|
||||
#define LLVM_LIBC_ENTRYPOINT(name) ENTRYPOINT_SECTION_ATTRIBUTE(name) name
|
||||
|
||||
The macro places the C++ function in a unique section with name
|
||||
``.llvm.libc.entrypoint.<function name>``. This allows us to add a C alias using
|
||||
a post build step. For example, for the ``round`` function, one can use
|
||||
``objcopy`` to add an alias symbol as follows::
|
||||
|
||||
objcopy --add-symbol round=.llvm.libc.entrypoint.round:0,function round.o
|
||||
|
||||
NOTE: We use a post build ``objcopy`` step to add an alias instead of using
|
||||
the ``__attribute__((alias))``. For C++, this ``alias`` attribute requires
|
||||
mangled names of the referees. Using the post build ``objcopy`` step helps
|
||||
us avoid putting mangled names with ``alias`` atttributes.
|
|
@ -0,0 +1,85 @@
|
|||
LLVM-libc Source Tree Layout
|
||||
============================
|
||||
|
||||
At the top-level, LLVM-libc source tree is organized in to the following
|
||||
directories::
|
||||
|
||||
+ libc
|
||||
- cmake
|
||||
- docs
|
||||
- include
|
||||
- lib
|
||||
- loader
|
||||
- src
|
||||
+ utils
|
||||
- build_scripts
|
||||
- testing
|
||||
- www
|
||||
|
||||
Each of these directories is explained in detail below.
|
||||
|
||||
The ``cmake`` directory
|
||||
-----------------------
|
||||
|
||||
The ``cmake`` directory contains the implementations of LLVM-libc's CMake build
|
||||
rules.
|
||||
|
||||
The ``docs`` directory
|
||||
----------------------
|
||||
|
||||
The ``docs`` directory contains design docs and also informative documents like
|
||||
this document on source layout.
|
||||
|
||||
The ``include`` directory
|
||||
-------------------------
|
||||
|
||||
The ``include`` directory contains:
|
||||
|
||||
1. Self contained public header files - These are header files which are
|
||||
already in the form that get installed when LLVM-libc is installed on a user's
|
||||
computer.
|
||||
2. ``*.h.def`` and ``*.h.in`` files - These files are used to construct the
|
||||
generated public header files.
|
||||
3. A ``CMakeLists.txt`` file - This file lists the targets for the self
|
||||
contained and generated public header files.
|
||||
|
||||
The ``lib`` directory
|
||||
---------------------
|
||||
|
||||
This directory contains a ``CMakeLists.txt`` file listing the targets for the
|
||||
public libraries ``libc.a``, ``libm.a`` etc.
|
||||
|
||||
The ``loader`` directory
|
||||
------------------------
|
||||
|
||||
This directory contains the implementations of the application loaders like
|
||||
``crt1.o`` etc.
|
||||
|
||||
The ``src`` directory
|
||||
---------------------
|
||||
|
||||
This directory contains the implementations of the llvm-libc entrypoints. It is
|
||||
further organized as follows:
|
||||
|
||||
1. There is a toplevel CMakeLists.txt file.
|
||||
2. For every public header file provided by llvm-libc, there exists a
|
||||
corresponding directory in the ``src`` directory. The name of the directory
|
||||
is same as the base name of the header file. For example, the directory
|
||||
corresponding to the public ``math.h`` header file is named ``math``. The
|
||||
implementation standard document explains more about the *header*
|
||||
directories.
|
||||
|
||||
The ``www`` directory
|
||||
---------------------
|
||||
|
||||
The ``www`` directory contains the HTML content of libc.llvm.org
|
||||
|
||||
The ``utils/build_scripts`` directory
|
||||
-------------------------------------
|
||||
|
||||
This directory contains scripts which support the build system, tooling etc.
|
||||
|
||||
The ``utils/testing`` directory
|
||||
-------------------------------
|
||||
|
||||
This directory contains testing infrastructure.
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
add_header(
|
||||
llvm_libc_common_h
|
||||
HDR
|
||||
__llvm-libc-common.h
|
||||
)
|
||||
|
||||
add_header(
|
||||
ctype_h
|
||||
HDR
|
||||
ctype.h
|
||||
DEPENDS
|
||||
llvm_libc_common_h
|
||||
)
|
||||
|
||||
add_header(
|
||||
math_h
|
||||
HDR
|
||||
math.h
|
||||
DEPENDS
|
||||
llvm_libc_common_h
|
||||
)
|
||||
|
||||
add_header(
|
||||
string_h
|
||||
HDR
|
||||
string.h
|
||||
DEPENDS
|
||||
llvm_libc_common_h
|
||||
)
|
|
@ -0,0 +1,33 @@
|
|||
//===------- Common definitions for LLVM-libc public header files- --------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC___COMMON_H
|
||||
#define LLVM_LIBC___COMMON_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#undef __BEGIN_C_DECLS
|
||||
#define __BEGIN_C_DECLS extern "C" {
|
||||
|
||||
#undef __END_C_DECLS
|
||||
#define __END_C_DECLS }
|
||||
|
||||
#else // not __cplusplus
|
||||
|
||||
#undef __BEGIN_C_DECLS
|
||||
#define __BEGIN_C_DECLS
|
||||
|
||||
#undef __END_C_DECLS
|
||||
#define __END_C_DECLS
|
||||
|
||||
#undef __restrict
|
||||
#define __restrict restrict // C99 and above support the restrict keyword.
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // LLVM_LIBC___COMMON_H
|
|
@ -0,0 +1,46 @@
|
|||
//===---------------- C standard library header ctype.h -----------------*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_CTYPE_H
|
||||
#define LLVM_LIBC_CTYPE_H
|
||||
|
||||
#include <__llvm-libc-common.h>
|
||||
|
||||
__BEGIN_C_DECLS
|
||||
|
||||
int isalnum(int);
|
||||
|
||||
int isalpha(int);
|
||||
|
||||
int isblank(int);
|
||||
|
||||
int iscntrl(int);
|
||||
|
||||
int isdigit(int);
|
||||
|
||||
int isgraph(int);
|
||||
|
||||
int islower(int);
|
||||
|
||||
int isprint(int);
|
||||
|
||||
int ispunct(int);
|
||||
|
||||
int isspace(int);
|
||||
|
||||
int isupper(int);
|
||||
|
||||
int isxdigit(int);
|
||||
|
||||
int tolower(int);
|
||||
|
||||
int toupper(int);
|
||||
|
||||
__END_C_DECLS
|
||||
|
||||
#endif // LLVM_LIBC_CTYPE_H
|
|
@ -0,0 +1,360 @@
|
|||
//===----------------- C standard library header math.h -----------------*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_MATH_H
|
||||
#define LLVM_LIBC_MATH_H
|
||||
|
||||
#include <__llvm-libc-common.h>
|
||||
|
||||
__BEGIN_C_DECLS
|
||||
|
||||
double acos(double);
|
||||
|
||||
float acosf(float);
|
||||
|
||||
long double acosl(long double);
|
||||
|
||||
double asin(double);
|
||||
|
||||
float asinf(float);
|
||||
|
||||
long double asinl(long double);
|
||||
|
||||
double atan(double);
|
||||
|
||||
float atanf(float);
|
||||
|
||||
long double atanl(long double);
|
||||
|
||||
double atan2(double, double);
|
||||
|
||||
float atan2f(float, float);
|
||||
|
||||
long double atan2l(long double, long double);
|
||||
|
||||
double cos(double);
|
||||
|
||||
float cosf(float);
|
||||
|
||||
long double cosl(long double);
|
||||
|
||||
double sin(double);
|
||||
|
||||
float sinf(float);
|
||||
|
||||
long double sinl(long double);
|
||||
|
||||
double tan(double);
|
||||
|
||||
float tanf(float);
|
||||
|
||||
long double tanl(long double);
|
||||
|
||||
double acosh(double);
|
||||
|
||||
float acoshf(float);
|
||||
|
||||
long double acoshl(long double);
|
||||
|
||||
double asinh(double);
|
||||
|
||||
float asinhf(float);
|
||||
|
||||
long double asinhl(long double);
|
||||
|
||||
double atanh(double);
|
||||
|
||||
float atanhf(float);
|
||||
|
||||
long double atanhl(long double);
|
||||
|
||||
double cosh(double);
|
||||
|
||||
float coshf(float);
|
||||
|
||||
long double coshl(long double);
|
||||
|
||||
double sinh(double);
|
||||
|
||||
float sinhf(float);
|
||||
|
||||
long double sinhl(long double);
|
||||
|
||||
double tanh(double);
|
||||
|
||||
float tanhf(float);
|
||||
|
||||
long double tanhl(long double);
|
||||
|
||||
double exp(double);
|
||||
|
||||
float expf(float);
|
||||
|
||||
long double expl(long double);
|
||||
|
||||
double exp2(double);
|
||||
|
||||
float exp2f(float);
|
||||
|
||||
long double exp2l(long double);
|
||||
|
||||
double expm1(double);
|
||||
|
||||
float expm1f(float);
|
||||
|
||||
long double expm1l(long double);
|
||||
|
||||
double frexp(double, int);
|
||||
|
||||
float frexpf(float, int);
|
||||
|
||||
long double frexpl(long double, int);
|
||||
|
||||
int ilogb(double);
|
||||
|
||||
int ilogbf(float);
|
||||
|
||||
int ilogbl(long double);
|
||||
|
||||
double ldexp(double, int);
|
||||
|
||||
float ldexpf(float, int);
|
||||
|
||||
long double ldexpl(long double, int);
|
||||
|
||||
double log(double);
|
||||
|
||||
float logf(float);
|
||||
|
||||
long double logl(long double);
|
||||
|
||||
double log10(double);
|
||||
|
||||
float log10f(float);
|
||||
|
||||
long double log10l(long double);
|
||||
|
||||
double log1p(double);
|
||||
|
||||
float log1pf(float);
|
||||
|
||||
long double log1pl(long double);
|
||||
|
||||
double log2(double);
|
||||
|
||||
float log2f(float);
|
||||
|
||||
long double log2l(long double);
|
||||
|
||||
double logb(double);
|
||||
|
||||
float logbf(float);
|
||||
|
||||
long double logbl(long double);
|
||||
|
||||
double modf(double, double);
|
||||
|
||||
float modff(float, float);
|
||||
|
||||
long double modfl(long double, long double);
|
||||
|
||||
double scalbn(double, int);
|
||||
|
||||
float scalbnf(float, int);
|
||||
|
||||
long double scalbnl(long double, int);
|
||||
|
||||
double scalbln(double, long int);
|
||||
|
||||
float scalblnf(float, long int);
|
||||
|
||||
long double scalblnl(long double, long int);
|
||||
|
||||
double cbrt(double);
|
||||
|
||||
float cbrtf(float);
|
||||
|
||||
long double cbrtl(long double);
|
||||
|
||||
double fabs(double);
|
||||
|
||||
float fabsf(float);
|
||||
|
||||
long double fabsl(long double);
|
||||
|
||||
double hypot(double, double);
|
||||
|
||||
float hypotf(float, float);
|
||||
|
||||
long double hypotl(long double, long double);
|
||||
|
||||
double pow(double, double);
|
||||
|
||||
float powf(float, float);
|
||||
|
||||
long double powl(long double, long double);
|
||||
|
||||
double sqrt(double);
|
||||
|
||||
float sqrtf(float);
|
||||
|
||||
long double sqrtl(long double);
|
||||
|
||||
double erf(double);
|
||||
|
||||
float erff(float);
|
||||
|
||||
long double erfl(long double);
|
||||
|
||||
double erfc(double);
|
||||
|
||||
float erfcf(float);
|
||||
|
||||
long double erfcl(long double);
|
||||
|
||||
double lgamma(double);
|
||||
|
||||
float lgammaf(float);
|
||||
|
||||
long double lgammal(long double);
|
||||
|
||||
double tgamma(double);
|
||||
|
||||
float tgammaf(float);
|
||||
|
||||
long double tgammal(long double);
|
||||
|
||||
double ceil(double);
|
||||
|
||||
float ceilf(float);
|
||||
|
||||
long double ceill(long double);
|
||||
|
||||
double floor(double);
|
||||
|
||||
float floorf(float);
|
||||
|
||||
long double floorl(long double);
|
||||
|
||||
double nearbyint(double);
|
||||
|
||||
float nearbyintf(float);
|
||||
|
||||
long double nearbyintl(long double);
|
||||
|
||||
double rint(double);
|
||||
|
||||
float rintf(float);
|
||||
|
||||
long double rintl(long double);
|
||||
|
||||
long int lrint(double);
|
||||
|
||||
long int lrintf(float);
|
||||
|
||||
long int lrintl(long double);
|
||||
|
||||
long long int llrint(double);
|
||||
|
||||
long long int llrintf(float);
|
||||
|
||||
long long int llrintl(long double);
|
||||
|
||||
double round(double);
|
||||
|
||||
float roundf(float);
|
||||
|
||||
long double roundl(long double);
|
||||
|
||||
long int lround(double);
|
||||
|
||||
long int lroundf(float);
|
||||
|
||||
long int lroundl(long double);
|
||||
|
||||
long long int llround(double);
|
||||
|
||||
long long int llroundf(float);
|
||||
|
||||
long long int llroundl(long double);
|
||||
|
||||
double trunc(double);
|
||||
|
||||
float truncf(float);
|
||||
|
||||
long double truncl(long double);
|
||||
|
||||
double fmod(double, double);
|
||||
|
||||
float fmodf(float, float);
|
||||
|
||||
long double fmodl(long double, long double);
|
||||
|
||||
double remainder(double, double);
|
||||
|
||||
float remainderf(float, float);
|
||||
|
||||
long double remainderl(long double, long double);
|
||||
|
||||
double remquo(double, double, int);
|
||||
|
||||
float remquof(float, float, int);
|
||||
|
||||
long double remquol(long double, long double, int);
|
||||
|
||||
double copysign(double, double);
|
||||
|
||||
float copysignf(float, float);
|
||||
|
||||
long double copysignl(long double, long double);
|
||||
|
||||
double nan(const char);
|
||||
|
||||
float nanf(const char);
|
||||
|
||||
long double nanl(const char);
|
||||
|
||||
double nextafter(double, double);
|
||||
|
||||
float nextafterf(float, float);
|
||||
|
||||
long double nextafterl(long double, long double);
|
||||
|
||||
double nexttoward(double, long double);
|
||||
|
||||
float nexttowardf(float, long double);
|
||||
|
||||
long double nexttowardl(long double, long double);
|
||||
|
||||
double fdim(double, double);
|
||||
|
||||
float fdimf(float, float);
|
||||
|
||||
long double fdiml(long double, long double);
|
||||
|
||||
double fmax(double, double);
|
||||
|
||||
double fmaxf(double, double);
|
||||
|
||||
double fmaxl(double, double);
|
||||
|
||||
double fmin(double, double);
|
||||
|
||||
float fminf(float, float);
|
||||
|
||||
long double fminl(long double, long double);
|
||||
|
||||
double fma(double, double, double);
|
||||
|
||||
float fmaf(float, float, float);
|
||||
|
||||
long double fmal(long double, long double, long double);
|
||||
|
||||
__END_C_DECLS
|
||||
|
||||
#endif // LLVM_LIBC_MATH_H
|
|
@ -0,0 +1,66 @@
|
|||
//===---------------- C standard library header string.h ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_STRING_H
|
||||
#define LLVM_LIBC_STRING_H
|
||||
|
||||
#include <__llvm-libc-common.h>
|
||||
|
||||
#define __need_size_t // To get only size_t from stddef.h
|
||||
#define __need_NULL // To get only NULL from stddef.h
|
||||
#include <stddef.h>
|
||||
|
||||
__BEGIN_C_DECLS
|
||||
|
||||
void *memcpy(void *__restrict, const void *__restrict, size_t);
|
||||
|
||||
void *memmove(void *, const void *, size_t);
|
||||
|
||||
int memcmp(const void *, const void *, size_t);
|
||||
|
||||
void *memchr(const void *, int, size_t);
|
||||
|
||||
void *memset(void *, int, size_t);
|
||||
|
||||
char *strcpy(char *__restrict, const char *__restrict);
|
||||
|
||||
char *strncpy(char *__restrict, const char *__restrict, size_t);
|
||||
|
||||
char *strcat(char *__restrict, const char *__restrict);
|
||||
|
||||
char *strncat(char *, const char *, size_t);
|
||||
|
||||
int strcmp(const char *, const char *);
|
||||
|
||||
int strcoll(const char *, const char *);
|
||||
|
||||
int strncmp(const char *, const char *, size_t);
|
||||
|
||||
size_t strxfrm(char *__restrict, const char *__restrict, size_t);
|
||||
|
||||
char *strchr(const char *, int);
|
||||
|
||||
size_t strcspn(const char *, const char *);
|
||||
|
||||
char *strpbrk(const char *, const char *);
|
||||
|
||||
char *strrchr(const char *, int c);
|
||||
|
||||
size_t strspn(const char *, const char *);
|
||||
|
||||
char *strstr(const char *, const char *);
|
||||
|
||||
char *strtok(char *__restrict, const char *__restrict);
|
||||
|
||||
char *strerror(int);
|
||||
|
||||
size_t strlen(const char *);
|
||||
|
||||
__END_C_DECLS
|
||||
|
||||
#endif // LLVM_LIBC_STRING_H
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
add_entrypoint_library(
|
||||
llvmlibc
|
||||
DEPENDS
|
||||
### C standard library entrypoints
|
||||
# string.h entrypoints
|
||||
strcpy
|
||||
strcat
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(string)
|
||||
|
||||
add_subdirectory(__support)
|
|
@ -0,0 +1,9 @@
|
|||
add_gen_header(
|
||||
support_common_h
|
||||
DEF_FILE common.h.def
|
||||
PARAMS
|
||||
entrypoint_macro=${LIBC_TARGET_OS}/entrypoint_macro.h.inc
|
||||
GEN_HDR common.h
|
||||
DATA_FILES
|
||||
${LIBC_TARGET_OS}/entrypoint_macro.h.inc
|
||||
)
|
|
@ -0,0 +1,18 @@
|
|||
//===-------------------- Common internal contructs ---------------------*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SUPPORT_COMMON_H
|
||||
#define LLVM_LIBC_SUPPORT_COMMON_H
|
||||
|
||||
#define INLINE_ASM __asm__ __volatile__
|
||||
|
||||
<!> The entrypoint macro has a platform specific definition. So, we include the
|
||||
<!> right definition at build time.
|
||||
%%include_file(${entrypoint_macro})
|
||||
|
||||
#endif // LLVM_LIBC_SUPPORT_COMMON_H
|
|
@ -0,0 +1,13 @@
|
|||
//===---- Definition of LLVM_LIBC_ENTRYPOINT macro for ELF paltforms ----*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
%%begin()
|
||||
|
||||
#define ENTRYPOINT_SECTION_ATTRIBUTE(name) \
|
||||
__attribute__((section(".llvm.libc.entrypoint."#name)))
|
||||
#define LLVM_LIBC_ENTRYPOINT(name) ENTRYPOINT_SECTION_ATTRIBUTE(name) name
|
|
@ -0,0 +1,4 @@
|
|||
add_custom_target(libc_string_unittests)
|
||||
|
||||
add_subdirectory(strcpy)
|
||||
add_subdirectory(strcat)
|
|
@ -0,0 +1,21 @@
|
|||
add_entrypoint_object(
|
||||
strcat
|
||||
SRCS
|
||||
strcat.cpp
|
||||
HDRS
|
||||
strcat.h
|
||||
DEPENDS
|
||||
strcpy
|
||||
string_h
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strcat_test
|
||||
SUITE
|
||||
libc_string_unittests
|
||||
SRCS
|
||||
strcat_test.cpp
|
||||
DEPENDS
|
||||
strcat
|
||||
strcpy
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
//===-------------------- Implementation of strcat -----------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/string/strcat/strcat.h"
|
||||
|
||||
#include "src/__support/common.h"
|
||||
#include "src/string/strcpy/strcpy.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
char *LLVM_LIBC_ENTRYPOINT(strcat)(char *dest, const char *src) {
|
||||
// We do not yet have an implementaion of strlen in so we will use strlen
|
||||
// from another libc.
|
||||
__llvm_libc::strcpy(dest + ::strlen(dest), src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------- Implementation header for strcat -------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STRING_STRCAT_H
|
||||
#define LLVM_LIBC_SRC_STRING_STRCAT_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
char *strcat(char *dest, const char *src);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STRING_STRCAT_H
|
|
@ -0,0 +1,43 @@
|
|||
//===---------------------- Unittests for strcat --------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/string/strcat/strcat.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(StrCatTest, EmptyDest) {
|
||||
std::string abc = "abc";
|
||||
char *dest = new char[4];
|
||||
|
||||
dest[0] = '\0';
|
||||
|
||||
char *result = __llvm_libc::strcat(dest, abc.c_str());
|
||||
ASSERT_EQ(dest, result);
|
||||
ASSERT_EQ(std::string(dest), abc);
|
||||
ASSERT_EQ(std::string(dest).size(), abc.size());
|
||||
|
||||
delete[] dest;
|
||||
}
|
||||
|
||||
TEST(StrCatTest, NonEmptyDest) {
|
||||
std::string abc = "abc";
|
||||
char *dest = new char[4];
|
||||
|
||||
dest[0] = 'x';
|
||||
dest[1] = 'y';
|
||||
dest[2] = 'z';
|
||||
dest[3] = '\0';
|
||||
|
||||
char *result = __llvm_libc::strcat(dest, abc.c_str());
|
||||
ASSERT_EQ(dest, result);
|
||||
ASSERT_EQ(std::string(dest), std::string("xyz") + abc);
|
||||
ASSERT_EQ(std::string(dest).size(), abc.size() + 3);
|
||||
|
||||
delete[] dest;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
add_entrypoint_object(
|
||||
strcpy
|
||||
SRCS
|
||||
strcpy.cpp
|
||||
HDRS
|
||||
strcpy.h
|
||||
DEPENDS
|
||||
string_h
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
strcpy_test
|
||||
SUITE
|
||||
libc_string_unittests
|
||||
SRCS
|
||||
strcpy_test.cpp
|
||||
DEPENDS
|
||||
strcpy
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
//===-------------------- Implementation of strcpy -----------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/string/strcpy/strcpy.h"
|
||||
|
||||
#include "src/__support/common.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
char *LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {
|
||||
return reinterpret_cast<char *>(::memcpy(dest, src, ::strlen(src) + 1));
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------- Implementation header for strcpy -------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STRING_STRCPY_H
|
||||
#define LLVM_LIBC_SRC_STRING_STRCPY_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
char *strcpy(char *dest, const char *src);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STRING_STRCPY_H
|
|
@ -0,0 +1,40 @@
|
|||
//===----------------------- Unittests for strcpy -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/string/strcpy/strcpy.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(StrCpyTest, EmptyDest) {
|
||||
std::string abc = "abc";
|
||||
char *dest = new char[4];
|
||||
|
||||
char *result = __llvm_libc::strcpy(dest, abc.c_str());
|
||||
ASSERT_EQ(dest, result);
|
||||
ASSERT_EQ(std::string(dest), abc);
|
||||
ASSERT_EQ(std::string(dest).size(), abc.size());
|
||||
|
||||
delete[] dest;
|
||||
}
|
||||
|
||||
TEST(StrCpyTest, OffsetDest) {
|
||||
std::string abc = "abc";
|
||||
char *dest = new char[7];
|
||||
|
||||
dest[0] = 'x';
|
||||
dest[1] = 'y';
|
||||
dest[2] = 'z';
|
||||
|
||||
char *result = __llvm_libc::strcpy(dest + 3, abc.c_str());
|
||||
ASSERT_EQ(dest + 3, result);
|
||||
ASSERT_EQ(std::string(dest), std::string("xyz") + abc);
|
||||
ASSERT_EQ(std::string(dest).size(), abc.size() + 3);
|
||||
|
||||
delete[] dest;
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
#! /usr/bin/python
|
||||
#===---------------- Script to generate header files ----------------------===#
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https:#llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
#===-----------------------------------------------------------------------===#
|
||||
#
|
||||
# This script takes a .h.def file and generates a .h header file.
|
||||
# See docs/header_generation.md for more information.
|
||||
#
|
||||
#===-----------------------------------------------------------------------===#
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
COMMAND_PREFIX = "%%"
|
||||
COMMENT_PREFIX = "<!>"
|
||||
|
||||
BEGIN_COMMAND = "begin"
|
||||
COMMENT_COMMAND = "comment"
|
||||
INCLUDE_FILE_COMMAND = "include_file"
|
||||
|
||||
|
||||
class _Location(object):
|
||||
def __init__(self, filename, line_number):
|
||||
self.filename = filename
|
||||
self.line_number = line_number
|
||||
|
||||
def __str__(self):
|
||||
return "%s:%s" % (self.filename, self.line_number)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def output_stream_manager(filename):
|
||||
if filename is None:
|
||||
try:
|
||||
yield sys.stdout
|
||||
finally:
|
||||
pass
|
||||
else:
|
||||
output_stream = open(filename, "w")
|
||||
try:
|
||||
yield output_stream
|
||||
finally:
|
||||
output_stream.close()
|
||||
|
||||
|
||||
def _parse_command(loc, line):
|
||||
open_paren = line.find("(")
|
||||
if open_paren < 0 or line[-1] != ")":
|
||||
return _fatal_error(loc, "Incorrect header generation command syntax.")
|
||||
command_name = line[len(COMMAND_PREFIX):open_paren]
|
||||
args = line[open_paren + 1:-1].split(",")
|
||||
args = [a.strip() for a in args]
|
||||
if len(args) == 1 and not args[0]:
|
||||
# There are no args, so we will make the args list an empty list.
|
||||
args = []
|
||||
return command_name.strip(), args
|
||||
|
||||
|
||||
def _is_named_arg(token):
|
||||
if token.startswith("${") and token.endswith("}"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def _get_arg_name(token):
|
||||
return token[2:-1]
|
||||
|
||||
|
||||
def _fatal_error(loc, msg):
|
||||
sys.exit("ERROR:%s: %s" % (loc, msg))
|
||||
|
||||
|
||||
def _is_begin_command(line):
|
||||
if line.startswith(COMMAND_PREFIX + BEGIN_COMMAND):
|
||||
return True
|
||||
|
||||
|
||||
def include_file_command(out_stream, loc, args, values):
|
||||
if len(args) != 1:
|
||||
_fatal_error(loc, "`%%include_file` command takes exactly one "
|
||||
"argument. %d given." % len(args))
|
||||
include_file_path = args[0]
|
||||
if _is_named_arg(include_file_path):
|
||||
arg_name = _get_arg_name(include_file_path)
|
||||
include_file_path = values.get(arg_name)
|
||||
if not include_file_path:
|
||||
_fatal_error(
|
||||
loc,
|
||||
"No value specified for argument '%s'." % arg_name)
|
||||
if not os.path.exists(include_file_path):
|
||||
_fatal_error(
|
||||
loc,
|
||||
"Include file %s not found." % include_file_path)
|
||||
with open(include_file_path, "r") as include_file:
|
||||
begin = False
|
||||
for line in include_file.readlines():
|
||||
line = line.strip()
|
||||
if _is_begin_command(line):
|
||||
# Parse the command to make sure there are no errors.
|
||||
command_name, args = _parse_command(loc, line)
|
||||
if args:
|
||||
_fatal_error(loc, "Begin command does not take any args.")
|
||||
begin = True
|
||||
# Skip the line on which %%begin() is listed.
|
||||
continue
|
||||
if begin:
|
||||
out_stream.write(line + "\n")
|
||||
|
||||
|
||||
def begin_command(out_stream, loc, args, values):
|
||||
# "begin" command can only occur in a file included with %%include_file
|
||||
# command. It is not a replacement command. Hence, we just fail with
|
||||
# a fatal error.
|
||||
_fatal_error(loc, "Begin command cannot be listed in an input file.")
|
||||
|
||||
|
||||
# Mapping from a command name to its implementation function.
|
||||
REPLACEMENT_COMMANDS = {
|
||||
INCLUDE_FILE_COMMAND: include_file_command,
|
||||
BEGIN_COMMAND: begin_command,
|
||||
}
|
||||
|
||||
|
||||
def apply_replacement_command(out_stream, loc, line, values):
|
||||
if not line.startswith(COMMAND_PREFIX):
|
||||
# This line is not a replacement command.
|
||||
return line
|
||||
command_name, args = _parse_command(loc, line)
|
||||
command = REPLACEMENT_COMMANDS.get(command_name.strip())
|
||||
if not command:
|
||||
_fatal_error(loc, "Unknown replacement command `%`", command_name)
|
||||
command(out_stream, loc, args, values)
|
||||
|
||||
|
||||
def parse_options():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Script to generate header files from .def files.")
|
||||
parser.add_argument("def_file", metavar="DEF_FILE",
|
||||
help="Path to the .def file.")
|
||||
parser.add_argument("--args", "-P", nargs= "*", default=[],
|
||||
help="NAME=VALUE pairs for command arguments in the "
|
||||
"input .def file.")
|
||||
# The output file argument is optional. If not specified, the generated
|
||||
# header file content will be written to stdout.
|
||||
parser.add_argument("--out-file", "-o",
|
||||
help="Path to the generated header file. Defaults to "
|
||||
"stdout")
|
||||
opts = parser.parse_args()
|
||||
if not all(["=" in arg for arg in opts.args]):
|
||||
# We want all args to be specified in the form "name=value".
|
||||
_fatal_error(
|
||||
__file__ + ":" + "[command line]",
|
||||
"Command arguments should be listed in the form NAME=VALUE")
|
||||
return opts
|
||||
|
||||
|
||||
def main():
|
||||
opts = parse_options()
|
||||
arg_values = {}
|
||||
for name_value_pair in opts.args:
|
||||
name, value = name_value_pair.split("=")
|
||||
arg_values[name] = value
|
||||
with open(opts.def_file, "r") as def_file:
|
||||
loc = _Location(opts.def_file, 0)
|
||||
with output_stream_manager(opts.out_file) as out_stream:
|
||||
for line in def_file:
|
||||
loc.line_number += 1
|
||||
line = line.strip()
|
||||
if line.startswith(COMMAND_PREFIX):
|
||||
replacement_text = apply_replacement_command(
|
||||
out_stream, loc, line, arg_values)
|
||||
out_stream.write("\n")
|
||||
elif line.startswith(COMMENT_PREFIX):
|
||||
# Ignore comment line
|
||||
continue
|
||||
else:
|
||||
out_stream.write(line + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -59,7 +59,7 @@ endif()
|
|||
# LLVM_EXTERNAL_${project}_SOURCE_DIR using LLVM_ALL_PROJECTS
|
||||
# This allows an easy way of setting up a build directory for llvm and another
|
||||
# one for llvm+clang+... using the same sources.
|
||||
set(LLVM_ALL_PROJECTS "clang;clang-tools-extra;compiler-rt;debuginfo-tests;libclc;libcxx;libcxxabi;libunwind;lld;lldb;llgo;openmp;parallel-libs;polly;pstl")
|
||||
set(LLVM_ALL_PROJECTS "clang;clang-tools-extra;compiler-rt;debuginfo-tests;libc;libclc;libcxx;libcxxabi;libunwind;lld;lldb;llgo;openmp;parallel-libs;polly;pstl")
|
||||
set(LLVM_ENABLE_PROJECTS "" CACHE STRING
|
||||
"Semicolon-separated list of projects to build (${LLVM_ALL_PROJECTS}), or \"all\".")
|
||||
if( LLVM_ENABLE_PROJECTS STREQUAL "all" )
|
||||
|
|
|
@ -31,6 +31,7 @@ if(${LLVM_BUILD_RUNTIME})
|
|||
# dependent projects can see the target names of their dependencies.
|
||||
add_llvm_external_project(libunwind)
|
||||
add_llvm_external_project(pstl)
|
||||
add_llvm_external_project(libc)
|
||||
add_llvm_external_project(libcxxabi)
|
||||
add_llvm_external_project(libcxx)
|
||||
endif()
|
||||
|
|
Loading…
Reference in New Issue