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 entrypoints live in the directory for the header they belong to. Some entrypoints are platform specific, and so their implementations are in a subdirectory with the name of the platform (e.g. stdio/linux/remove.cpp).

Implementation of entrypoints can span multiple .cpp and .h files, but there will be at least one header file with name of the form <entrypoint name>.h for every entrypoint. This header file is called the implementation header file. For the isalpha function, the path to the implementation header file is src/ctype/isalpha.h.

Implementation Header File Structure

We will use the isalpha function from the public ctype.h header file as an example. The isalpha function will be declared in an internal header file src/ctype/isalpha.h as follows:

// --- isalpha.h --- //
#ifndef LLVM_LIBC_SRC_CTYPE_ISALPHA_H
#define LLVM_LIBC_SRC_CTYPE_ISALPHA_H

namespace LIBC_NAMESPACE_DECL {

int isalpha(int c);

} // namespace LIBC_NAMESPACE_DECL

#endif LLVM_LIBC_SRC_CTYPE_ISALPHA_H

Notice that the isalpha function declaration is nested inside the namespace LIBC_NAMESPACE_DECL. All implementation constructs in LLVM-libc are declared within the namespace LIBC_NAMESPACE_DECL.

.cpp File Structure

The main .cpp file is named <entrypoint name>.cpp and is usually in the same folder as the header. It contains the signature of the entrypoint function, which must be defined with the LLVM_LIBC_FUNCTION macro. For example, the isalpha function from ctype.h is defined as follows, in the file src/ctype/isalpha.cpp:

// --- isalpha.cpp --- //

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(int, isalpha, (int c)) {
  // ... implementation goes here.
}

} // namespace LIBC_NAMESPACE_DECL

Notice the use of the macro LLVM_LIBC_FUNCTION. This macro helps us define a C alias symbol for the C++ implementation. For example, for a library build, the macro is defined as follows:

#define LLVM_LIBC_FUNCTION(type, name, arglist)
    LLVM_LIBC_FUNCTION_IMPL(type, name, arglist)
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist)
    LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name)
        __##name##_impl__ __asm__(#name);
    decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]];
    type __##name##_impl__ arglist

The LLVM_LIBC_FUNCTION_ATTR macro is normally defined to nothing, but can be defined by vendors who want to set their own attributes.