diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a17effd24..1601b88a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,9 +8,7 @@ on: workflow_dispatch: env: - LLVM_RELEASE_VERSION_WINDOWS: 21.1.8 - LLVM_RELEASE_VERSION_MAC: 21 - LLVM_RELEASE_VERSION_LINUX: 21 + LLVM_RELEASE_VERSION: 21.x LLVM_RELEASE_VERSION_LINUX_MUSL: 20 LLVM_RELEASE_VERSION_OPENBSD: 20 LLVM_RELEASE_VERSION_NETBSD: 19 @@ -33,7 +31,7 @@ jobs: - uses: actions/cache@v5 with: path: build/_deps - key: ${{ runner.os }}-llvm-${{ env.LLVM_RELEASE_VERSION_WINDOWS }}-${{ matrix.build_type }}-${{ hashFiles('CMakeLists.txt', '.github/workflows/main.yml') }} + key: ${{ runner.os }}-llvm-${{ env.LLVM_RELEASE_VERSION }}-${{ matrix.build_type }}-${{ hashFiles('CMakeLists.txt', '.github/workflows/main.yml') }} # set up the environment for Ninja - uses: ilammy/msvc-dev-cmd@v1 @@ -42,7 +40,7 @@ jobs: - name: CMake Build run: | - cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DC3_FETCH_LLVM=ON cmake --build build --config ${{ matrix.build_type }} # We remove the GNU link tool so C3C picks up the MSVC link.exe @@ -132,40 +130,17 @@ jobs: run: ./scripts/tools/ci_tests.sh "./build/c3c" build-linux: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: build_type: [Release, Debug] - llvm_version: [17, 18, 19, 20, 21, 22] steps: - uses: actions/checkout@v6 - run: sudo apt-get update && sudo apt-get install -y zlib1g zlib1g-dev python3 ninja-build curl libcurl4-openssl-dev - - name: Install Clang ${{matrix.llvm_version}} - run: | - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - REPO_URL="http://apt.llvm.org/focal/ llvm-toolchain-focal" - if [[ "${{matrix.llvm_version}}" != "${{env.LLVM_DEV_VERSION}}" ]]; then REPO_URL="$REPO_URL-${{matrix.llvm_version}}"; fi - sudo add-apt-repository "deb $REPO_URL main" - sudo apt-get update - PKGS="clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev libpolly-${{matrix.llvm_version}}-dev" - if [[ "${{matrix.llvm_version}}" < 18 ]]; then PKGS="$PKGS libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools"; fi - sudo apt-get install -y $PKGS - name: CMake Build run: | - C3_LLVM_VER=${{matrix.llvm_version}} - if [[ "${{matrix.llvm_version}}" -ge 18 && "${{matrix.llvm_version}}" != "${{env.LLVM_DEV_VERSION}}" ]]; then C3_LLVM_VER="${{matrix.llvm_version}}.1"; fi - - cmake -B build -G Ninja \ - -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ - -DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \ - -DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \ - -DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \ - -DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \ - -DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \ - -DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \ - -DLLVM_ENABLE_LIBXML2=OFF \ - -DC3_LLVM_VERSION=$C3_LLVM_VER + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DC3_FETCH_LLVM=ON cmake --build build - name: Run Unified Tests run: ./scripts/tools/ci_tests.sh "./build/c3c" @@ -177,11 +152,9 @@ jobs: make C3C_PATH=../../../../build/ run - name: Bundle & Upload (Linux) - if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX run: | bash ./scripts/tools/package_build.sh "./build/c3c" "c3-linux-${{matrix.build_type}}" "tar" - uses: actions/upload-artifact@v6 - if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX with: name: c3-linux-${{matrix.build_type}} path: c3-linux-${{matrix.build_type}}.tar.gz @@ -224,44 +197,11 @@ jobs: fail-fast: false matrix: build_type: [Release, Debug] - llvm_version: [17, 18, 19, 20, 21] steps: - uses: actions/checkout@v6 - - name: Download LLVM - run: | - brew_install() { - for pkg in "$@"; do - brew list "$pkg" &>/dev/null || brew install "$pkg" - done - } - if [[ "${{ matrix.llvm_version }}" == "21" ]]; then - brew_install llvm lld ninja curl - echo "/opt/homebrew/opt/llvm/bin" >> $GITHUB_PATH - echo "/opt/homebrew/opt/lld/bin" >> $GITHUB_PATH - else - brew_install llvm@${{ matrix.llvm_version }} ninja curl - echo "/opt/homebrew/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH - if [[ "${{ matrix.llvm_version }}" -ge 19 ]]; then - brew_install lld@${{ matrix.llvm_version }} - echo "/opt/homebrew/opt/lld@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH - fi - fi - echo "CPATH=$(xcrun --show-sdk-path)/user/include" >> $GITHUB_ENV - name: CMake Build run: | - C3_LLVM_VER=${{matrix.llvm_version}} - if [[ "${{matrix.llvm_version}}" -ge 18 ]]; then C3_LLVM_VER="${{matrix.llvm_version}}.1"; fi - if [[ "${{ matrix.llvm_version }}" == "21" ]]; then - C3_LLD_DIR="/opt/homebrew/opt/lld/lib" - C3_LLD_INCLUDE_DIR="/opt/homebrew/opt/lld/include" - elif [[ "${{ matrix.llvm_version }}" -ge 19 ]]; then - C3_LLD_DIR="/opt/homebrew/opt/lld@${{ matrix.llvm_version }}/lib" - C3_LLD_INCLUDE_DIR="/opt/homebrew/opt/lld@${{ matrix.llvm_version }}/include" - else - C3_LLD_DIR="" - C3_LLD_INCLUDE_DIR="" - fi - cmake -B build -G Ninja -DC3_LLVM_VERSION=$C3_LLVM_VER -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DC3_LLD_DIR=$C3_LLD_DIR -DC3_LLD_INCLUDE_DIR=$C3_LLD_INCLUDE_DIR + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DC3_FETCH_LLVM=ON cmake --build build - name: Run Unified Tests run: ./scripts/tools/ci_tests.sh "./build/c3c" @@ -272,10 +212,8 @@ jobs: ../../build/c3c build hello_world_lib -vv --trust=full - name: Bundle & Upload (Mac) - if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC run: bash ./scripts/tools/package_build.sh "./build/c3c" "c3-macos-${{matrix.build_type}}" "zip" - uses: actions/upload-artifact@v6 - if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC with: name: c3-macos-${{matrix.build_type}} path: c3-macos-${{matrix.build_type}}.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 621738112..cc588d10e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,12 +97,16 @@ set(C3_USE_TB OFF CACHE BOOL "Use TB") set(C3_LLD_DIR "" CACHE STRING "Use custom LLD directory") set(C3_LLD_INCLUDE_DIR "" CACHE STRING "Use custom LLD include directory") set(C3_ENABLE_CLANGD_LSP OFF CACHE BOOL "Enable/Disable output of compile commands during generation") +set(C3_FETCH_LLVM OFF CACHE BOOL "Automatically download LLVM artifacts") +set(C3_LLVM_TAG "llvm_21.x" CACHE STRING "Tag/Branch to download LLVM from") set(LLVM_CRT_LIBRARY_DIR "" CACHE STRING "Use custom llvm's compiler-rt directory") set(TCC_LIB_PATH "/usr/lib/tcc/libtcc1.a" CACHE STRING "Use custom libtcc1.a path") set(C3_OPTIONS C3_LINK_DYNAMIC C3_WITH_LLVM + C3_FETCH_LLVM + C3_LLVM_TAG C3_LLVM_VERSION C3_USE_MIMALLOC C3_MIMALLOC_TAG @@ -155,51 +159,79 @@ if(C3_ENABLE_CLANGD_LSP) endif(C3_ENABLE_CLANGD_LSP) if(C3_WITH_LLVM) - if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") - if (C3_LLVM_VERSION STREQUAL "auto") - set(C3_LLVM_VERSION ${C3_LLVM_DEFAULT_VERSION}) + if(C3_FETCH_LLVM) + # 1. Determine local platform ID + if (WIN32) + set(C3_LLVM_PLATFORM "windows-amd64") + elseif (APPLE) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + set(C3_LLVM_PLATFORM "darwin-aarch64") + else() + set(C3_LLVM_PLATFORM "darwin-amd64") + endif() + else() # Linux + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(C3_LLVM_PLATFORM "linux-aarch64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "riscv64") + set(C3_LLVM_PLATFORM "linux-riscv64") + else() + set(C3_LLVM_PLATFORM "linux-amd64") + endif() endif() - FetchContent_Declare( - LLVM_Windows - URL https://github.com/c3lang/win-llvm/releases/download/llvm_21_1_8/llvm-21.1.8-windows-amd64-msvc17-libcmt.7z - ) - FetchContent_Declare( - LLVM_Windows_debug - URL https://github.com/c3lang/win-llvm/releases/download/llvm_21_1_8/llvm-21.1.8-windows-amd64-msvc17-libcmt-dbg.7z - ) - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - message("Loading Windows LLVM debug libraries, this may take a while...") - FetchContent_MakeAvailable(LLVM_Windows_debug) - set(llvm_dir ${llvm_windows_debug_SOURCE_DIR}) - else() - message("Loading Windows LLVM libraries, this may take a while...") - FetchContent_MakeAvailable(LLVM_Windows) - set(llvm_dir ${llvm_windows_SOURCE_DIR}) - endif() - message("Loaded Windows LLVM libraries into ${llvm_dir}") - set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH}) - find_package(LLVM REQUIRED CONFIG) - find_package(LLD REQUIRED CONFIG) + # 2. Determine if we want Debug or Release + set(C3_LLVM_SUFFIX "") + set(C3_LLVM_TYPE "Release") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(C3_LLVM_SUFFIX "-dbg") + set(C3_LLVM_TYPE "Debug") + endif() + + # 3. Construct URL + set(C3_LLVM_ARTIFACT_NAME "llvm-${C3_LLVM_PLATFORM}${C3_LLVM_SUFFIX}") + #set(C3_LLVM_URL "https://github.com/c3lang/c3-llvm/releases/download/${C3_LLVM_TAG}/${C3_LLVM_ARTIFACT_NAME}.tar.gz") + #set(C3_LLVM_URL "https://github.com//ManuLinares/llvm-custom-builds/releases/download/${C3_LLVM_TAG}/${C3_LLVM_ARTIFACT_NAME}.tar.gz") + + # We could also just set "latest" here to always fetch the latest release + set(C3_LLVM_URL "https://github.com/c3lang/llvm-for-c3/releases/latest/download/${C3_LLVM_ARTIFACT_NAME}.tar.gz") + + message(STATUS "Fetching ${C3_LLVM_TYPE} LLVM artifact for ${C3_LLVM_PLATFORM}...") + message(STATUS "URL: ${C3_LLVM_URL}") + + FetchContent_Declare( + LLVM_Artifact + URL ${C3_LLVM_URL} + ) + FetchContent_MakeAvailable(LLVM_Artifact) + + # 4. Point CMake to the fetched location + set(llvm_dir ${llvm_artifact_SOURCE_DIR}) + set(CMAKE_PREFIX_PATH ${llvm_dir} ${CMAKE_PREFIX_PATH}) + set(LLVM_DIR "${llvm_dir}/lib/cmake/llvm") + set(LLD_DIR "${llvm_dir}/lib/cmake/lld") + + # TEST: For Windows, we might need to add the bin dir to prefix path for find_package to work well + if (WIN32) + set(CMAKE_SYSTEM_PREFIX_PATH ${llvm_dir} ${CMAKE_SYSTEM_PREFIX_PATH}) + endif() + + find_package(LLVM REQUIRED CONFIG NO_DEFAULT_PATH) + find_package(LLD REQUIRED CONFIG NO_DEFAULT_PATH) else() - # Add paths for LLVM CMake files of version 19 and higher as they follow a new installation - # layout and are now in /usr/lib/llvm/*/lib/cmake/llvm/ rather than /usr/lib/cmake/llvm/ - # - # Because of CMAKE_FIND_PACKAGE_SORT_ORDER CMAKE_FIND_PACKAGE_SORT_DIRECTION, - # the newest version will always be found first. - c3_print_variables(CMAKE_PREFIX_PATH) - if (DEFINED LLVM_DIR) - message(STATUS "Looking for LLVM CMake files in user-specified directory ${LLVM_DIR}") + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + # Legacy MSVC path if someone explicitly disabled fetching but is on MSVC + find_package(LLVM REQUIRED CONFIG) + find_package(LLD REQUIRED CONFIG) else() + # Default system search file (GLOB LLVM_CMAKE_PATHS "/usr/lib/llvm/*/lib/cmake/llvm/") list (APPEND CMAKE_PREFIX_PATH ${LLVM_CMAKE_PATHS} "/usr/lib/") - message(STATUS "No LLVM_DIR specified, searching default directories ${CMAKE_PREFIX_PATH}") - endif() - if (NOT C3_LLVM_VERSION STREQUAL "auto") - find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG) - else() - find_package(LLVM REQUIRED CONFIG) + if (NOT C3_LLVM_VERSION STREQUAL "auto") + find_package(LLVM ${C3_LLVM_VERSION} REQUIRED CONFIG) + else() + find_package(LLVM REQUIRED CONFIG) + endif() endif() endif() @@ -297,7 +329,7 @@ if(C3_WITH_LLVM) find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} REQUIRED) else() find_library(LLVM NAMES libLLVM.a LLVM.lib PATHS ${LLVM_LIBRARY_DIRS} REQUIRED) - endif() + endif() set(llvm_libs ${LLVM}) # These don't seem to be reliable on windows. @@ -325,17 +357,36 @@ if(C3_WITH_LLVM) if (APPLE) set(lld_libs ${lld_libs} xar) - find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR}) - find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR}) - find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR}) - find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR}) - set(sanitizer_runtime_libraries - ${RT_ASAN_DYNAMIC} - ${RT_TSAN_DYNAMIC} - # Unused - # ${RT_UBSAN_DYNAMIC} - # ${RT_LSAN_DYNAMIC} - ) + if (llvm_dir) + file(GLOB_RECURSE RT_ASAN_DYNAMIC "${llvm_dir}/*libclang_rt.asan_osx_dynamic.dylib") + file(GLOB_RECURSE RT_TSAN_DYNAMIC "${llvm_dir}/*libclang_rt.tsan_osx_dynamic.dylib") + endif() + + if (NOT RT_ASAN_DYNAMIC OR NOT RT_TSAN_DYNAMIC) + # Fallback to searching in LLVM_LIBRARY_DIRS (for non-fetched LLVM) + find_file(RT_ASAN_DYNAMIC_PATH NAMES libclang_rt.asan_osx_dynamic.dylib PATHS ${LLVM_LIBRARY_DIRS} PATH_SUFFIXES "clang/${LLVM_MAJOR_VERSION}/lib/darwin" "clang/${LLVM_PACKAGE_VERSION}/lib/darwin") + find_file(RT_TSAN_DYNAMIC_PATH NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS ${LLVM_LIBRARY_DIRS} PATH_SUFFIXES "clang/${LLVM_MAJOR_VERSION}/lib/darwin" "clang/${LLVM_PACKAGE_VERSION}/lib/darwin") + if (RT_ASAN_DYNAMIC_PATH) + set(RT_ASAN_DYNAMIC ${RT_ASAN_DYNAMIC_PATH}) + endif() + if (RT_TSAN_DYNAMIC_PATH) + set(RT_TSAN_DYNAMIC ${RT_TSAN_DYNAMIC_PATH}) + endif() + endif() + + if (RT_ASAN_DYNAMIC) + list(GET RT_ASAN_DYNAMIC 0 RT_ASAN_DYNAMIC) + endif() + if (RT_TSAN_DYNAMIC) + list(GET RT_TSAN_DYNAMIC 0 RT_TSAN_DYNAMIC) + endif() + + if (RT_ASAN_DYNAMIC AND RT_TSAN_DYNAMIC) + set(sanitizer_runtime_libraries + ${RT_ASAN_DYNAMIC} + ${RT_TSAN_DYNAMIC} + ) + endif() endif() message(STATUS "Linking to llvm libs ${llvm_libs}") @@ -524,7 +575,7 @@ else() endif() if(C3_WITH_LLVM) - target_link_libraries(c3c ${llvm_libs} miniz c3c_wrappers ${lld_libs}) + target_link_libraries(c3c miniz c3c_wrappers) target_include_directories(c3c PRIVATE "${CMAKE_SOURCE_DIR}/wrapper/include/") @@ -532,11 +583,11 @@ if(C3_WITH_LLVM) target_include_directories(c3c_wrappers PRIVATE "${CMAKE_SOURCE_DIR}/wrapper/include/") - target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs}) + target_link_libraries(c3c_wrappers PUBLIC ${lld_libs} ${llvm_libs}) else() - target_link_libraries(c3c ${llvm_libs} miniz ${lld_libs}) + target_link_libraries(c3c miniz ${lld_libs} ${llvm_libs}) endif() @@ -653,8 +704,10 @@ if (C3_WITH_LLVM AND DEFINED sanitizer_runtime_libraries) if (APPLE) # Change LC_ID_DYLIB to be rpath-based instead of having an absolute path + # We set DYLD_LIBRARY_PATH so the tools (which might be dynamic) can find libLLVM.dylib in the artifact + string(REPLACE ";" ":" _dyld_path "${LLVM_LIBRARY_DIRS}") add_custom_command(TARGET c3c POST_BUILD - COMMAND find $/c3c_rt -type f -name "*.dylib" -execdir ${LLVM_TOOLS_BINARY_DIR}/llvm-install-name-tool -id @rpath/{} {} $ + COMMAND ${CMAKE_COMMAND} -E env "DYLD_LIBRARY_PATH=${_dyld_path}:$ENV{DYLD_LIBRARY_PATH}" find $/c3c_rt -type f -name "*.dylib" -execdir ${LLVM_TOOLS_BINARY_DIR}/llvm-install-name-tool -id @rpath/{} {} $ VERBATIM) endif()