Compile LLVM from sources on macOS Catalina (How to solve "stdio.h" not found)

Viewed 909

I'm bringing to your attention a question I tackled with for a few days and no issue could solve for me, in the hope that it'll save some other people time.

I try to compile LLVM from sources on macOS Catalina (10.15).

To do so, I used the following commands (after following the LLVM build manual):

git clone https://github.com/llvm/llvm-project
cd llvm-project
mkdir build && cd build
cmake -G "Ninja" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE="Debug" ../llvm
ninja

Now you should have a working clang compiler under build/bin. However, given /tmp/program.c with this contents:

#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;
}

I got the following output:

/tmp/program.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.```

I tried a lot of solutions, including setting `CPATH`, `CFLAGS`, `CXXFLAGS`, `LDFLAGS` etc but none worked.
2 Answers

System headers new path

Since macOS Catalina, the /usr folder is been mounted as a read-only directory, so even as a root - no one has permission to modify this folder (well, unless you reboot in SIP mode, which's obviously not a considerable solution). The entire toolchain is saved by default under /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk. You can get your path by executing xcrun --show-sdk-path. I'll assume that you do have the default path in my answer but please adjust as needed.

Gathering information

Running clang with the -v flag gave me the following:

./clang /tmp/program.c -v --    
clang version 11.0.0 (https://github.com/llvm/llvm-project 01641197ee0bd3895c756c925723c8c8e03bcb09)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
InstalledDir: ~/llvm/llvm-project/build/bin/.
 "~/llvm/llvm-project/build/bin/clang-11" -cc1 -triple x86_64-apple-macosx10.15.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -main-file-name program.c -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fno-rounding-math -munwind-tables -fcompatibility-qualified-id-block-type-checking -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -target-linker-version 556.6 -v -resource-dir ~/llvm/llvm-project/build/lib/clang/11.0.0 -internal-isystem /usr/local/include -internal-isystem ~/llvm/llvm-project/build/lib/clang/11.0.0/include -internal-externc-isystem /usr/include -fdebug-compilation-dir ~/llvm/llvm-project/build/bin -ferror-limit 19 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fmax-type-align=16 -fcolor-diagnostics -o /var/folders/64/6bf82c_52ws1n4cwc376znvr0000gn/T/program-d111a4.o -x c /tmp/program.c
clang -cc1 version 11.0.0 based upon LLVM 11.0.0git default target x86_64-apple-darwin19.5.0
ignoring nonexistent directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 ~/llvm/llvm-project/build/lib/clang/11.0.0/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
/tmp/program.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.

Which can teach us that our include paths for system headers are:

/usr/local/include
~/llvm/llvm-project/build/lib/clang/11.0.0/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)

Hence, we can see that the location of the new headers (/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk) doesn't appear here and thus the error.

We could do a symbolic link from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk to /usr/local/include, but that'd create conflicting headers and have bad side effects (yes, I tried. Yes, it was very stupid...).

Solution

We can see that one of the default search headers path appears under the build directory (~/llvm/llvm-project/build/lib/clang/11.0.0/include). Symbolic-linking the standard headers to this directory won't create any dangerous conflicts.

Hence, all you need to do to solve this issue, is:

ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/* ~/llvm/llvm-project/build/lib/clang/11.0

I hope that my answer will help others who struggle with this issue.

To be able to use clang compiled from LLVM sources on macOS, you can do the following:

  • Set PATH to include the bin directory where the newly built clang is located.
  • New clang needs to know where XCode SDK is located. You can do this by setting SDKROOT environment variable. For example:
 SDKROOT=`xcrun --show-sdk-path` clang test.c

That should be it.

Related