Does building libc require full LLVM build?

I’m trying to cross compile libc following the instructions on this page.

https://libc.llvm.org/full_cross_build.html

The target triple is the same “arm-none-eabi”. When I compile libc I get the following error

../libc/utils/HdrGen\Command.h:12:10: fatal error: 'llvm/ADT/SmallVector.h' file not found
   12 | #include "llvm/ADT/SmallVector.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~

This kind of suggests that you need to build the whole LLVM before even trying to build libc. The instructions in standalone cross build suggests that you can build libc with an existing binary release with clang without building the LLVM infrastructure before (-DLLVM_ENABLE_PROJECTS=clang).

Is it possible to build libc without LLVM built previously?

There is a new headergen implementation in trunk already which only requires python and its yaml parser.

Thanks for the reply. With trunk I assume you mean the HEAD of the main branch.

I tried this first and I did manage to compile it, however there were some problems there which made me assume that the main branch wasn’t ready and therefore I used the release/19.x branch.

First target “arm-none-eabi” doesn’t work because I get this error.

libc\src/__support/CPP/atomic.h:91:5: error: large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0  bytes) [-Werror,-Watomic-alignment]
   91 |     __scoped_atomic_store_n(&val, rhs, int(mem_ord), (int)(mem_scope));
      |     ^

This error can go away if you set the target to “armv7-none-eabi”. Then the libc and libm go through the build.

However, then when you start to use the libc headers in a project I get this problem. I added in libc\config\baremetal\arm\headers.txt

    libc.include.wchar

and in libc\config\baremetal\arm\entrypoints.txt

    # wchar.h entrypoints
    libc.src.wchar.wctob

Because I need wchar.

Then I get the following error.

libc/include\llvm-libc-types/wchar_t.h:12:1: warning: typedef requires

      a name [-Wmissing-declarations]
   12 | typedef __WCHAR_TYPE__ wchar_t;
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The libc\include\llvm-libc-types\wchar.h include file is different from the release/19.x which looks like this.

#ifndef LLVM_LIBC_TYPES_WCHAR_T_H
#define LLVM_LIBC_TYPES_WCHAR_T_H

// Since __need_wchar_t is defined, we get the definition of wchar_t from the
// standalone C header stddef.h. Also, because __need_wchar_t is defined,
// including stddef.h will pull only the type wchar_t and nothing else.
#define __need_wchar_t
#include <stddef.h>
#undef __need_wchar_t

#endif // LLVM_LIBC_TYPES_WCHAR_T_H

versus the main branch.

#ifndef LLVM_LIBC_TYPES_WCHAR_T_H
#define LLVM_LIBC_TYPES_WCHAR_T_H

typedef __WCHAR_TYPE__ wchar_t;

#endif // LLVM_LIBC_TYPES_WCHAR_T_H

I dont’ know the background of this change and when I search for __WCHAR_TYPE__ I end up with nothing other than in wchar_t.h itself.

Is this also related to the LLVM needs to be built before libc?

I am waiting in an airport so I did not go through the post. Just a quick reply to this: the __XXX_TYPE__ thing is the internal representation of type as provided by clang/gcc.

Is this some configuration that I have missed? Shouldn’t wchar_t always be present and default to 32-bits unless said otherwise like for Windows targets or -fshort-wchar is passed?

I also got another error.

libc/include\llvm-libc-types/ssize_t.h:12:24: error: typedef
      redefinition with different types ('long long' vs 'int')
   12 | typedef __INT64_TYPE__ ssize_t;

This is obviously incorrect for ARM 32-bit targets. Isn’t there a __SSIZE_TYPE__?

It seems be discussed here about two years ago.

Could you please post the cmake command you’re using? That will help a lot with debugging. Also Windows support is very limited right now, so things may be broken.

Here it is and yes I’m cross compiling on Windows.

cmake ../runtimes -G Ninja -DLLVM_ENABLE_RUNTIMES=libc -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_WORKS=True -DCMAKE_CXX_COMPILER_WORKS=True -DLLVM_LIBC_FULL_BUILD=ON -DLIBC_TARGET_TRIPLE="armv7-none-eabi" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-mcpu=cortex-a9 -mthumb -msoft-float" -DCMAKE_CXX_FLAGS="-mcpu=cortex-a9 -mthumb -msoft-float"
 

It is essentially the one in the cross build guide but with a few extra C flags for the CPU, but they shouldn’t matter for the include file generation.

Regarding cross compiling on Windows, when compiling libc cmake seems to add compiler options intended for Windows. For example adding a library dependency to msvcrt. This is cmake that adds these flags and do not detect that the target triple is different from host.

The cmake script for libc doesn’t seem to detect if you are cross compiling or not. One way to come around this is to provide a toolchain file with -DCMAKE_TOOLCHAIN_FILE=mytoolchainfile.txt. This will reset the compiler flags and you can add yours. Keep in mind that you still have to provide -DLIBC_TARGET_TRIPLE="armv7-none-eabi" because it sets additional cmake flags that are required, unless you provide your own config.json.

The question is the clib cmake file should detect this on its own or if it is required to provide a toolchain file of other than host. I’d say you should provide a toolchain file as it provides most flexibility. This is something that needs to be documented and clarified to the users who want to cross build clib.

The mental mode for cmake is to let user specify whether they are cross-compiling. Please see CMAKE_CROSSCOMPILING — CMake 3.30.4 Documentation