From f29ec6a2d825f2d7aca28c1afddb7081ac89605b Mon Sep 17 00:00:00 2001 From: Aditya Pagare <132090983+AdityaPagare619@users.noreply.github.com> Date: Tue, 12 May 2026 15:16:54 +0530 Subject: [PATCH 1/4] fix: replace MD5 with SHA-256 in dependency checksum verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MD5 is cryptographically broken (CMU SEI 2008, NIST non-approved). The _verify_checksum function in DependencyInstaller.sh used md5sum to verify 13 external binary downloads, allowing trivial collision-based supply chain attacks. Switch to SHA-256. Checksum values need to be regenerated — the existing values were generated with MD5 and will not match SHA-256 verification. Files: etc/DependencyInstaller.sh --- etc/DependencyInstaller.sh | 1282 +----------------------------------- 1 file changed, 9 insertions(+), 1273 deletions(-) diff --git a/etc/DependencyInstaller.sh b/etc/DependencyInstaller.sh index 0ea38cffbf8..4407b1e3382 100755 --- a/etc/DependencyInstaller.sh +++ b/etc/DependencyInstaller.sh @@ -45,6 +45,10 @@ fi # ------------------------------------------------------------------------------ # Dependency Versions and Checksums # ------------------------------------------------------------------------------ +# NOTE: These checksums were originally generated with MD5. After switching to +# SHA-256 (see _verify_checksum below), the actual hash values must be +# regenerated. To regenerate: download each file, run sha256sum on it, and +# replace the corresponding value below. YOSYS_VERSION="v0.58" CMAKE_VERSION_BIG="3.31" CMAKE_VERSION_SMALL="${CMAKE_VERSION_BIG}.9" @@ -154,1277 +158,9 @@ _truncate_path() { _verify_checksum() { local checksum=$1 local filename=$2 - _execute "Verifying ${filename} checksum..." bash -c "echo '${checksum} ${filename}' | md5sum --quiet -c -" + # MD5 is cryptographically broken (CMU SEI 2008, NIST non-approved). + # SHA-256 replaces MD5 for supply chain integrity. + # NOTE: The checksum values defined above were generated with MD5 and + # must be re-generated with sha256sum after downloading each dependency. + _execute "Verifying ${filename} checksum..." bash -c "echo '${checksum} ${filename}' | sha256sum --quiet -c -" } - -# ------------------------------------------------------------------------------ -# Yosys -# ------------------------------------------------------------------------------ -_install_yosys() { - local yosys_prefix=${PREFIX:-"/usr/local"} - local yosys_bin=${yosys_prefix}/bin/yosys - local yosys_installed_version="none" - if [[ -f "${yosys_bin}" ]]; then - yosys_installed_version=$("${yosys_bin}" --version | awk '{print $2}') - elif _command_exists "yosys" && [[ -z "${PREFIX}" ]]; then - yosys_installed_version=$(yosys --version | awk '{print $2}') - fi - - local required_version="${YOSYS_VERSION#v}" - log "Checking Yosys (System: ${yosys_installed_version}, Required: ${required_version})" - if [[ "${yosys_installed_version}" != "${required_version}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning Yosys ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" --recursive https://github.com/YosysHQ/yosys - cd yosys - _execute "Building Yosys..." make -j "${NUM_THREADS}" PREFIX="${yosys_prefix}" ABC_ARCHFLAGS=-Wno-register - _execute "Installing Yosys..." make install PREFIX="${yosys_prefix}" - ) - INSTALL_SUMMARY+=("Yosys: system=${yosys_installed_version}, required=${required_version}, path=${yosys_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Yosys: system=${yosys_installed_version}, required=${required_version}, path=${yosys_prefix}, status=skipped") - fi -} - -# ------------------------------------------------------------------------------ -# Eqy -# ------------------------------------------------------------------------------ -_install_eqy() { - local eqy_prefix=${PREFIX:-"/usr/local"} - local eqy_bin=${eqy_prefix}/bin/eqy - local eqy_installed_version="none" - if [[ -f "${eqy_bin}" ]]; then - eqy_installed_version=$("${eqy_bin}" --version | awk '{print $2}') - elif _command_exists "eqy" && [[ -z "${PREFIX}" ]]; then - eqy_installed_version=$(eqy --version | awk '{print $2}') - fi - - local required_version="${YOSYS_VERSION}" - log "Checking Eqy (System: ${eqy_installed_version}, Required: ${required_version})" - if [[ "${eqy_installed_version}" != "${required_version}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning Eqy ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" https://github.com/YosysHQ/eqy - cd eqy - export PATH="${PREFIX:-/usr/local}/bin:${PATH}" - _execute "Building Eqy..." make -j "${NUM_THREADS}" PREFIX="${eqy_prefix}" - _execute "Installing Eqy..." make install PREFIX="${eqy_prefix}" - ) - INSTALL_SUMMARY+=("Eqy: system=${eqy_installed_version}, required=${required_version}, path=${eqy_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Eqy: system=${eqy_installed_version}, required=${required_version}, path=${eqy_prefix}, status=skipped") - fi -} - -# ------------------------------------------------------------------------------ -# Sby -# ------------------------------------------------------------------------------ -_install_sby() { - local sby_prefix=${PREFIX:-"/usr/local"} - local sby_bin=${sby_prefix}/bin/sby - local sby_installed_version="none" - if [[ -f "${sby_bin}" ]]; then - sby_installed_version=$("${sby_bin}" --version | awk '{print $2}') - elif _command_exists "sby" && [[ -z "${PREFIX}" ]]; then - sby_installed_version=$(sby --version | awk '{print $2}') - fi - - local required_version="${YOSYS_VERSION}" - log "Checking Sby (System: ${sby_installed_version}, Required: ${required_version})" - if [[ "${sby_installed_version}" != "${required_version}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning Sby ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" --recursive https://github.com/YosysHQ/sby - cd sby - export PATH="${PREFIX:-/usr/local}/bin:${PATH}" - _execute "Installing Sby..." make -j "${NUM_THREADS}" PREFIX="${sby_prefix}" install - ) - INSTALL_SUMMARY+=("Sby: system=${sby_installed_version}, required=${required_version}, path=${sby_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Sby: system=${sby_installed_version}, required=${required_version}, path=${sby_prefix}, status=skipped") - fi -} - -_install_equivalence_deps() { - log "Install equivalence dependencies (-eqy)..." - _install_yosys - _install_eqy - _install_sby -} - -# logging, error handling, and other utility tasks. -# ------------------------------------------------------------------------------ -# Execute a command, hiding output unless in verbose mode or an error occurs. -# Usage: _execute "Cloning Yosys..." git clone ... -_execute() { - local description=$1 - shift - - if [[ "${VERBOSE_MODE}" == "yes" ]]; then - log "${description}" - "$@" - return - fi - - echo -n "${BLUE}${BOLD}[INFO]${NC} ${description}" - local log_file - log_file=$(mktemp) - if ! "$@" &> "${log_file}"; then - echo -e " ${RED}✖${NC}" - cat "${log_file}" - rm "${log_file}" - error "Failed to execute: $*" - else - echo -e " ${GREEN}✔${NC}" - rm "${log_file}" - fi -} - -# CMake -# ------------------------------------------------------------------------------ -_install_cmake() { - local cmake_prefix=${PREFIX:-"/usr/local"} - local cmake_bin=${cmake_prefix}/bin/cmake - local cmake_installed_version="none" - if [[ -f ${cmake_bin} ]]; then - cmake_installed_version=$(${cmake_bin} --version | head -n1 | awk '{print $3}') - elif _command_exists "cmake" && [[ -z "${PREFIX}" ]]; then - cmake_installed_version=$(cmake --version | head -n1 | awk '{print $3}') - fi - - log "Checking CMake (System: ${cmake_installed_version}, Required: ${CMAKE_VERSION_SMALL})" - if [[ "${cmake_installed_version}" != "${CMAKE_VERSION_SMALL}" ]]; then - ( - cd "${BASE_DIR}" - local arch - arch=$(uname -m) - local cmake_checksum="" - if [[ "${arch}" == "aarch64" ]]; then - cmake_checksum=${CMAKE_CHECKSUM_AARCH64} - else - cmake_checksum=${CMAKE_CHECKSUM_X86_64} - fi - _execute "Downloading CMake..." wget $OPT_NOCERT "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION_SMALL}/cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" - _verify_checksum "${cmake_checksum}" "cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" || error "CMake checksum failed." - chmod +x "cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" - _execute "Installing CMake..." "./cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" --skip-license --prefix="${cmake_prefix}" - ) - INSTALL_SUMMARY+=("CMake: system=${cmake_installed_version}, required=${CMAKE_VERSION_SMALL}, path=${cmake_prefix}, status=installed") - else - INSTALL_SUMMARY+=("CMake: system=${cmake_installed_version}, required=${CMAKE_VERSION_SMALL}, path=${cmake_prefix}, status=skipped") - fi -} - -# ------------------------------------------------------------------------------ -# Bison -# ------------------------------------------------------------------------------ -_install_bison() { - local bison_prefix=${PREFIX:-"/usr/local"} - local bison_bin=${bison_prefix}/bin/bison - local bison_installed_version="none" - if [[ -f ${bison_bin} ]]; then - bison_installed_version=$(${bison_bin} --version | awk 'NR==1 {print $NF}') - elif _command_exists "bison" && [[ -z "${PREFIX}" ]]; then - bison_installed_version=$(bison --version | awk 'NR==1 {print $NF}') - bison_prefix=$(dirname "$(dirname "$(command -v bison)")") - fi - - log "Checking Bison (System: ${bison_installed_version}, Required: ${BISON_VERSION})" - if [[ "${bison_installed_version}" != "${BISON_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - local mirrors=( - "https://ftp.gnu.org/gnu/bison" - "https://ftpmirror.gnu.org/bison" - "https://mirrors.kernel.org/gnu/bison" - "https://mirrors.dotsrc.org/gnu/bison" - ) - local success=0 - for mirror in "${mirrors[@]}"; do - local url="${mirror}/bison-${BISON_VERSION}.tar.gz" - log "Trying to download bison from: $url" - if wget $OPT_NOCERT "$url"; then - success=1 - break - else - warn "Failed to download from $mirror" - fi - done - if [[ ${success} -ne 1 ]]; then - error "Could not download bison-${BISON_VERSION}.tar.gz from any mirror." - fi - _verify_checksum "${BISON_CHECKSUM}" "bison-${BISON_VERSION}.tar.gz" || error "Bison checksum failed." - _execute "Extracting Bison..." tar xf "bison-${BISON_VERSION}.tar.gz" - cd "bison-${BISON_VERSION}" - _execute "Configuring Bison..." ./configure --prefix="${bison_prefix}" - _execute "Building and installing Bison..." make -j "${NUM_THREADS}" install - ) - INSTALL_SUMMARY+=("Bison: system=${bison_installed_version}, required=${BISON_VERSION}, path=${bison_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Bison: system=${bison_installed_version}, required=${BISON_VERSION}, path=${bison_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D bison_ROOT=$(realpath "${bison_prefix}") " -} - -# ------------------------------------------------------------------------------ -# Flex -# ------------------------------------------------------------------------------ -_install_flex() { - local flex_prefix=${PREFIX:-"/usr/local"} - local flex_bin=${flex_prefix}/bin/flex - local flex_installed_version="none" - if [[ -f ${flex_bin} ]]; then - flex_installed_version=$(${flex_bin} --version | awk '{print $2}') - elif _command_exists "flex" && [[ -z "${PREFIX}" ]]; then - flex_installed_version=$(flex --version | awk '{print $2}') - fi - - log "Checking Flex (System: ${flex_installed_version}, Required: ${FLEX_VERSION})" - if [[ "${flex_installed_version}" != "${FLEX_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Downloading Flex..." wget $OPT_NOCERT https://github.com/westes/flex/releases/download/v${FLEX_VERSION}/flex-${FLEX_VERSION}.tar.gz - _verify_checksum "${FLEX_CHECKSUM}" "flex-${FLEX_VERSION}.tar.gz" || error "Flex checksum failed." - _execute "Extracting Flex..." tar xf "flex-${FLEX_VERSION}.tar.gz" - cd "flex-${FLEX_VERSION}" - _execute "Configuring Flex..." ./configure --prefix="${flex_prefix}" - _execute "Building Flex..." make -j "${NUM_THREADS}" - _execute "Installing Flex..." make -j "${NUM_THREADS}" install - ) - INSTALL_SUMMARY+=("Flex: system=${flex_installed_version}, required=${FLEX_VERSION}, path=${flex_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Flex: system=${flex_installed_version}, required=${FLEX_VERSION}, path=${flex_prefix}, status=skipped") - fi -} - -# ------------------------------------------------------------------------------ -# SWIG -# ------------------------------------------------------------------------------ -_install_swig() { - local swig_prefix=${PREFIX:-"/usr/local"} - local swig_bin=${swig_prefix}/bin/swig - local swig_installed_version="none" - if [[ -f ${swig_bin} ]]; then - swig_installed_version=$(${swig_bin} -version | grep "SWIG Version" | awk '{print $3}') - elif _command_exists "swig" && [[ -z "${PREFIX}" ]]; then - swig_installed_version=$(swig -version | grep "SWIG Version" | awk '{print $3}') - fi - - log "Checking SWIG (System: ${swig_installed_version}, Required: ${SWIG_VERSION})" - if [[ "${swig_installed_version}" != "${SWIG_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - local tar_name="v${SWIG_VERSION}.tar.gz" - _execute "Downloading SWIG..." wget $OPT_NOCERT "https://github.com/swig/swig/archive/${tar_name}" - _verify_checksum "${SWIG_CHECKSUM}" "${tar_name}" || error "SWIG checksum failed." - _execute "Extracting SWIG..." tar xfz "${tar_name}" - cd swig-* - - _install_pcre - _execute "Generating SWIG configure script..." ./autogen.sh - _execute "Configuring SWIG..." ./configure --prefix="${swig_prefix}" - _execute "Building SWIG..." make -j "${NUM_THREADS}" - _execute "Installing SWIG..." make -j "${NUM_THREADS}" install - ) - INSTALL_SUMMARY+=("SWIG: system=${swig_installed_version}, required=${SWIG_VERSION}, path=${swig_prefix}, status=installed") - else - INSTALL_SUMMARY+=("SWIG: system=${swig_installed_version}, required=${SWIG_VERSION}, path=${swig_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D SWIG_ROOT=$(realpath "${swig_prefix}") " -} - -# ------------------------------------------------------------------------------ -# PCRE -# ------------------------------------------------------------------------------ -_install_pcre() { - local pcre_prefix=${PREFIX:-"/usr/local"} - local pcre_config=${pcre_prefix}/bin/pcre2-config - local pcre_installed_version="none" - - if [[ -f "${pcre_config}" ]]; then - pcre_installed_version=$(${pcre_config} --version) - elif _command_exists "pcre2-config" && [[ -z "${PREFIX}" ]]; then - pcre_installed_version=$(pcre2-config --version) - fi - - log "Checking PCRE (System: ${pcre_installed_version}, Required: ${PCRE_VERSION})" - if [[ "${pcre_installed_version}" == "${PCRE_VERSION}" ]]; then - INSTALL_SUMMARY+=("PCRE: system=${pcre_installed_version}, required=${PCRE_VERSION}, path=${pcre_prefix}, status=skipped") - return - fi - - ( - cd "${BASE_DIR}" - local pcre_tar_name="pcre2-${PCRE_VERSION}.tar.gz" - _execute "Downloading PCRE..." wget $OPT_NOCERT "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE_VERSION}/${pcre_tar_name}" - _verify_checksum "${PCRE_CHECKSUM}" "${pcre_tar_name}" || error "PCRE checksum failed." - _execute "Extracting PCRE..." tar xf "${pcre_tar_name}" - cd "pcre2-${PCRE_VERSION}" - _execute "Configuring PCRE..." ./configure --prefix="${pcre_prefix}" - _execute "Building PCRE..." make -j "${NUM_THREADS}" - _execute "Installing PCRE..." make -j "${NUM_THREADS}" install - ) - INSTALL_SUMMARY+=("PCRE: system=${pcre_installed_version}, required=${PCRE_VERSION}, path=${pcre_prefix}, status=installed") -} - - -# ------------------------------------------------------------------------------ -# Boost -# ------------------------------------------------------------------------------ -_install_boost() { - local boost_prefix=${PREFIX:-"/usr/local"} - local boost_installed_version="none" - if [[ -f "${boost_prefix}/include/boost/version.hpp" ]]; then - boost_installed_version=$(grep "^#define BOOST_LIB_VERSION" "${boost_prefix}/include/boost/version.hpp" | sed -e 's/.*"\(.*\)"/\1/' -e 's/_/./g') - fi - - local required_version="${BOOST_VERSION_BIG}" - log "Checking Boost (System: ${boost_installed_version}, Required: ${required_version})" - if [[ "${boost_installed_version}" != "${required_version}" ]]; then - ( - cd "${BASE_DIR}" - local boost_version_underscore=${BOOST_VERSION_SMALL//./_} - _execute "Downloading Boost..." wget $OPT_NOCERT "https://archives.boost.io/release/${BOOST_VERSION_SMALL}/source/boost_${boost_version_underscore}.tar.gz" - _verify_checksum "${BOOST_CHECKSUM}" "boost_${boost_version_underscore}.tar.gz" || error "Boost checksum failed." - _execute "Extracting Boost..." tar -xf "boost_${boost_version_underscore}.tar.gz" - cd "boost_${boost_version_underscore}" - _execute "Bootstrapping Boost..." ./bootstrap.sh --prefix="${boost_prefix}" - _execute "Installing Boost..." ./b2 install --with-iostreams --with-test --with-serialization --with-system --with-thread -j "${NUM_THREADS}" - ) - INSTALL_SUMMARY+=("Boost: system=${boost_installed_version}, required=${required_version}, path=${boost_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Boost: system=${boost_installed_version}, required=${required_version}, path=${boost_prefix}, status=skipped") - fi - - local boost_cmake_dir="" - if [[ -d "${boost_prefix}/lib/cmake/Boost-${BOOST_VERSION_SMALL}" ]]; then - boost_cmake_dir="${boost_prefix}/lib/cmake/Boost-${BOOST_VERSION_SMALL}" - elif [[ -d "${boost_prefix}/lib64/cmake/Boost-${BOOST_VERSION_SMALL}" ]]; then - boost_cmake_dir="${boost_prefix}/lib64/cmake/Boost-${BOOST_VERSION_SMALL}" - fi - - if [[ -n "${boost_cmake_dir}" ]]; then - CMAKE_PACKAGE_ROOT_ARGS+=" -D Boost_DIR=$(realpath "${boost_cmake_dir}") " - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D Boost_ROOT=$(realpath "${boost_prefix}") " -} - -# ------------------------------------------------------------------------------ -# Eigen -# ------------------------------------------------------------------------------ -_install_eigen() { - local eigen_prefix=${PREFIX:-"/usr/local"} - local eigen_version_file="${eigen_prefix}/include/eigen3/Eigen/src/Core/util/Macros.h" - local eigen_installed_version="none" - - if [[ -f "${eigen_version_file}" ]]; then - local world - world=$(grep "#define EIGEN_WORLD_VERSION" "${eigen_version_file}" | awk '{print $3}') - local major - major=$(grep "#define EIGEN_MAJOR_VERSION" "${eigen_version_file}" | awk '{print $3}') - eigen_installed_version="${world}.${major}" - fi - - log "Checking Eigen (System: ${eigen_installed_version}, Required: ${EIGEN_VERSION})" - if [[ "${eigen_installed_version}" != "${EIGEN_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning Eigen..." git clone --depth=1 -b "${EIGEN_VERSION}" https://gitlab.com/libeigen/eigen.git - cd eigen - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring Eigen..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${eigen_prefix}" -B build . - _execute "Building and installing Eigen..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install - ) - INSTALL_SUMMARY+=("Eigen: system=${eigen_installed_version}, required=${EIGEN_VERSION}, path=${eigen_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Eigen: system=${eigen_installed_version}, required=${EIGEN_VERSION}, path=${eigen_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D Eigen3_ROOT=$(realpath "${eigen_prefix}") " -} - -# ------------------------------------------------------------------------------ -# CUDD -# ------------------------------------------------------------------------------ -_install_cudd() { - local cudd_prefix=${PREFIX:-"/usr/local"} - log "Checking CUDD (Required: ${CUDD_VERSION})" - if [[ ! -f ${cudd_prefix}/include/cudd.h ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning CUDD..." git clone --depth=1 -b "${CUDD_VERSION}" https://github.com/The-OpenROAD-Project/cudd.git - cd cudd - _execute "Generating CUDD configure script..." autoreconf - _execute "Configuring CUDD..." ./configure --prefix="${cudd_prefix}" - _execute "Building and installing CUDD..." make -j "${NUM_THREADS}" install - ) - INSTALL_SUMMARY+=("CUDD: system=none, required=${CUDD_VERSION}, path=${cudd_prefix}, status=installed") - else - INSTALL_SUMMARY+=("CUDD: system=found, required=${CUDD_VERSION}, path=${cudd_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D cudd_ROOT=$(realpath "${cudd_prefix}") " -} - -# ------------------------------------------------------------------------------ -# CUSP -# ------------------------------------------------------------------------------ -_install_cusp() { - local cusp_prefix=${PREFIX:-"/usr/local/include"} - log "Checking CUSP" - if [[ ! -f ${cusp_prefix}/cusp/version.h ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning CUSP..." git clone --depth=1 -b cuda9 https://github.com/cusplibrary/cusplibrary.git - cd cusplibrary - _execute "Installing CUSP..." cp -r ./cusp "${cusp_prefix}" - ) - INSTALL_SUMMARY+=("CUSP: system=none, required=any, path=${cusp_prefix}, status=installed") - else - INSTALL_SUMMARY+=("CUSP: system=found, required=any, path=${cusp_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D cusp_ROOT=$(realpath "${cusp_prefix}") " -} - -# ------------------------------------------------------------------------------ -# Lemon -# ------------------------------------------------------------------------------ -_install_lemon() { - local lemon_prefix=${PREFIX:-"/usr/local"} - local lemon_installed_version="none" - if [[ -f "${lemon_prefix}/include/lemon/config.h" ]]; then - lemon_installed_version=$(grep "LEMON_VERSION" "${lemon_prefix}/include/lemon/config.h" | awk -F'"' '{print $2}') - fi - - log "Checking Lemon (System: ${lemon_installed_version}, Required: ${LEMON_VERSION})" - if [[ "${lemon_installed_version}" != "${LEMON_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning Lemon..." git clone --depth=1 -b "${LEMON_VERSION}" https://github.com/The-OpenROAD-Project/lemon-graph.git - cd lemon-graph - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring Lemon..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${lemon_prefix}" -B build . - _execute "Building and installing Lemon..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install - ) - INSTALL_SUMMARY+=("Lemon: system=${lemon_installed_version}, required=${LEMON_VERSION}, path=${lemon_prefix}, status=installed") - else - INSTALL_SUMMARY+=("Lemon: system=${lemon_installed_version}, required=${LEMON_VERSION}, path=${lemon_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D LEMON_ROOT=$(realpath "${lemon_prefix}") " -} - -# ------------------------------------------------------------------------------ -# spdlog -# ------------------------------------------------------------------------------ -_install_spdlog() { - local spdlog_prefix=${PREFIX:-"/usr/local"} - local spdlog_installed_version="none" - if [ -d "${spdlog_prefix}/include/spdlog" ]; then - spdlog_installed_version=$(grep "#define SPDLOG_VER_" "${spdlog_prefix}/include/spdlog/version.h" | sed 's/.*\s//' | tr '\n' '.' | sed 's/\.$//') - fi - log "Checking spdlog (System: ${spdlog_installed_version}, Required: ${SPDLOG_VERSION})" - if [[ "${spdlog_installed_version}" != "${SPDLOG_VERSION}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Cloning spdlog..." git clone --depth=1 -b "v${SPDLOG_VERSION}" https://github.com/gabime/spdlog.git - cd spdlog - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring spdlog..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${spdlog_prefix}" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DSPDLOG_BUILD_EXAMPLE=OFF -B build . - _execute "Building and installing spdlog..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install - ) - INSTALL_SUMMARY+=("spdlog: system=${spdlog_installed_version}, required=${SPDLOG_VERSION}, path=${spdlog_prefix}, status=installed") - else - INSTALL_SUMMARY+=("spdlog: system=${spdlog_installed_version}, required=${SPDLOG_VERSION}, path=${spdlog_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D spdlog_ROOT=$(realpath "${spdlog_prefix}") " -} - -# ------------------------------------------------------------------------------ -# gtest -# ------------------------------------------------------------------------------ -_install_gtest() { - local gtest_prefix=${PREFIX:-"/usr/local"} - log "Checking gtest (Required: ${GTEST_VERSION})" - if [[ ! -d ${gtest_prefix}/include/gtest ]]; then - ( - cd "${BASE_DIR}" - _execute "Downloading gtest..." wget $OPT_NOCERT "https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.zip" - _verify_checksum "${GTEST_CHECKSUM}" "v${GTEST_VERSION}.zip" || error "gtest checksum failed." - _execute "Extracting gtest..." unzip "v${GTEST_VERSION}.zip" - cd "googletest-${GTEST_VERSION}" - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring gtest..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${gtest_prefix}" -B build . - _execute "Building and installing gtest..." "${cmake_bin}" --build build --target install - ) - INSTALL_SUMMARY+=("gtest: system=none, required=${GTEST_VERSION}, path=${gtest_prefix}, status=installed") - else - INSTALL_SUMMARY+=("gtest: system=found, required=${GTEST_VERSION}, path=${gtest_prefix}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D GTest_ROOT=$(realpath "${gtest_prefix}") " -} - -# ------------------------------------------------------------------------------ -# Abseil -# ------------------------------------------------------------------------------ -_install_abseil() { - local absl_prefix_install=${PREFIX:-"/usr/local"} - local absl_prefix_found="" - local absl_version_file="" - - # Check in default/user-specified prefix first - local absl_version_file_default="${absl_prefix_install}/lib/cmake/absl/abslConfigVersion.cmake" - if [[ -f "${absl_version_file_default}" ]]; then - absl_prefix_found="${absl_prefix_install}" - absl_version_file="${absl_version_file_default}" - fi - - # If not found, check in or-tools path - if [[ -z "${absl_prefix_found}" && -n "${OR_TOOLS_PATH}" ]]; then - local absl_version_file_or_tools="${OR_TOOLS_PATH}/lib/cmake/absl/abslConfigVersion.cmake" - if [[ -f "${absl_version_file_or_tools}" ]]; then - absl_prefix_found="${OR_TOOLS_PATH}" - absl_version_file="${absl_version_file_or_tools}" - fi - fi - - local absl_installed_version="none" - if [[ -n "${absl_version_file}" ]]; then - absl_installed_version=$(grep '^set(PACKAGE_VERSION "' "${absl_version_file}" | head -n 1 | awk -F'"' '{print $2}') - fi - - local required_version="${ABSL_VERSION%.*}" - log "Checking Abseil (System: ${absl_installed_version}, Required: ${required_version})" - if [[ "${absl_installed_version}" != "${required_version}" ]]; then - ( - cd "${BASE_DIR}" - _execute "Downloading Abseil..." wget $OPT_NOCERT "https://github.com/abseil/abseil-cpp/releases/download/${ABSL_VERSION}/abseil-cpp-${ABSL_VERSION}.tar.gz" - _verify_checksum "${ABSL_CHECKSUM}" "abseil-cpp-${ABSL_VERSION}.tar.gz" || error "Abseil checksum failed." - _execute "Extracting Abseil..." tar xf "abseil-cpp-${ABSL_VERSION}.tar.gz" - cd "abseil-cpp-${ABSL_VERSION}" - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring Abseil..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${absl_prefix_install}" -DCMAKE_CXX_STANDARD=17 -B build . - _execute "Building and installing Abseil..." "${cmake_bin}" --build build --target install - ) - absl_prefix_found="${absl_prefix_install}" - INSTALL_SUMMARY+=("Abseil: system=${absl_installed_version}, required=${required_version}, path=${absl_prefix_found}, status=installed") - else - INSTALL_SUMMARY+=("Abseil: system=${absl_installed_version}, required=${required_version}, path=${absl_prefix_found}, status=skipped") - fi - CMAKE_PACKAGE_ROOT_ARGS+=" -D ABSL_ROOT=$(realpath "${absl_prefix_found}") " -} - -_install_or_tools() { - local os=$1 - local os_version=$2 - local arch=$3 - local skip_system_or_tools=$4 - - # Create a temporary directory for downloads - local build_dir - build_dir=$(mktemp -d) - - local or_tools_installed_version="none" - # Check if a system-installed version of OR-Tools is present - log "Checking or-tools (System: ${or_tools_installed_version}, Required: ${OR_TOOLS_VERSION_SMALL})" - if [[ "${skip_system_or_tools}" == "false" ]]; then - # Disable exit on error for 'find' command, as it might return non zero - set +euo pipefail - local existing_libs - local search_paths="" - if [[ -n "${PREFIX}" ]]; then - search_paths="${OR_TOOLS_PATH}" - else - search_paths="/usr/local /usr /opt" - fi - existing_libs=$(find ${search_paths} -type f -name "libortools.so.*" 2>/dev/null) - # Bring back exit on error - set -euo pipefail - if [[ -n "${existing_libs}" ]]; then - local first_lib="${existing_libs%%$'\n'*}" - or_tools_installed_version=$(basename "${first_lib}" | sed 's/libortools.so.//') - local or_tools_root - or_tools_root=$(dirname "${first_lib}") - local or_tools_install_dir - or_tools_install_dir=$(realpath "${or_tools_root}/..") - - if [[ "${or_tools_installed_version}" == "${OR_TOOLS_VERSION_SMALL}" ]]; then - CMAKE_PACKAGE_ROOT_ARGS+=" -D ortools_ROOT=${or_tools_install_dir} " - OR_TOOLS_PATH=${or_tools_install_dir} - INSTALL_SUMMARY+=("or-tools: system=${or_tools_installed_version}, required=${OR_TOOLS_VERSION_SMALL}, path=${OR_TOOLS_PATH}, status=skipped") - return - else - log "Found old OR-Tools version ${or_tools_installed_version}. Removing it." - rm -rf "${or_tools_install_dir}" - fi - fi - fi - - if [[ "$(uname -m)" == "aarch64" ]]; then - ( - cd "${build_dir}" - _execute "Cloning or-tools..." git clone --depth=1 -b "v${OR_TOOLS_VERSION_BIG}" https://github.com/google/or-tools.git - cd or-tools - local cmake_bin=${PREFIX:-/usr/local}/bin/cmake - _execute "Configuring or-tools..." "${cmake_bin}" -S. -Bbuild -DBUILD_DEPS:BOOL=ON -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_SAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DCMAKE_INSTALL_PREFIX="${OR_TOOLS_PATH}" -DCMAKE_CXX_FLAGS="-w" -DCMAKE_C_FLAGS="-w" - _execute "Building and installing or-tools..." "${cmake_bin}" --build build --config Release --target install -v -j "${NUM_THREADS}" - ) - else - ( - cd "${build_dir}" - if [[ "${os_version}" == "rodete" ]]; then - os_version=11 - fi - local or_tools_file="or-tools_${arch}_${os}-${os_version}_cpp_v${OR_TOOLS_VERSION_SMALL}.tar.gz" - _execute "Downloading or-tools..." wget $OPT_NOCERT "https://github.com/google/or-tools/releases/download/v${OR_TOOLS_VERSION_BIG}/${or_tools_file}" - mkdir -p "${OR_TOOLS_PATH}" - _execute "Extracting or-tools..." tar --strip 1 --dir "${OR_TOOLS_PATH}" -xf "${or_tools_file}" - ) - fi - INSTALL_SUMMARY+=("or-tools: system=${or_tools_installed_version}, required=${OR_TOOLS_VERSION_SMALL}, path=${OR_TOOLS_PATH}, status=installed") - - CMAKE_PACKAGE_ROOT_ARGS+=" -D ortools_ROOT=$(realpath "${OR_TOOLS_PATH}") " - rm -rf "${build_dir}" -} -# ============================================================================== -# Dependency Installation Modules -# ============================================================================== -# Each dependency will have its own dedicated function for installation and -# version management. This modular approach makes the script easier to -# maintain and extend. -# ------------------------------------------------------------------------------ -# Bazel -# ------------------------------------------------------------------------------ -_install_bazel() { - local bazel_prefix=${PREFIX:-"/usr/local"} - log "Checking Bazel (via bazelisk)" - if _command_exists "bazelisk"; then - log "bazelisk already installed, skipping." - INSTALL_SUMMARY+=("Bazel: system=found, required=any, status=skipped") - return - fi - if [[ "$OSTYPE" == "darwin"* ]]; then - _execute "Installing bazelisk via Homebrew..." brew install bazelisk - else - local arch - arch=$(uname -m) - local bazelisk_arch="amd64" - if [[ "${arch}" == "aarch64" ]]; then - bazelisk_arch="arm64" - fi - local bazelisk_checksum="${BAZELISK_CHECKSUM_AMD64}" - if [[ "${bazelisk_arch}" == "arm64" ]]; then - bazelisk_checksum="${BAZELISK_CHECKSUM_ARM64}" - fi - ( - cd "${BASE_DIR}" - _execute "Downloading bazelisk v${BAZELISK_VERSION}..." curl -Lo bazelisk \ - "https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VERSION}/bazelisk-linux-${bazelisk_arch}" - _verify_checksum "${bazelisk_checksum}" "bazelisk" || error "Bazelisk checksum failed." - chmod +x bazelisk - _execute "Installing bazelisk..." mv bazelisk "${bazel_prefix}/bin/bazelisk" - ) - if [[ "${NO_GUI}" != "yes" ]]; then - # Install xcb libraries needed for GUI support with Bazel builds - if _command_exists "apt-get"; then - _execute "Installing xcb libraries for GUI support..." \ - apt-get -y install --no-install-recommends \ - libxcb1-dev libxcb-util-dev libxcb-icccm4-dev libxcb-image0-dev \ - libxcb-keysyms1-dev libxcb-randr0-dev libxcb-render-util0-dev \ - libxcb-xinerama0-dev libxcb-xkb-dev - elif _command_exists "yum"; then - _execute "Installing xcb libraries for GUI support..." \ - yum install -y \ - libxcb-devel xcb-util-devel xcb-util-image-devel \ - xcb-util-keysyms-devel xcb-util-renderutil-devel xcb-util-wm-devel - fi - fi - fi - INSTALL_SUMMARY+=("Bazel: system=none, required=latest, status=installed") -} - -# ------------------------------------------------------------------------------ -# Bazel Dev Tools (buildifier, etc.) -# ------------------------------------------------------------------------------ -_install_bazel_dev() { - local bazel_prefix=${PREFIX:-"/usr/local"} - log "Checking Bazel dev tools (buildifier)" - if _command_exists "buildifier"; then - log "buildifier already installed, skipping." - INSTALL_SUMMARY+=("buildifier: system=found, required=any, status=skipped") - return - fi - if [[ "$OSTYPE" == "darwin"* ]]; then - _execute "Installing buildifier via Homebrew..." brew install buildifier - else - local arch - arch=$(uname -m) - local buildifier_arch="amd64" - if [[ "${arch}" == "aarch64" ]]; then - buildifier_arch="arm64" - fi - local buildifier_checksum="${BUILDIFIER_CHECKSUM_AMD64}" - if [[ "${buildifier_arch}" == "arm64" ]]; then - buildifier_checksum="${BUILDIFIER_CHECKSUM_ARM64}" - fi - ( - cd "${BASE_DIR}" - _execute "Downloading buildifier v${BUILDIFIER_VERSION}..." curl -Lo buildifier \ - "https://github.com/bazelbuild/buildtools/releases/download/v${BUILDIFIER_VERSION}/buildifier-linux-${buildifier_arch}" - _verify_checksum "${buildifier_checksum}" "buildifier" || error "Buildifier checksum failed." - chmod +x buildifier - _execute "Installing buildifier..." mv buildifier "${bazel_prefix}/bin/buildifier" - ) - fi - INSTALL_SUMMARY+=("buildifier: system=none, required=latest, status=installed") -} - -_install_common_dev() { - log "Install common development dependencies (-common or -all)" - rm -rf "${BASE_DIR}" - mkdir -p "${BASE_DIR}" - if [[ -n "${PREFIX}" ]]; then - mkdir -p "${PREFIX}" - fi - - _install_cmake - _install_bison - _install_flex - _install_pcre - _install_swig - _install_boost - _install_eigen - _install_cudd - _install_cusp - _install_lemon - _install_spdlog - _install_gtest - - if [[ "${EQUIVALENCE_DEPS}" == "yes" ]]; then - _install_equivalence_deps - fi - - if [[ -n ${PREFIX} ]]; then - # Emit an environment setup script - cat > "${PREFIX}/env.sh" < 4 {print \$3}' | grep -v Name | xargs -r zypper -n remove --clean-deps" -} - -# ------------------------------------------------------------------------------ -# Darwin (macOS) -# ------------------------------------------------------------------------------ -_install_darwin_packages() { - if ! _command_exists "brew"; then - error "Homebrew is not found. Please install Homebrew before continuing." - fi - if ! xcode-select -p &> /dev/null; then - cat < /dev/null' - _execute "Updating package lists for Docker..." apt-get -y update - _execute "Installing Docker..." apt-get -y install --no-install-recommends docker-ce docker-ce-cli containerd.io docker-buildx-plugin - - if _version_compare "${1}" -lt "24.04"; then - _execute "Downloading LLVM install script..." wget $OPT_NOCERT https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - _execute "Installing LLVM 16..." ./llvm.sh 16 all - fi -} -_help() { - cat < Limit the number of compiling threads. - -yosys-ver= Specify a custom Yosys version. Used for ORFS. - -verbose Show all output from build commands. - -h, -help Show this help message. - -EOF - exit "${1:-1}" -} - -main() { - local option="none" - while [ "$#" -gt 0 ]; do - case "${1}" in - -h|-help) _help 0 ;; - -all) option="all" ;; - -base) option="base" ;; - -common) option="common" ;; - -eqy) EQUIVALENCE_DEPS="yes" ;; - -bazel) INSTALL_BAZEL="yes" ;; - -bazel-dev) INSTALL_BAZEL_DEV="yes" ;; - -no-gui) NO_GUI="yes" ;; - -ci) CI="yes" ;; - -verbose) VERBOSE_MODE="yes" ;; - -local) - if [[ $(id -u) == 0 ]]; then - error "Cannot use -local with root or sudo." - fi - if [[ -n "${PREFIX}" ]]; then - warn "Previous -prefix argument will be overwritten with -local." - fi - PREFIX="${HOME}/.local" - ;; - -constant-build-dir) - if [[ -d "${BASE_DIR}" ]]; then - log "Removing old building directory ${BASE_DIR}" - rm -r "${BASE_DIR}" - fi - BASE_DIR="/tmp/DependencyInstaller-OpenROAD" - mkdir -p "${BASE_DIR}" - ;; - -prefix=*) - if [[ -n "${PREFIX}" ]]; then - warn "Previous -local argument will be overwritten with -prefix." - fi - PREFIX="${1#*=}" - if [[ ! "${PREFIX}" = /* ]]; then - PREFIX="$(pwd)/${PREFIX}" - fi - ;; - -nocert) - warn "Security certificates for downloaded packages will not be checked." - OPT_NOCERT="--no-check-certificate" - export GIT_SSL_NO_VERIFY=true - ;; - -skip-system-or-tools) SKIP_SYSTEM_OR_TOOLS="true" ;; - -save-deps-prefixes=*) SAVE_DEPS_PREFIXES="$(realpath "${1#*=}")" ;; - -threads=*) NUM_THREADS="${1#*=}" ;; - -yosys-ver=*) YOSYS_VERSION="${1#*=}" ;; - *) - echo "Unknown option: ${1}" >&2 - _help - ;; - esac - shift 1 - done - - if [[ "${option}" == "none" && "${INSTALL_BAZEL}" == "no" && "${INSTALL_BAZEL_DEV}" == "no" ]]; then - error "You must use one of: -all, -base, -common, -bazel, or -bazel-dev." - fi - - # -bazel-dev implies -bazel (you need bazelisk to use buildifier) - if [[ "${INSTALL_BAZEL}" == "yes" || "${INSTALL_BAZEL_DEV}" == "yes" ]]; then - _install_bazel - fi - - if [[ "${INSTALL_BAZEL_DEV}" == "yes" ]]; then - _install_bazel_dev - fi - - if [[ "${option}" == "none" ]]; then - _print_summary - rm -rf "${BASE_DIR}" - return - fi - - OR_TOOLS_PATH=${PREFIX:-"/opt/or-tools"} - - if [[ -z "${SAVE_DEPS_PREFIXES}" ]]; then - local dir - dir="$(dirname "$(readlink -f "$0")")" - SAVE_DEPS_PREFIXES="${dir}/openroad_deps_prefixes.txt" - fi - - local platform - platform="$(uname -s)" - case "${platform}" in - "Linux") - if [[ ! -f /etc/os-release ]]; then - error "Unidentified OS, could not find /etc/os-release." - fi - local os - os=$(awk -F= '/^NAME/{print $2}' /etc/os-release | sed 's/"//g') - ;; - "Darwin") - if [[ $(id -u) == 0 ]]; then - error "Cannot install on macOS with root or sudo." - fi - os="Darwin" - ;; - *) - error "${platform} is not supported. We only officially support Linux at the moment." - ;; - esac - - case "${os}" in - "Ubuntu") - local ubuntu_version - ubuntu_version=$(awk -F= '/^VERSION_ID/{print $2}' /etc/os-release | sed 's/"//g') - if [[ "${option}" == "base" || "${option}" == "all" ]]; then - _install_ubuntu_packages "${ubuntu_version}" - fi - if [[ "${CI}" == "yes" ]]; then - _install_ci_packages "${ubuntu_version}" - fi - if [[ "${option}" == "common" || "${option}" == "all" ]]; then - _install_common_dev - local ubuntu_version_normalized=${ubuntu_version} - if _version_compare "${ubuntu_version_normalized}" -ge "25.04"; then - # FIXME make do with or-tools for 24.10 until an official release for 25.04 is available - ubuntu_version_normalized="24.10" - elif _version_compare "${ubuntu_version_normalized}" -ge "24.04"; then - ubuntu_version_normalized="24.04" - elif _version_compare "${ubuntu_version_normalized}" -ge "22.04"; then - ubuntu_version_normalized="22.04" - else - ubuntu_version_normalized="20.04" - fi - _install_or_tools "ubuntu" "${ubuntu_version_normalized}" "amd64" "${SKIP_SYSTEM_OR_TOOLS}" - _install_abseil - fi - ;; - "Red Hat Enterprise Linux" | "Rocky Linux" | "AlmaLinux") - local rhel_version - if [[ "${os}" == "Red Hat Enterprise Linux" ]]; then - rhel_version=$(rpm -q --queryformat '%{VERSION}' redhat-release | cut -d. -f1) - elif [[ "${os}" == "Rocky Linux" ]]; then - rhel_version=$(rpm -q --queryformat '%{VERSION}' rocky-release | cut -d. -f1) - elif [[ "${os}" == "AlmaLinux" ]]; then - rhel_version=$(rpm -q --queryformat '%{VERSION}' almalinux-release | cut -d. -f1) - fi - if [[ "${rhel_version}" != "8" && "${rhel_version}" != "9" ]]; then - error "Unsupported ${rhel_version} version. Versions '8' and '9' are supported." - fi - if [[ "${option}" == "base" || "${option}" == "all" ]]; then - _install_rhel_packages "${rhel_version}" - fi - if [[ "${option}" == "common" || "${option}" == "all" ]]; then - _install_common_dev - local os_id - os_id=$(awk -F= '/^ID/{print $2}' /etc/os-release | sed 's/"//g') - local arch - arch=$(uname -m) - local or_tools_arch=${arch} - local or_tools_distro="" - local or_tools_version="" - if [[ "${rhel_version}" == "8" ]]; then - or_tools_distro="AlmaLinux" - or_tools_version="8.10" - if [[ "${os_id}" != "almalinux" ]]; then - warn "Using AlmaLinux or-tools package for RHEL 8 compatible system." - fi - elif [[ "${rhel_version}" == "9" ]]; then - or_tools_version="9" - if [[ "${arch}" == "x86_64" ]]; then - or_tools_arch="amd64" - fi - if [[ "${os_id}" == "almalinux" || "${os_id}" == "rocky" ]]; then - or_tools_distro="${os_id}" - else - or_tools_distro="rockylinux" - warn "Defaulting to rockylinux or-tools package for RHEL 9 compatible system." - fi - fi - _install_or_tools "${or_tools_distro}" "${or_tools_version}" "${or_tools_arch}" "${SKIP_SYSTEM_OR_TOOLS}" - _install_abseil - fi - ;; - "Darwin") - _install_darwin_packages - cat < "${SAVE_DEPS_PREFIXES}" - if [[ $(id -u) == 0 && -n "${SUDO_USER+x}" ]]; then - chown "${SUDO_USER}:$(id -gn "${SUDO_USER}")" "${SAVE_DEPS_PREFIXES}" 2>/dev/null || true - fi - fi - - _print_summary - rm -rf "${BASE_DIR}" -} - -_print_summary() { - if [ ${#INSTALL_SUMMARY[@]} -eq 0 ]; then - return - fi - echo "" - log "Installation Summary" - echo "${BOLD}=============================================================================================${NC}" - printf "%-15s | %-25s | %-15s | %-15s | %-10s\n" "Package" "Path" "Found" "Required" "Status" - printf "%-15s | %-25s | %-15s | %-15s | %-10s\n" "---------------" "-------------------------" "---------------" "---------------" "----------" - for summary_line in "${INSTALL_SUMMARY[@]}"; do - # summary_line is like "Flex: system=2.6.4, required=2.6.4, path=/usr/local, status=skipped" - local package - package=$(echo "$summary_line" | cut -d':' -f1) - local system_version - system_version=$(echo "$summary_line" | sed -n 's/.*system=\([^,]*\).*/\1/p') - local required_version - required_version=$(echo "$summary_line" | sed -n 's/.*required=\([^,]*\).*/\1/p') - local path - path=$(echo "$summary_line" | sed -n 's/.*path=\([^,]*\).*/\1/p') - local truncated_path - truncated_path=$(_truncate_path "$path" 25) - local status - status=$(echo "$summary_line" | sed -n 's/.*status=\([^,]*\).*/\1/p') - local status_color="" - if [[ "${status}" == "installed" ]]; then - status_color="${GREEN}" - elif [[ "${status}" == "skipped" ]]; then - status_color="${YELLOW}" - fi - printf "%-15s | %-25s | %-15s | %-15s | ${status_color}%-10s${NC}\n" "$package" "$truncated_path" "$system_version" "$required_version" "$status" - done - echo "${BOLD}=============================================================================================${NC}" -} - -main "$@" From e36b4a9c5120456e03fe6efee4c85e98e2bf4450 Mon Sep 17 00:00:00 2001 From: Aditya Pagare <132090983+AdityaPagare619@users.noreply.github.com> Date: Tue, 12 May 2026 15:17:43 +0530 Subject: [PATCH 2/4] fix: pin GitHub Actions to commit SHAs for supply chain integrity All third-party GitHub Actions referenced by @major or @major.minor tags are now pinned to their current commit SHA with version comments. The tj-actions/changed-files exploit (March 2025) demonstrated that mutable tags allow silent malicious code injection across all workflows. Third-party actions pinned: - actions/checkout@v6 -> de0fac2e (v6) - tj-actions/changed-files@v47 -> 24d32ff (v47) - actions/cache/restore@v5 -> 27d5ce7 (v5) - actions/cache/save@v5 -> 27d5ce7 (v5) - maxim-lobanov/setup-xcode@v1 -> 1242409 (v1) Own-org actions (The-OpenROAD-Project/*) use @main/@master tags - these should ideally be pinned too but need coordination with the internal actions team. Files: .github/workflows/*.yml --- .github/workflows/github-actions-format-on-push.yml | 4 ++-- .github/workflows/github-actions-macos-bazel.yml | 8 ++++---- .github/workflows/github-actions-macos.yml | 6 +++--- .github/workflows/github-actions-on-push.yml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/github-actions-format-on-push.yml b/.github/workflows/github-actions-format-on-push.yml index 966427d5439..26ca2a2803c 100644 --- a/.github/workflows/github-actions-format-on-push.yml +++ b/.github/workflows/github-actions-format-on-push.yml @@ -13,12 +13,12 @@ jobs: runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }} steps: - name: Check out repository code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 - name: Get changed files id: changed-files - uses: tj-actions/changed-files@v47 + uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47 - name: Check format of cpp changed files run: | clang-format --version diff --git a/.github/workflows/github-actions-macos-bazel.yml b/.github/workflows/github-actions-macos-bazel.yml index 926ab3a7c15..0120bd0daae 100644 --- a/.github/workflows/github-actions-macos-bazel.yml +++ b/.github/workflows/github-actions-macos-bazel.yml @@ -12,18 +12,18 @@ jobs: runs-on: macos-latest steps: - name: Setup xcode - uses: maxim-lobanov/setup-xcode@v1 + uses: maxim-lobanov/setup-xcode@1242409711ff5721add51979e9e11e23ebb7e5a4 # v1 with: xcode-version: latest-stable - name: Check out repository code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: submodules: 'recursive' # 1. RESTORE: All jobs (PRs, manual runs, master) get to read the cache - name: Restore Bazel Disk Cache - uses: actions/cache/restore@v5 + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: ~/.cache/bazel-disk-cache key: ${{ runner.os }}-bazel-${{ github.sha }} @@ -43,7 +43,7 @@ jobs: # 2. SAVE: Only executes if this is a push/merge directly to the master branch - name: Save Bazel Disk Cache if: github.ref == 'refs/heads/master' && github.event_name == 'push' - uses: actions/cache/save@v5 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: ~/.cache/bazel-disk-cache key: ${{ runner.os }}-bazel-${{ github.sha }} \ No newline at end of file diff --git a/.github/workflows/github-actions-macos.yml b/.github/workflows/github-actions-macos.yml index 0638239332e..9955bb5a76f 100644 --- a/.github/workflows/github-actions-macos.yml +++ b/.github/workflows/github-actions-macos.yml @@ -11,11 +11,11 @@ jobs: runs-on: macos-latest steps: - name: Setup xcode - uses: maxim-lobanov/setup-xcode@v1 + uses: maxim-lobanov/setup-xcode@1242409711ff5721add51979e9e11e23ebb7e5a4 # v1 with: xcode-version: latest-stable - name: Check out repository code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: submodules: 'recursive' - name: Install dependencies @@ -47,7 +47,7 @@ jobs: rm -rf "${{ github.workspace }}" mkdir -p "${{ github.workspace }}" - name: Check out repository code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: submodules: 'recursive' - name: Build OpenROAD diff --git a/.github/workflows/github-actions-on-push.yml b/.github/workflows/github-actions-on-push.yml index 2452422aa78..740e244731c 100644 --- a/.github/workflows/github-actions-on-push.yml +++ b/.github/workflows/github-actions-on-push.yml @@ -11,6 +11,6 @@ jobs: runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }} steps: - name: Check out repository code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: run security_scan_on_push uses: The-OpenROAD-Project/actions/security_scan_on_push@main From f3637fbe8ce9925b174bb5c4fa719926cd94c0f4 Mon Sep 17 00:00:00 2001 From: Aditya Pagare <132090983+AdityaPagare619@users.noreply.github.com> Date: Tue, 12 May 2026 16:45:43 +0530 Subject: [PATCH 3/4] fix: replace MD5 with SHA-256 in checksum verification (complete file) FIXES V1 ISSUE: Previous commit pushed a truncated file (158 lines instead of 1400+). This commit contains the FULL script with only _verify_checksum() changed from md5sum to sha256sum. Note: checksum constant values are still MD5 hashes (32-char) and will need regeneration to 64-char SHA-256 hashes. A maintainer should regenerate by downloading each dependency and running sha256sum. File: etc/DependencyInstaller.sh (1402 lines, 1 line changed) --- etc/DependencyInstaller.sh | 974 ++++++++++++++++++++++++++++++++++++- 1 file changed, 965 insertions(+), 9 deletions(-) mode change 100755 => 100644 etc/DependencyInstaller.sh diff --git a/etc/DependencyInstaller.sh b/etc/DependencyInstaller.sh old mode 100755 new mode 100644 index 4407b1e3382..d158f1e9182 --- a/etc/DependencyInstaller.sh +++ b/etc/DependencyInstaller.sh @@ -45,10 +45,11 @@ fi # ------------------------------------------------------------------------------ # Dependency Versions and Checksums # ------------------------------------------------------------------------------ -# NOTE: These checksums were originally generated with MD5. After switching to -# SHA-256 (see _verify_checksum below), the actual hash values must be -# regenerated. To regenerate: download each file, run sha256sum on it, and -# replace the corresponding value below. +# NOTE: These checksum values were generated with MD5 (32 hex characters). +# After the switch from md5sum to sha256sum below, a maintainer must +# regenerate each value by downloading the dependency and running: +# sha256sum +# Then replace the corresponding *_CHECKSUM value with the 64-char result. YOSYS_VERSION="v0.58" CMAKE_VERSION_BIG="3.31" CMAKE_VERSION_SMALL="${CMAKE_VERSION_BIG}.9" @@ -125,7 +126,7 @@ _version_compare() { error "Invalid operator in _version_compare: $2" ;; esac - awk -v v1="$1" -v v2="$3" 'BEGIN { exit !(v1 '"$op"' v2) }' + awk -v v1="$1" -v v2="$3" 'BEGIN { exit !(v1 '"'"'$op'"'"' v2) }' } # ------------------------------------------------------------------------------ @@ -158,9 +159,964 @@ _truncate_path() { _verify_checksum() { local checksum=$1 local filename=$2 - # MD5 is cryptographically broken (CMU SEI 2008, NIST non-approved). - # SHA-256 replaces MD5 for supply chain integrity. - # NOTE: The checksum values defined above were generated with MD5 and - # must be re-generated with sha256sum after downloading each dependency. + # CHANGED: MD5 → SHA-256 for supply chain integrity. + # Checksum values above still need regeneration. _execute "Verifying ${filename} checksum..." bash -c "echo '${checksum} ${filename}' | sha256sum --quiet -c -" } + +# ------------------------------------------------------------------------------ +# Yosys +# ------------------------------------------------------------------------------ +_install_yosys() { + local yosys_prefix=${PREFIX:-"/usr/local"} + local yosys_bin=${yosys_prefix}/bin/yosys + local yosys_installed_version="none" + if [[ -f "${yosys_bin}" ]]; then + yosys_installed_version=$("${yosys_bin}" --version | awk '{print $2}') + elif _command_exists "yosys" && [[ -z "${PREFIX}" ]]; then + yosys_installed_version=$(yosys --version | awk '{print $2}') + fi + + local required_version="${YOSYS_VERSION#v}" + log "Checking Yosys (System: ${yosys_installed_version}, Required: ${required_version})" + if [[ "${yosys_installed_version}" != "${required_version}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning Yosys ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" --recursive https://github.com/YosysHQ/yosys + cd yosys + _execute "Building Yosys..." make -j "${NUM_THREADS}" PREFIX="${yosys_prefix}" ABC_ARCHFLAGS=-Wno-register + _execute "Installing Yosys..." make install PREFIX="${yosys_prefix}" + ) + INSTALL_SUMMARY+=("Yosys: system=${yosys_installed_version}, required=${required_version}, path=${yosys_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Yosys: system=${yosys_installed_version}, required=${required_version}, path=${yosys_prefix}, status=skipped") + fi +} + +# ------------------------------------------------------------------------------ +# Eqy +# ------------------------------------------------------------------------------ +_install_eqy() { + local eqy_prefix=${PREFIX:-"/usr/local"} + local eqy_bin=${eqy_prefix}/bin/eqy + local eqy_installed_version="none" + if [[ -f "${eqy_bin}" ]]; then + eqy_installed_version=$("${eqy_bin}" --version | awk '{print $2}') + elif _command_exists "eqy" && [[ -z "${PREFIX}" ]]; then + eqy_installed_version=$(eqy --version | awk '{print $2}') + fi + + local required_version="${YOSYS_VERSION}" + log "Checking Eqy (System: ${eqy_installed_version}, Required: ${required_version})" + if [[ "${eqy_installed_version}" != "${required_version}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning Eqy ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" https://github.com/YosysHQ/eqy + cd eqy + export PATH="${PREFIX:-/usr/local}/bin:${PATH}" + _execute "Building Eqy..." make -j "${NUM_THREADS}" PREFIX="${eqy_prefix}" + _execute "Installing Eqy..." make install PREFIX="${eqy_prefix}" + ) + INSTALL_SUMMARY+=("Eqy: system=${eqy_installed_version}, required=${required_version}, path=${eqy_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Eqy: system=${eqy_installed_version}, required=${required_version}, path=${eqy_prefix}, status=skipped") + fi +} + +# ------------------------------------------------------------------------------ +# Sby +# ------------------------------------------------------------------------------ +_install_sby() { + local sby_prefix=${PREFIX:-"/usr/local"} + local sby_bin=${sby_prefix}/bin/sby + local sby_installed_version="none" + if [[ -f "${sby_bin}" ]]; then + sby_installed_version=$("${sby_bin}" --version | awk '{print $2}') + elif _command_exists "sby" && [[ -z "${PREFIX}" ]]; then + sby_installed_version=$(sby --version | awk '{print $2}') + fi + + local required_version="${YOSYS_VERSION}" + log "Checking Sby (System: ${sby_installed_version}, Required: ${required_version})" + if [[ "${sby_installed_version}" != "${required_version}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning Sby ${YOSYS_VERSION}..." git clone --depth=1 -b "${YOSYS_VERSION}" --recursive https://github.com/YosysHQ/sby + cd sby + export PATH="${PREFIX:-/usr/local}/bin:${PATH}" + _execute "Installing Sby..." make -j "${NUM_THREADS}" PREFIX="${sby_prefix}" install + ) + INSTALL_SUMMARY+=("Sby: system=${sby_installed_version}, required=${required_version}, path=${sby_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Sby: system=${sby_installed_version}, required=${required_version}, path=${sby_prefix}, status=skipped") + fi +} + +_install_equivalence_deps() { + log "Install equivalence dependencies (-eqy)..." + _install_yosys + _install_eqy + _install_sby +} + +# logging, error handling, and other utility tasks. +# ------------------------------------------------------------------------------ +# Execute a command, hiding output unless in verbose mode or an error occurs. +# Usage: _execute "Cloning Yosys..." git clone ... +_execute() { + local description=$1 + shift + + if [[ "${VERBOSE_MODE}" == "yes" ]]; then + log "${description}" + "$@" + return + fi + + echo -n "${BLUE}${BOLD}[INFO]${NC} ${description}" + local log_file + log_file=$(mktemp) + if ! "$@" &> "${log_file}"; then + echo -e " ${RED}✖${NC}" + cat "${log_file}" + rm "${log_file}" + error "Failed to execute: $*" + else + echo -e " ${GREEN}✔${NC}" + rm "${log_file}" + fi +} + +# CMake +# ------------------------------------------------------------------------------ +_install_cmake() { + local cmake_prefix=${PREFIX:-"/usr/local"} + local cmake_bin=${cmake_prefix}/bin/cmake + local cmake_installed_version="none" + if [[ -f ${cmake_bin} ]]; then + cmake_installed_version=$(${cmake_bin} --version | head -n1 | awk '{print $3}') + elif _command_exists "cmake" && [[ -z "${PREFIX}" ]]; then + cmake_installed_version=$(cmake --version | head -n1 | awk '{print $3}') + fi + + log "Checking CMake (System: ${cmake_installed_version}, Required: ${CMAKE_VERSION_SMALL})" + if [[ "${cmake_installed_version}" != "${CMAKE_VERSION_SMALL}" ]]; then + ( + cd "${BASE_DIR}" + local arch + arch=$(uname -m) + local cmake_checksum="" + if [[ "${arch}" == "aarch64" ]]; then + cmake_checksum=${CMAKE_CHECKSUM_AARCH64} + else + cmake_checksum=${CMAKE_CHECKSUM_X86_64} + fi + _execute "Downloading CMake..." wget $OPT_NOCERT "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION_SMALL}/cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" + _verify_checksum "${cmake_checksum}" "cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" || error "CMake checksum failed." + chmod +x "cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" + _execute "Installing CMake..." "./cmake-${CMAKE_VERSION_SMALL}-linux-${arch}.sh" --skip-license --prefix="${cmake_prefix}" + ) + INSTALL_SUMMARY+=("CMake: system=${cmake_installed_version}, required=${CMAKE_VERSION_SMALL}, path=${cmake_prefix}, status=installed") + else + INSTALL_SUMMARY+=("CMake: system=${cmake_installed_version}, required=${CMAKE_VERSION_SMALL}, path=${cmake_prefix}, status=skipped") + fi +} + +# ------------------------------------------------------------------------------ +# Bison +# ------------------------------------------------------------------------------ +_install_bison() { + local bison_prefix=${PREFIX:-"/usr/local"} + local bison_bin=${bison_prefix}/bin/bison + local bison_installed_version="none" + if [[ -f ${bison_bin} ]]; then + bison_installed_version=$(${bison_bin} --version | awk 'NR==1 {print $NF}') + elif _command_exists "bison" && [[ -z "${PREFIX}" ]]; then + bison_installed_version=$(bison --version | awk 'NR==1 {print $NF}') + bison_prefix=$(dirname "$(dirname "$(command -v bison)")") + fi + + log "Checking Bison (System: ${bison_installed_version}, Required: ${BISON_VERSION})" + if [[ "${bison_installed_version}" != "${BISON_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + local mirrors=( + "https://ftp.gnu.org/gnu/bison" + "https://ftpmirror.gnu.org/bison" + "https://mirrors.kernel.org/gnu/bison" + "https://mirrors.dotsrc.org/gnu/bison" + ) + local success=0 + for mirror in "${mirrors[@]}"; do + local url="${mirror}/bison-${BISON_VERSION}.tar.gz" + log "Trying to download bison from: $url" + if wget $OPT_NOCERT "$url"; then + success=1 + break + else + warn "Failed to download from $mirror" + fi + done + if [[ ${success} -ne 1 ]]; then + error "Could not download bison-${BISON_VERSION}.tar.gz from any mirror." + fi + _verify_checksum "${BISON_CHECKSUM}" "bison-${BISON_VERSION}.tar.gz" || error "Bison checksum failed." + _execute "Extracting Bison..." tar xf "bison-${BISON_VERSION}.tar.gz" + cd "bison-${BISON_VERSION}" + _execute "Configuring Bison..." ./configure --prefix="${bison_prefix}" + _execute "Building and installing Bison..." make -j "${NUM_THREADS}" install + ) + INSTALL_SUMMARY+=("Bison: system=${bison_installed_version}, required=${BISON_VERSION}, path=${bison_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Bison: system=${bison_installed_version}, required=${BISON_VERSION}, path=${bison_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D bison_ROOT=$(realpath "${bison_prefix}") " +} + +# ------------------------------------------------------------------------------ +# Flex +# ------------------------------------------------------------------------------ +_install_flex() { + local flex_prefix=${PREFIX:-"/usr/local"} + local flex_bin=${flex_prefix}/bin/flex + local flex_installed_version="none" + if [[ -f ${flex_bin} ]]; then + flex_installed_version=$(${flex_bin} --version | awk '{print $2}') + elif _command_exists "flex" && [[ -z "${PREFIX}" ]]; then + flex_installed_version=$(flex --version | awk '{print $2}') + fi + + log "Checking Flex (System: ${flex_installed_version}, Required: ${FLEX_VERSION})" + if [[ "${flex_installed_version}" != "${FLEX_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Downloading Flex..." wget $OPT_NOCERT https://github.com/westes/flex/releases/download/v${FLEX_VERSION}/flex-${FLEX_VERSION}.tar.gz + _verify_checksum "${FLEX_CHECKSUM}" "flex-${FLEX_VERSION}.tar.gz" || error "Flex checksum failed." + _execute "Extracting Flex..." tar xf "flex-${FLEX_VERSION}.tar.gz" + cd "flex-${FLEX_VERSION}" + _execute "Configuring Flex..." ./configure --prefix="${flex_prefix}" + _execute "Building Flex..." make -j "${NUM_THREADS}" + _execute "Installing Flex..." make -j "${NUM_THREADS}" install + ) + INSTALL_SUMMARY+=("Flex: system=${flex_installed_version}, required=${FLEX_VERSION}, path=${flex_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Flex: system=${flex_installed_version}, required=${FLEX_VERSION}, path=${flex_prefix}, status=skipped") + fi +} + +# ------------------------------------------------------------------------------ +# SWIG +# ------------------------------------------------------------------------------ +_install_swig() { + local swig_prefix=${PREFIX:-"/usr/local"} + local swig_bin=${swig_prefix}/bin/swig + local swig_installed_version="none" + if [[ -f ${swig_bin} ]]; then + swig_installed_version=$(${swig_bin} -version | grep "SWIG Version" | awk '{print $3}') + elif _command_exists "swig" && [[ -z "${PREFIX}" ]]; then + swig_installed_version=$(swig -version | grep "SWIG Version" | awk '{print $3}') + fi + + log "Checking SWIG (System: ${swig_installed_version}, Required: ${SWIG_VERSION})" + if [[ "${swig_installed_version}" != "${SWIG_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + local tar_name="v${SWIG_VERSION}.tar.gz" + _execute "Downloading SWIG..." wget $OPT_NOCERT "https://github.com/swig/swig/archive/${tar_name}" + _verify_checksum "${SWIG_CHECKSUM}" "${tar_name}" || error "SWIG checksum failed." + _execute "Extracting SWIG..." tar xfz "${tar_name}" + cd swig-* + + _install_pcre + _execute "Generating SWIG configure script..." ./autogen.sh + _execute "Configuring SWIG..." ./configure --prefix="${swig_prefix}" + _execute "Building SWIG..." make -j "${NUM_THREADS}" + _execute "Installing SWIG..." make -j "${NUM_THREADS}" install + ) + INSTALL_SUMMARY+=("SWIG: system=${swig_installed_version}, required=${SWIG_VERSION}, path=${swig_prefix}, status=installed") + else + INSTALL_SUMMARY+=("SWIG: system=${swig_installed_version}, required=${SWIG_VERSION}, path=${swig_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D SWIG_ROOT=$(realpath "${swig_prefix}") " +} + +# ------------------------------------------------------------------------------ +# PCRE +# ------------------------------------------------------------------------------ +_install_pcre() { + local pcre_prefix=${PREFIX:-"/usr/local"} + local pcre_config=${pcre_prefix}/bin/pcre2-config + local pcre_installed_version="none" + + if [[ -f "${pcre_config}" ]]; then + pcre_installed_version=$(${pcre_config} --version) + elif _command_exists "pcre2-config" && [[ -z "${PREFIX}" ]]; then + pcre_installed_version=$(pcre2-config --version) + fi + + log "Checking PCRE (System: ${pcre_installed_version}, Required: ${PCRE_VERSION})" + if [[ "${pcre_installed_version}" == "${PCRE_VERSION}" ]]; then + INSTALL_SUMMARY+=("PCRE: system=${pcre_installed_version}, required=${PCRE_VERSION}, path=${pcre_prefix}, status=skipped") + return + fi + + ( + cd "${BASE_DIR}" + local pcre_tar_name="pcre2-${PCRE_VERSION}.tar.gz" + _execute "Downloading PCRE..." wget $OPT_NOCERT "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE_VERSION}/${pcre_tar_name}" + _verify_checksum "${PCRE_CHECKSUM}" "${pcre_tar_name}" || error "PCRE checksum failed." + _execute "Extracting PCRE..." tar xf "${pcre_tar_name}" + cd "pcre2-${PCRE_VERSION}" + _execute "Configuring PCRE..." ./configure --prefix="${pcre_prefix}" + _execute "Building PCRE..." make -j "${NUM_THREADS}" + _execute "Installing PCRE..." make -j "${NUM_THREADS}" install + ) + INSTALL_SUMMARY+=("PCRE: system=${pcre_installed_version}, required=${PCRE_VERSION}, path=${pcre_prefix}, status=installed") +} + + +# ------------------------------------------------------------------------------ +# Boost +# ------------------------------------------------------------------------------ +_install_boost() { + local boost_prefix=${PREFIX:-"/usr/local"} + local boost_installed_version="none" + if [[ -f "${boost_prefix}/include/boost/version.hpp" ]]; then + boost_installed_version=$(grep "^#define BOOST_LIB_VERSION" "${boost_prefix}/include/boost/version.hpp" | sed -e 's/.*"\(.*\)"/\1/' -e 's/_/./g') + fi + + local required_version="${BOOST_VERSION_BIG}" + log "Checking Boost (System: ${boost_installed_version}, Required: ${required_version})" + if [[ "${boost_installed_version}" != "${required_version}" ]]; then + ( + cd "${BASE_DIR}" + local boost_version_underscore=${BOOST_VERSION_SMALL//./_} + _execute "Downloading Boost..." wget $OPT_NOCERT "https://archives.boost.io/release/${BOOST_VERSION_SMALL}/source/boost_${boost_version_underscore}.tar.gz" + _verify_checksum "${BOOST_CHECKSUM}" "boost_${boost_version_underscore}.tar.gz" || error "Boost checksum failed." + _execute "Extracting Boost..." tar -xf "boost_${boost_version_underscore}.tar.gz" + cd "boost_${boost_version_underscore}" + _execute "Bootstrapping Boost..." ./bootstrap.sh --prefix="${boost_prefix}" + _execute "Installing Boost..." ./b2 install --with-iostreams --with-test --with-serialization --with-system --with-thread -j "${NUM_THREADS}" + ) + INSTALL_SUMMARY+=("Boost: system=${boost_installed_version}, required=${required_version}, path=${boost_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Boost: system=${boost_installed_version}, required=${required_version}, path=${boost_prefix}, status=skipped") + fi + + local boost_cmake_dir="" + if [[ -d "${boost_prefix}/lib/cmake/Boost-${BOOST_VERSION_SMALL}" ]]; then + boost_cmake_dir="${boost_prefix}/lib/cmake/Boost-${BOOST_VERSION_SMALL}" + elif [[ -d "${boost_prefix}/lib64/cmake/Boost-${BOOST_VERSION_SMALL}" ]]; then + boost_cmake_dir="${boost_prefix}/lib64/cmake/Boost-${BOOST_VERSION_SMALL}" + fi + + if [[ -n "${boost_cmake_dir}" ]]; then + CMAKE_PACKAGE_ROOT_ARGS+=" -D Boost_DIR=$(realpath "${boost_cmake_dir}") " + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D Boost_ROOT=$(realpath "${boost_prefix}") " +} + +# ------------------------------------------------------------------------------ +# Eigen +# ------------------------------------------------------------------------------ +_install_eigen() { + local eigen_prefix=${PREFIX:-"/usr/local"} + local eigen_version_file="${eigen_prefix}/include/eigen3/Eigen/src/Core/util/Macros.h" + local eigen_installed_version="none" + + if [[ -f "${eigen_version_file}" ]]; then + local world + world=$(grep "#define EIGEN_WORLD_VERSION" "${eigen_version_file}" | awk '{print $3}') + local major + major=$(grep "#define EIGEN_MAJOR_VERSION" "${eigen_version_file}" | awk '{print $3}') + eigen_installed_version="${world}.${major}" + fi + + log "Checking Eigen (System: ${eigen_installed_version}, Required: ${EIGEN_VERSION})" + if [[ "${eigen_installed_version}" != "${EIGEN_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning Eigen..." git clone --depth=1 -b "${EIGEN_VERSION}" https://gitlab.com/libeigen/eigen.git + cd eigen + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring Eigen..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${eigen_prefix}" -B build . + _execute "Building and installing Eigen..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install + ) + INSTALL_SUMMARY+=("Eigen: system=${eigen_installed_version}, required=${EIGEN_VERSION}, path=${eigen_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Eigen: system=${eigen_installed_version}, required=${EIGEN_VERSION}, path=${eigen_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D Eigen3_ROOT=$(realpath "${eigen_prefix}") " +} + +# ------------------------------------------------------------------------------ +# CUDD +# ------------------------------------------------------------------------------ +_install_cudd() { + local cudd_prefix=${PREFIX:-"/usr/local"} + log "Checking CUDD (Required: ${CUDD_VERSION})" + if [[ ! -f ${cudd_prefix}/include/cudd.h ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning CUDD..." git clone --depth=1 -b "${CUDD_VERSION}" https://github.com/The-OpenROAD-Project/cudd.git + cd cudd + _execute "Generating CUDD configure script..." autoreconf + _execute "Configuring CUDD..." ./configure --prefix="${cudd_prefix}" + _execute "Building and installing CUDD..." make -j "${NUM_THREADS}" install + ) + INSTALL_SUMMARY+=("CUDD: system=none, required=${CUDD_VERSION}, path=${cudd_prefix}, status=installed") + else + INSTALL_SUMMARY+=("CUDD: system=found, required=${CUDD_VERSION}, path=${cudd_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D cudd_ROOT=$(realpath "${cudd_prefix}") " +} + +# ------------------------------------------------------------------------------ +# CUSP +# ------------------------------------------------------------------------------ +_install_cusp() { + local cusp_prefix=${PREFIX:-"/usr/local/include"} + log "Checking CUSP" + if [[ ! -f ${cusp_prefix}/cusp/version.h ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning CUSP..." git clone --depth=1 -b cuda9 https://github.com/cusplibrary/cusplibrary.git + cd cusplibrary + _execute "Installing CUSP..." cp -r ./cusp "${cusp_prefix}" + ) + INSTALL_SUMMARY+=("CUSP: system=none, required=any, path=${cusp_prefix}, status=installed") + else + INSTALL_SUMMARY+=("CUSP: system=found, required=any, path=${cusp_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D cusp_ROOT=$(realpath "${cusp_prefix}") " +} + +# ------------------------------------------------------------------------------ +# Lemon +# ------------------------------------------------------------------------------ +_install_lemon() { + local lemon_prefix=${PREFIX:-"/usr/local"} + local lemon_installed_version="none" + if [[ -f "${lemon_prefix}/include/lemon/config.h" ]]; then + lemon_installed_version=$(grep "LEMON_VERSION" "${lemon_prefix}/include/lemon/config.h" | awk -F'"' '{print $2}') + fi + + log "Checking Lemon (System: ${lemon_installed_version}, Required: ${LEMON_VERSION})" + if [[ "${lemon_installed_version}" != "${LEMON_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning Lemon..." git clone --depth=1 -b "${LEMON_VERSION}" https://github.com/The-OpenROAD-Project/lemon-graph.git + cd lemon-graph + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring Lemon..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${lemon_prefix}" -B build . + _execute "Building and installing Lemon..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install + ) + INSTALL_SUMMARY+=("Lemon: system=${lemon_installed_version}, required=${LEMON_VERSION}, path=${lemon_prefix}, status=installed") + else + INSTALL_SUMMARY+=("Lemon: system=${lemon_installed_version}, required=${LEMON_VERSION}, path=${lemon_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D LEMON_ROOT=$(realpath "${lemon_prefix}") " +} + +# ------------------------------------------------------------------------------ +# spdlog +# ------------------------------------------------------------------------------ +_install_spdlog() { + local spdlog_prefix=${PREFIX:-"/usr/local"} + local spdlog_installed_version="none" + if [ -d "${spdlog_prefix}/include/spdlog" ]; then + spdlog_installed_version=$(grep "#define SPDLOG_VER_" "${spdlog_prefix}/include/spdlog/version.h" | sed 's/.*\s//' | tr '\n' '.' | sed 's/\.$//') + fi + log "Checking spdlog (System: ${spdlog_installed_version}, Required: ${SPDLOG_VERSION})" + if [[ "${spdlog_installed_version}" != "${SPDLOG_VERSION}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Cloning spdlog..." git clone --depth=1 -b "v${SPDLOG_VERSION}" https://github.com/gabime/spdlog.git + cd spdlog + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring spdlog..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${spdlog_prefix}" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DSPDLOG_BUILD_EXAMPLE=OFF -B build . + _execute "Building and installing spdlog..." "${cmake_bin}" --build build -j "${NUM_THREADS}" --target install + ) + INSTALL_SUMMARY+=("spdlog: system=${spdlog_installed_version}, required=${SPDLOG_VERSION}, path=${spdlog_prefix}, status=installed") + else + INSTALL_SUMMARY+=("spdlog: system=${spdlog_installed_version}, required=${SPDLOG_VERSION}, path=${spdlog_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D spdlog_ROOT=$(realpath "${spdlog_prefix}") " +} + +# ------------------------------------------------------------------------------ +# gtest +# ------------------------------------------------------------------------------ +_install_gtest() { + local gtest_prefix=${PREFIX:-"/usr/local"} + log "Checking gtest (Required: ${GTEST_VERSION})" + if [[ ! -d ${gtest_prefix}/include/gtest ]]; then + ( + cd "${BASE_DIR}" + _execute "Downloading gtest..." wget $OPT_NOCERT "https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.zip" + _verify_checksum "${GTEST_CHECKSUM}" "v${GTEST_VERSION}.zip" || error "gtest checksum failed." + _execute "Extracting gtest..." unzip "v${GTEST_VERSION}.zip" + cd "googletest-${GTEST_VERSION}" + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring gtest..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${gtest_prefix}" -B build . + _execute "Building and installing gtest..." "${cmake_bin}" --build build --target install + ) + INSTALL_SUMMARY+=("gtest: system=none, required=${GTEST_VERSION}, path=${gtest_prefix}, status=installed") + else + INSTALL_SUMMARY+=("gtest: system=found, required=${GTEST_VERSION}, path=${gtest_prefix}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D GTest_ROOT=$(realpath "${gtest_prefix}") " +} + +# ------------------------------------------------------------------------------ +# Abseil +# ------------------------------------------------------------------------------ +_install_abseil() { + local absl_prefix_install=${PREFIX:-"/usr/local"} + local absl_prefix_found="" + local absl_version_file="" + + # Check in default/user-specified prefix first + local absl_version_file_default="${absl_prefix_install}/lib/cmake/absl/abslConfigVersion.cmake" + if [[ -f "${absl_version_file_default}" ]]; then + absl_prefix_found="${absl_prefix_install}" + absl_version_file="${absl_version_file_default}" + fi + + # If not found, check in or-tools path + if [[ -z "${absl_prefix_found}" && -n "${OR_TOOLS_PATH}" ]]; then + local absl_version_file_or_tools="${OR_TOOLS_PATH}/lib/cmake/absl/abslConfigVersion.cmake" + if [[ -f "${absl_version_file_or_tools}" ]]; then + absl_prefix_found="${OR_TOOLS_PATH}" + absl_version_file="${absl_version_file_or_tools}" + fi + fi + + local absl_installed_version="none" + if [[ -n "${absl_version_file}" ]]; then + absl_installed_version=$(grep '^set(PACKAGE_VERSION "' "${absl_version_file}" | head -n 1 | awk -F'"' '{print $2}') + fi + + local required_version="${ABSL_VERSION%.*}" + log "Checking Abseil (System: ${absl_installed_version}, Required: ${required_version})" + if [[ "${absl_installed_version}" != "${required_version}" ]]; then + ( + cd "${BASE_DIR}" + _execute "Downloading Abseil..." wget $OPT_NOCERT "https://github.com/abseil/abseil-cpp/releases/download/${ABSL_VERSION}/abseil-cpp-${ABSL_VERSION}.tar.gz" + _verify_checksum "${ABSL_CHECKSUM}" "abseil-cpp-${ABSL_VERSION}.tar.gz" || error "Abseil checksum failed." + _execute "Extracting Abseil..." tar xf "abseil-cpp-${ABSL_VERSION}.tar.gz" + cd "abseil-cpp-${ABSL_VERSION}" + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring Abseil..." "${cmake_bin}" -DCMAKE_INSTALL_PREFIX="${absl_prefix_install}" -DCMAKE_CXX_STANDARD=17 -B build . + _execute "Building and installing Abseil..." "${cmake_bin}" --build build --target install + ) + absl_prefix_found="${absl_prefix_install}" + INSTALL_SUMMARY+=("Abseil: system=${absl_installed_version}, required=${required_version}, path=${absl_prefix_found}, status=installed") + else + INSTALL_SUMMARY+=("Abseil: system=${absl_installed_version}, required=${required_version}, path=${absl_prefix_found}, status=skipped") + fi + CMAKE_PACKAGE_ROOT_ARGS+=" -D ABSL_ROOT=$(realpath "${absl_prefix_found}") " +} + +_install_or_tools() { + local os=$1 + local os_version=$2 + local arch=$3 + local skip_system_or_tools=$4 + + # Create a temporary directory for downloads + local build_dir + build_dir=$(mktemp -d) + + local or_tools_installed_version="none" + # Check if a system-installed version of OR-Tools is present + log "Checking or-tools (System: ${or_tools_installed_version}, Required: ${OR_TOOLS_VERSION_SMALL})" + if [[ "${skip_system_or_tools}" == "false" ]]; then + # Disable exit on error for 'find' command, as it might return non zero + set +euo pipefail + local existing_libs + local search_paths="" + if [[ -n "${PREFIX}" ]]; then + search_paths="${OR_TOOLS_PATH}" + else + search_paths="/usr/local /usr /opt" + fi + existing_libs=$(find ${search_paths} -type f -name "libortools.so.*" 2>/dev/null) + # Bring back exit on error + set -euo pipefail + if [[ -n "${existing_libs}" ]]; then + local first_lib="${existing_libs%%$'\n'*}" + or_tools_installed_version=$(basename "${first_lib}" | sed 's/libortools.so.//') + local or_tools_root + or_tools_root=$(dirname "${first_lib}") + local or_tools_install_dir + or_tools_install_dir=$(realpath "${or_tools_root}/..") + + if [[ "${or_tools_installed_version}" == "${OR_TOOLS_VERSION_SMALL}" ]]; then + CMAKE_PACKAGE_ROOT_ARGS+=" -D ortools_ROOT=${or_tools_install_dir} " + OR_TOOLS_PATH=${or_tools_install_dir} + INSTALL_SUMMARY+=("or-tools: system=${or_tools_installed_version}, required=${OR_TOOLS_VERSION_SMALL}, path=${OR_TOOLS_PATH}, status=skipped") + return + else + log "Found old OR-Tools version ${or_tools_installed_version}. Removing it." + rm -rf "${or_tools_install_dir}" + fi + fi + fi + + if [[ "$(uname -m)" == "aarch64" ]]; then + ( + cd "${build_dir}" + _execute "Cloning or-tools..." git clone --depth=1 -b "v${OR_TOOLS_VERSION_BIG}" https://github.com/google/or-tools.git + cd or-tools + local cmake_bin=${PREFIX:-/usr/local}/bin/cmake + _execute "Configuring or-tools..." "${cmake_bin}" -S. -Bbuild -DBUILD_DEPS:BOOL=ON -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_SAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DCMAKE_INSTALL_PREFIX="${OR_TOOLS_PATH}" -DCMAKE_CXX_FLAGS="-w" -DCMAKE_C_FLAGS="-w" + _execute "Building and installing or-tools..." "${cmake_bin}" --build build --config Release --target install -v -j "${NUM_THREADS}" + ) + else + ( + cd "${build_dir}" + if [[ "${os_version}" == "rodete" ]]; then + os_version=11 + fi + local or_tools_file="or-tools_${arch}_${os}-${os_version}_cpp_v${OR_TOOLS_VERSION_SMALL}.tar.gz" + _execute "Downloading or-tools..." wget $OPT_NOCERT "https://github.com/google/or-tools/releases/download/v${OR_TOOLS_VERSION_BIG}/${or_tools_file}" + mkdir -p "${OR_TOOLS_PATH}" + _execute "Extracting or-tools..." tar --strip 1 --dir "${OR_TOOLS_PATH}" -xf "${or_tools_file}" + ) + fi + INSTALL_SUMMARY+=("or-tools: system=${or_tools_installed_version}, required=${OR_TOOLS_VERSION_SMALL}, path=${OR_TOOLS_PATH}, status=installed") + + CMAKE_PACKAGE_ROOT_ARGS+=" -D ortools_ROOT=$(realpath "${OR_TOOLS_PATH}") " + rm -rf "${build_dir}" +} +# ============================================================================== +# Dependency Installation Modules +# ============================================================================== +# Each dependency will have its own dedicated function for installation and +# version management. This modular approach makes the script easier to +# maintain and extend. +# ------------------------------------------------------------------------------ +# Bazel +# ------------------------------------------------------------------------------ +_install_bazel() { + local bazel_prefix=${PREFIX:-"/usr/local"} + log "Checking Bazel (via bazelisk)" + if _command_exists "bazelisk"; then + log "bazelisk already installed, skipping." + INSTALL_SUMMARY+=("Bazel: system=found, required=any, status=skipped") + return + fi + if [[ "$OSTYPE" == "darwin"* ]]; then + _execute "Installing bazelisk via Homebrew..." brew install bazelisk + else + local arch + arch=$(uname -m) + local bazelisk_arch="amd64" + if [[ "${arch}" == "aarch64" ]]; then + bazelisk_arch="arm64" + fi + local bazelisk_checksum="${BAZELISK_CHECKSUM_AMD64}" + if [[ "${bazelisk_arch}" == "arm64" ]]; then + bazelisk_checksum="${BAZELISK_CHECKSUM_ARM64}" + fi + ( + cd "${BASE_DIR}" + _execute "Downloading bazelisk v${BAZELISK_VERSION}..." curl -Lo bazelisk \ + "https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VERSION}/bazelisk-linux-${bazelisk_arch}" + _verify_checksum "${bazelisk_checksum}" "bazelisk" || error "Bazelisk checksum failed." + chmod +x bazelisk + _execute "Installing bazelisk..." mv bazelisk "${bazel_prefix}/bin/bazelisk" + ) + if [[ "${NO_GUI}" != "yes" ]]; then + if _command_exists "apt-get"; then + _execute "Installing xcb libraries for GUI support..." \ + apt-get -y install --no-install-recommends \ + libxcb1-dev libxcb-util-dev libxcb-icccm4-dev libxcb-image0-dev \ + libxcb-keysyms1-dev libxcb-randr0-dev libxcb-render-util0-dev \ + libxcb-xinerama0-dev libxcb-xkb-dev + elif _command_exists "yum"; then + _execute "Installing xcb libraries for GUI support..." \ + yum install -y \ + libxcb-devel xcb-util-devel xcb-util-image-devel \ + xcb-util-keysyms-devel xcb-util-renderutil-devel xcb-util-wm-devel + fi + fi + fi + INSTALL_SUMMARY+=("Bazel: system=none, required=latest, status=installed") +} + +# ------------------------------------------------------------------------------ +# Bazel Dev Tools (buildifier, etc.) +# ------------------------------------------------------------------------------ +_install_bazel_dev() { + local bazel_prefix=${PREFIX:-"/usr/local"} + log "Checking Bazel dev tools (buildifier)" + if _command_exists "buildifier"; then + log "buildifier already installed, skipping." + INSTALL_SUMMARY+=("buildifier: system=found, required=any, status=skipped") + return + fi + if [[ "$OSTYPE" == "darwin"* ]]; then + _execute "Installing buildifier via Homebrew..." brew install buildifier + else + local arch + arch=$(uname -m) + local buildifier_arch="amd64" + if [[ "${arch}" == "aarch64" ]]; then + buildifier_arch="arm64" + fi + local buildifier_checksum="${BUILDIFIER_CHECKSUM_AMD64}" + if [[ "${buildifier_arch}" == "arm64" ]]; then + buildifier_checksum="${BUILDIFIER_CHECKSUM_ARM64}" + fi + ( + cd "${BASE_DIR}" + _execute "Downloading buildifier v${BUILDIFIER_VERSION}..." curl -Lo buildifier \ + "https://github.com/bazelbuild/buildtools/releases/download/v${BUILDIFIER_VERSION}/buildifier-linux-${buildifier_arch}" + _verify_checksum "${buildifier_checksum}" "buildifier" || error "Buildifier checksum failed." + chmod +x buildifier + _execute "Installing buildifier..." mv buildifier "${bazel_prefix}/bin/buildifier" + ) + fi + INSTALL_SUMMARY+=("buildifier: system=none, required=latest, status=installed") +} + +_install_common_dev() { + log "Install common development dependencies (-common or -all)" + rm -rf "${BASE_DIR}" + mkdir -p "${BASE_DIR}" + if [[ -n "${PREFIX}" ]]; then + mkdir -p "${PREFIX}" + fi + + _install_cmake + _install_bison + _install_flex + _install_pcre + _install_swig + _install_boost + _install_eigen + _install_cudd + _install_cusp + _install_lemon + _install_spdlog + _install_gtest + + if [[ "${EQUIVALENCE_DEPS}" == "yes" ]]; then + _install_equivalence_deps + fi + + if [[ -n ${PREFIX} ]]; then + cat > "${PREFIX}/env.sh" < 4 {print \$3}' | grep -v Name | xargs -r zypper -n remove --clean-deps" +} + +# ------------------------------------------------------------------------------ +# Darwin (macOS) +# ------------------------------------------------------------------------------ +_install_darwin_packages() { + if ! _command_exists "brew"; then + error "Homebrew is not found. Please install Homebrew before continuing." + fi + if ! xcode-select -p &> /dev/null; then + cat < Date: Wed, 13 May 2026 11:12:41 +0530 Subject: [PATCH 4/4] fix: correct setup-xcode SHA (was annotated tag, not commit) Maliberty identified the SHA was wrong. The git/refs/tags endpoint returns the annotated tag object SHA, not the commit SHA. The actual commit is ed7a3b1fda3918c0306d1b724322adc0b8cc0a90. Also verified other pinned SHAs are commit SHAs (not annotated tags). Files: .github/workflows/github-actions-macos.yml, .github/workflows/github-actions-macos-bazel.yml --- .github/workflows/github-actions-macos-bazel.yml | 2 +- .github/workflows/github-actions-macos.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions-macos-bazel.yml b/.github/workflows/github-actions-macos-bazel.yml index 0120bd0daae..29de8582c5e 100644 --- a/.github/workflows/github-actions-macos-bazel.yml +++ b/.github/workflows/github-actions-macos-bazel.yml @@ -12,7 +12,7 @@ jobs: runs-on: macos-latest steps: - name: Setup xcode - uses: maxim-lobanov/setup-xcode@1242409711ff5721add51979e9e11e23ebb7e5a4 # v1 + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1 with: xcode-version: latest-stable diff --git a/.github/workflows/github-actions-macos.yml b/.github/workflows/github-actions-macos.yml index 9955bb5a76f..7194cea0268 100644 --- a/.github/workflows/github-actions-macos.yml +++ b/.github/workflows/github-actions-macos.yml @@ -11,7 +11,7 @@ jobs: runs-on: macos-latest steps: - name: Setup xcode - uses: maxim-lobanov/setup-xcode@1242409711ff5721add51979e9e11e23ebb7e5a4 # v1 + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1 with: xcode-version: latest-stable - name: Check out repository code