Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.swp
*.profraw

llvm-project/llvm-project-*
llvm-project/clang
2 changes: 2 additions & 0 deletions ci/test-clang-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ fi

CC=/repo/toolchain/bin/clang
CXX=/repo/toolchain/bin/clang++
LLVM_PROFILE_FILE=foo.profraw
LLVM_PROFILE_VERBOSE=1
Comment on lines +12 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As shellcheck points out, these should be exported if we are going to keep them around (more on that below).

hello_c=/repo/llvm-project/hello.c
hello_cpp=/repo/llvm-project/hello.cpp
hello_exe=/tmp/hello
Expand Down
92 changes: 92 additions & 0 deletions llvm-project/Dockerfile.epoch4
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
ARG BASE

FROM alpine:edge AS source
RUN wget --no-verbose https://git.kernel.org/torvalds/t/linux-5.18-rc6.tar.gz
RUN wget --no-verbose https://musl.libc.org/releases/musl-1.2.3.tar.gz
RUN wget --no-verbose https://zlib.net/zlib-1.2.12.tar.gz
RUN wget --no-verbose https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.1/llvm-project-14.0.1.src.tar.xz

FROM ${BASE} AS stage3
FROM alpine:edge AS stage4

### BEGIN STAGE4

COPY --from=stage3 /usr/local/bin /usr/local/bin
COPY --from=stage3 /usr/local/lib /usr/local/lib
COPY --from=stage3 /usr/local/include /usr/local/include
RUN cd /usr/lib/ && \
for library in libc++abi.so.1 libc++.a libc++abi.a libc++.so.1 libunwind.so.1 libunwind.a; \
do ln -s "/usr/local/lib/x86_64-alpine-linux-musl/${library}" . ; \
done

### Linux
COPY --from=source linux-5.18-rc6.tar.gz .
RUN tar xf linux-5.18-rc6.tar.gz
RUN apk add make musl-dev rsync
RUN make -C linux-5.18-rc6 INSTALL_HDR_PATH=/sysroot/usr LLVM=1 -j$(nproc) headers_install
RUN apk del rsync musl-dev make

### Musl
COPY --from=source musl-1.2.3.tar.gz .
RUN tar xf musl-1.2.3.tar.gz
ARG MUSL_DIR=musl-1.2.3/build
RUN mkdir -p ${MUSL_DIR}
RUN cd ${MUSL_DIR} && \
CC=clang AR=llvm-ar RANLIB=llvm-ranlib \
../configure --prefix=/usr --syslibdir=/usr/lib
RUN apk add make
RUN make -C ${MUSL_DIR} -j$(nproc)
RUN make -C ${MUSL_DIR} -j$(nproc) DESTDIR=/sysroot install-headers
RUN make -C ${MUSL_DIR} -j$(nproc) DESTDIR=/sysroot install-libs
RUN apk del make

# Pause for a quick sanity check
COPY hello.c hello.cpp /
ARG SYSROOT=--sysroot=/sysroot
RUN clang ${SYSROOT} hello.c && ./a.out && \
clang ${SYSROOT} hello.c -static && ./a.out && \
clang++ ${SYSROOT} hello.cpp && ./a.out && \
clang++ ${SYSROOT} hello.cpp -static -lc++abi && ./a.out
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the SYSROOT ARG?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not "install" the sysroot we built to the standard /usr/local/. I think I need to play around with --prefix when configuring.

I somewhat think it's interesting to keep the sysroot separate, but the kernel has some hermiticity issues with host utilities that make building it more difficult.

Specifically, I'm using ARG to shorten repeated use of long command line options; not for someone to override at docker build time.

Should I install the sysroot to /usr/local/ and drop the explicit --sysroot= flags?


### Zlib
COPY --from=source zlib-1.2.12.tar.gz .
RUN tar xf zlib-1.2.12.tar.gz
ARG ZLIB_DIR=zlib-1.2.12/build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the value of this. Do you intend for it to be controllable by the invoker?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just making it shorter to refer to multiple times.

RUN mkdir -p ${ZLIB_DIR}
RUN cd ${ZLIB_DIR} && \
CC="clang ${SYSROOT}" AR=llvm-ar ../configure --prefix=/sysroot/usr
RUN apk add make
RUN make -C ${ZLIB_DIR} -j$(nproc)
RUN make -C ${ZLIB_DIR} -j$(nproc) install
RUN apk del make

### LLVM
COPY --from=source llvm-project-14.0.1.src.tar.xz .
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the value of the COPY instead of just downloading it? If you are trying to save space by avoiding the layer, it seems like building and copying artifacts is what you want.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not trying to optimize space of the docker image at all; rather I'm trying to optimize development time. It's faster to copy the tarball between local images than to keep redownloading it.

RUN tar xf llvm-project-14.0.1.src.tar.xz && \
mv llvm-project-14.0.1.src llvm-project
RUN apk add cmake ninja python3
COPY stage4.cmake llvm-project/.
ARG LLVM_BUILD_DIR=llvm-project/llvm/build
RUN cmake \
-B ${LLVM_BUILD_DIR} \
-C llvm-project/stage4.cmake \
-D LLVM_DEFAULT_TARGET_TRIPLE=$(clang -print-target-triple) \
-S llvm-project/llvm \
-G Ninja
RUN ninja -C ${LLVM_BUILD_DIR} install-clang install-lld
RUN ninja -C ${LLVM_BUILD_DIR} install-clang-resource-headers
RUN ninja -C ${LLVM_BUILD_DIR} \
install-llvm-ar \
install-llvm-nm \
install-llvm-objcopy \
install-llvm-objdump \
install-llvm-ranlib \
install-llvm-readelf \
install-llvm-strip
RUN ninja -C ${LLVM_BUILD_DIR} install-compiler-rt

RUN apk del cmake ninja python3

# Final test
RUN llvm-readelf -p .comment $(which clang) | grep -e clang -e LLD
RUN llvm-readelf -p .comment $(which clang) | grep -v GCC
11 changes: 7 additions & 4 deletions llvm-project/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ epoch2:
epoch3:
$(call epoch_cmd,$@,$(IMAGE):stage3-$(HOST_ARCH),$(IMAGE):stage2-$(HOST_ARCH))

clang: epoch3
epoch4:
$(call epoch_cmd,$@,$(IMAGE):stage4-$(HOST_ARCH),$(IMAGE):stage3-$(HOST_ARCH))

clang: epoch4
$(DOCKER) rm llvm-project || true
$(DOCKER) create --name llvm-project $(IMAGE):stage3-$(HOST_ARCH)
$(DOCKER) create --name llvm-project $(IMAGE):stage4-$(HOST_ARCH)
$(DOCKER) cp llvm-project:/usr/local/bin/clang-14 clang

test: epoch3
bash ../ci/test-clang.sh $(IMAGE):stage3-$(HOST_ARCH)
test: epoch4
bash ../ci/test-clang.sh $(IMAGE):stage4-$(HOST_ARCH)
96 changes: 96 additions & 0 deletions llvm-project/stage4.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Please try to keep these cmake variables alphabetically sorted.

# Enable optimizations, as opposed to a debug build.
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")

# Explicitly use stage3's clang. Not necessary, just being explicit.
set(CMAKE_CXX_COMPILER "/usr/local/bin/clang++" CACHE FILEPATH "")
set(CMAKE_C_COMPILER "/usr/local/bin/clang" CACHE FILEPATH "")

# See above comment for CMAKE_CXX_COMPILER.
# Use the sysroot we've been building up.
set(CMAKE_CXX_FLAGS "--sysroot=/sysroot" CACHE STRING "")
set(CMAKE_C_FLAGS "--sysroot=/sysroot" CACHE STRING "")

# Statically link resulting executable.
set(CMAKE_EXE_LINKER_FLAGS "-static -lc++abi" CACHE STRING "")

# The compiler builtins are necessary.
set(COMPILER_RT_BUILD_BUILTINS ON CACHE BOOL "")

# GWP ASAN fails to build without libexecinfo-dev. Don't need it for stage3.
set(COMPILER_RT_BUILD_GWP_ASAN OFF CACHE BOOL "")

# Don't need libfuzzer, ever.
set(COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "")

# Don't need memprof, ever.
set(COMPILER_RT_BUILD_MEMPROF OFF CACHE BOOL "")

# Don't need ORC, ever.
set(COMPILER_RT_BUILD_ORC OFF CACHE BOOL "")

# Explicitly enable profiling support. The implicit default is ON.
set(COMPILER_RT_BUILD_PROFILE ON CACHE BOOL "")

# Disable sanitizer support. Not necessary for stage3.
set(COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")

# Don't need xray.
set(COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "")

# Build LLVM instrumented to collect PGO profile data.
set(LLVM_BUILD_INSTRUMENTED ON CACHE BOOL "")

# Use libc++ from stage3.
# TODO: is CMAKE_CXX_FLAGS still necessary if this is set?
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")

# Use lld from stage3.
set(LLVM_ENABLE_LLD ON CACHE BOOL "")

# Build clang, lld, and compiler-rt.
set(LLVM_ENABLE_PROJECTS "clang;lld;compiler-rt" CACHE STRING "")

# FORCE_ON causes the build to fail if zlib is not found in the environment
# during configuration, rather than much later during link.
set(LLVM_ENABLE_ZLIB "FORCE_ON" CACHE STRING "")

# This is necessary to statically link libc++ into clang.
set(LLVM_STATIC_LINK_CXX_STDLIB "1" CACHE STRING "")

# Just build stage3 to target the host. It's not the end product, so it won't
# be able to target all of the kernel targets we can build.
set(LLVM_TARGETS_TO_BUILD "host;" CACHE STRING "")

# Necessary to avoid warnings about counter overflow.
set(LLVM_VP_COUNTERS_PER_SITE "6" CACHE STRING "")

# Set clang's default --stdlib= to libc++.
set(CLANG_DEFAULT_CXX_STDLIB "libc++" CACHE STRING "")

# Set clang's default -fuse-ld= to lld.
set(CLANG_DEFAULT_LINKER "lld" CACHE STRING "")

# Have clang default to llvm-objcopy.
set(CLANG_DEFAULT_OBJCOPY "llvm-objcopy" CACHE STRING "")

# Set clang's default --rtlib= to compiler-rt.
set(CLANG_DEFAULT_RTLIB "compiler-rt" CACHE STRING "")

# Set clang's default --unwindlib= to libunwind.
set(CLANG_DEFAULT_UNWINDLIB "libunwind" CACHE STRING "")

# Disable arc migrate. We don't use that, ever.
set(CLANG_ENABLE_ARCMT OFF CACHE BOOL "")

# Disable static analyzer. Don't need it for stage3.
set(CLANG_ENABLE_STATIC_ANALYZER OFF CACHE BOOL "")

# Disable plugin support. Don't need it, ever.
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")

# Because we're using --prefix=/sysroot/usr, zlib gets installed to a
# non-standard path.
set(ZLIB_INCLUDE_DIR "/sysroot/usr/include/zlib.h" CACHE FILEPATH "")
set(ZLIB_LIBRARY "/sysroot/usr/lib/libz.a" CACHE FILEPATH "")