Improve command detection in CMake

This commit is contained in:
Ashcon Partovi
2024-10-01 13:50:15 -07:00
parent 07fd814629
commit 27a157b6c1
8 changed files with 141 additions and 100 deletions

View File

@@ -30,7 +30,6 @@ jobs:
name: clang-format name: clang-format
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: sudo rm /usr/bin/clang-format
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
@@ -49,20 +48,12 @@ jobs:
- name: Install LLVM - name: Install LLVM
run: | run: |
curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all
- run: ls -l /usr/lib/llvm-${LLVM_VERSION_MAJOR}/bin/
- run: echo "/usr/lib/llvm-${LLVM_VERSION_MAJOR}/bin/" >> $GITHUB_PATH
- name: Clang Format Version
env:
ENABLE_CCACHE: OFF
LLVM_VERSION: ${{ env.LLVM_VERSION }}
run: |
bun run clang-format:version
- name: Clang Format - name: Clang Format
env: env:
ENABLE_CCACHE: OFF ENABLE_CCACHE: OFF
LLVM_VERSION: ${{ env.LLVM_VERSION }} LLVM_VERSION: ${{ env.LLVM_VERSION }}
run: | run: |
bun run clang-format bun run clang-format:diff
- name: Commit - name: Commit
uses: stefanzweifel/git-auto-commit-action@v5 uses: stefanzweifel/git-auto-commit-action@v5
with: with:

View File

@@ -43,10 +43,11 @@ include(BuildBun)
# --- Analysis --- # --- Analysis ---
include(RunClangFormat) optionx(ENABLE_ANALYSIS BOOL "If analysis targets should be enabled" DEFAULT OFF)
include(RunClangTidy)
include(RunZigFormat)
if (ENABLE_PRETTIER) if(ENABLE_ANALYSIS)
include(RunClangFormat)
include(RunClangTidy)
include(RunZigFormat)
include(RunPrettier) include(RunPrettier)
endif() endif()

View File

@@ -1,6 +1,6 @@
import Color from "color"; import Color from "color";
import tinycolor from "tinycolor2"; import tinycolor from "tinycolor2";
import { bench, run, group } from "./runner.mjs"; import { bench, group, run } from "./runner.mjs";
const inputs = ["#f00", "rgb(255, 0, 0)", "rgba(255, 0, 0, 1)", "hsl(0, 100%, 50%)"]; const inputs = ["#f00", "rgb(255, 0, 0)", "rgba(255, 0, 0, 1)", "hsl(0, 100%, 50%)"];

View File

@@ -30,6 +30,10 @@ macro(optionx variable type description)
set(multiValueArgs) set(multiValueArgs)
cmake_parse_arguments(${variable} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(${variable} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(DEFINED ${variable})
set(${variable}_VALUE ${${variable}})
endif()
if(NOT ${type} MATCHES "^(BOOL|STRING|FILEPATH|PATH|INTERNAL)$") if(NOT ${type} MATCHES "^(BOOL|STRING|FILEPATH|PATH|INTERNAL)$")
set(${variable}_REGEX ${type}) set(${variable}_REGEX ${type})
set(${variable}_TYPE STRING) set(${variable}_TYPE STRING)
@@ -65,7 +69,9 @@ macro(optionx variable type description)
message(FATAL_ERROR "Invalid ${${variable}_SOURCE}: ${${variable}_PREVIEW}=\"${${variable}}\", please use ${${variable}_PREVIEW}=<${${variable}_REGEX}>") message(FATAL_ERROR "Invalid ${${variable}_SOURCE}: ${${variable}_PREVIEW}=\"${${variable}}\", please use ${${variable}_PREVIEW}=<${${variable}_REGEX}>")
endif() endif()
message(STATUS "Set ${variable}: ${${variable}}") if(NOT ${variable}_VALUE STREQUAL ${variable})
message(STATUS "Set ${variable}: ${${variable}}")
endif()
endmacro() endmacro()
# unsupported() # unsupported()
@@ -194,102 +200,153 @@ function(setenv variable value)
message(STATUS "Set ENV ${variable}: ${value}") message(STATUS "Set ENV ${variable}: ${value}")
endfunction() endfunction()
# check_command() # satisfies_range()
# Description: # Description:
# Checks if a command is available, used by `find_command()` as a validator. # Check if a version satisfies a version range
# Arguments: # Arguments:
# FOUND bool - The variable to set to true if the version is found # version string - The version to check (e.g. "1.2.3")
# CMD string - The executable to check the version of # range string - The range to check against (e.g. ">=1.2.3")
function(check_command FOUND CMD) # variable string - The variable to store the result in
set(${FOUND} OFF PARENT_SCOPE) function(satisfies_range version range variable)
if(range STREQUAL "ignore")
if(${CMD} MATCHES "zig") set(${variable} ON PARENT_SCOPE)
set(CHECK_COMMAND ${CMD} version)
else()
set(CHECK_COMMAND ${CMD} --version)
endif()
execute_process(
COMMAND ${CHECK_COMMAND}
RESULT_VARIABLE RESULT
OUTPUT_VARIABLE OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT RESULT EQUAL 0 OR NOT OUTPUT)
message(DEBUG "${CHECK_COMMAND}, exited with code ${RESULT}")
return() return()
endif() endif()
parse_semver(${OUTPUT} CMD) set(${variable} OFF PARENT_SCOPE)
parse_semver(${CHECK_COMMAND_VERSION} CHECK)
if(CHECK_COMMAND_VERSION MATCHES ">=") string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" match "${version}")
if(NOT CMD_VERSION VERSION_GREATER_EQUAL ${CHECK_VERSION}) if(NOT match)
message(DEBUG "${CHECK_COMMAND}, actual: ${CMD_VERSION}, expected: ${CHECK_COMMAND_VERSION}") return()
return() endif()
endif() set(version ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3})
elseif(CHECK_COMMAND_VERSION MATCHES ">")
if(NOT CMD_VERSION VERSION_GREATER ${CHECK_VERSION}) string(REGEX MATCH "(>=|<=|>|<)?([0-9]+)\\.([0-9]+)\\.([0-9]+)" match "${range}")
message(DEBUG "${CHECK_COMMAND}, actual: ${CMD_VERSION}, expected: ${CHECK_COMMAND_VERSION}") if(NOT match)
return() return()
endif() endif()
set(comparator ${CMAKE_MATCH_1})
set(range ${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${CMAKE_MATCH_4})
if(comparator STREQUAL ">=")
set(comparator VERSION_GREATER_EQUAL)
elseif(comparator STREQUAL ">")
set(comparator VERSION_GREATER)
elseif(comparator STREQUAL "<=")
set(comparator VERSION_LESS_EQUAL)
elseif(comparator STREQUAL "<")
set(comparator VERSION_LESS)
else() else()
if(NOT CMD_VERSION VERSION_EQUAL ${CHECK_VERSION}) set(comparator VERSION_EQUAL)
message(DEBUG "${CHECK_COMMAND}, actual: ${CMD_VERSION}, expected: =${CHECK_COMMAND_VERSION}")
return()
endif()
endif() endif()
set(${FOUND} TRUE PARENT_SCOPE) if(version ${comparator} ${range})
set(${variable} ON PARENT_SCOPE)
endif()
endfunction() endfunction()
# find_command() # find_command()
# Description: # Description:
# Finds a command, similar to `find_program()`, but allows for version checking. # Finds a command, similar to `find_program()`, but allows for version checking.
# Arguments: # Arguments:
# VARIABLE string - The variable to set # VARIABLE string - The variable to set
# COMMAND string[] - The names of the command to find # VERSION_VARIABLE string - The variable to check for the version
# PATHS string[] - The paths to search for the command # COMMAND string[] - The names of the command to find
# REQUIRED bool - If false, the command is optional # PATHS string[] - The paths to search for the command
# VERSION string - The version of the command to find (e.g. "1.2.3" or ">1.2.3") # REQUIRED bool - If false, the command is optional
# VERSION string - The version of the command to find (e.g. "1.2.3" or ">1.2.3")
function(find_command) function(find_command)
set(options) set(args VARIABLE VERSION_VARIABLE REQUIRED VERSION)
set(args VARIABLE VERSION MIN_VERSION REQUIRED)
set(multiArgs COMMAND PATHS) set(multiArgs COMMAND PATHS)
cmake_parse_arguments(CMD "${options}" "${args}" "${multiArgs}" ${ARGN}) cmake_parse_arguments(FIND "" "${args}" "${multiArgs}" ${ARGN})
if(NOT CMD_VARIABLE) if(NOT FIND_VARIABLE OR NOT FIND_COMMAND)
message(FATAL_ERROR "find_command: VARIABLE is required") message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}: VARIABLE and COMMAND are required")
endif() endif()
if(NOT CMD_COMMAND) if(NOT FIND_VERSION_VARIABLE)
message(FATAL_ERROR "find_command: COMMAND is required") set(FIND_VERSION_VARIABLE ${FIND_VARIABLE}_VERSION)
endif() endif()
if(CMD_VERSION) list(GET FIND_COMMAND 0 FIND_NAME)
set(CHECK_COMMAND_VERSION ${CMD_VERSION}) # special global variable optionx(${FIND_VERSION_VARIABLE} STRING "The version of ${FIND_NAME} to find" DEFAULT "${FIND_VERSION}")
set(CMD_VALIDATOR VALIDATOR check_command)
if(${FIND_VERSION_VARIABLE})
function(find_command_version variable exe)
set(${variable} OFF PARENT_SCOPE)
if(${exe} MATCHES "(go|zig)(\.exe)?$")
set(command ${exe} version)
else()
set(command ${exe} --version)
endif()
execute_process(
COMMAND ${command}
RESULT_VARIABLE result
OUTPUT_VARIABLE output
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT result EQUAL 0)
set(reason "exited with ${result}")
elseif(NOT output)
set(reason "no output")
else()
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" match "${output}")
if(match)
set(version ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3})
set(reason "\"${version}\"")
else()
set(reason "no version")
endif()
endif()
set_property(GLOBAL PROPERTY ${FIND_NAME} "${exe}: ${reason}" APPEND)
if(version)
satisfies_range(${version} ${${FIND_VERSION_VARIABLE}} ${variable})
set(${variable} ${${variable}} PARENT_SCOPE)
endif()
endfunction()
set(FIND_VALIDATOR VALIDATOR find_command_version)
endif() endif()
find_program( find_program(
${CMD_VARIABLE} ${FIND_VARIABLE}
NAMES ${CMD_COMMAND} NAMES ${FIND_COMMAND}
PATHS ${CMD_PATHS} PATHS ${FIND_PATHS}
${CMD_VALIDATOR} ${FIND_VALIDATOR}
) )
if(NOT CMD_REQUIRED STREQUAL "OFF" AND ${CMD_VARIABLE} MATCHES "NOTFOUND") if(NOT FIND_REQUIRED STREQUAL "OFF" AND ${FIND_VARIABLE} MATCHES "NOTFOUND")
if(CMD_VERSION) set(error "Command not found: \"${FIND_NAME}\"")
message(FATAL_ERROR "Command not found: \"${CMD_COMMAND}\" that matches version \"${CHECK_COMMAND_VERSION}\"")
if(FIND_VERSION)
set(error "${error} that satisfies version \"${${FIND_VERSION_VARIABLE}}\"")
endif() endif()
message(FATAL_ERROR "Command not found: \"${CMD_COMMAND}\"")
get_property(FIND_RESULTS GLOBAL PROPERTY ${FIND_NAME})
if(NOT FIND_RESULTS MATCHES "NOTFOUND")
set(error "${error}\nThe following commands did not satisfy the requirement:")
foreach(result ${FIND_RESULTS})
set(error "${error}\n ${result}")
endforeach()
endif()
set(error "${error}\nTo fix this, either:
1. Install ${FIND_NAME} ${${FIND_VERSION_VARIABLE}}
2. Set -D${FIND_VERSION_VARIABLE}=<version> to require a different version
3. Set -D${FIND_VERSION_VARIABLE}=ignore to allow any version
")
message(FATAL_ERROR ${error})
endif() endif()
if(${CMD_VARIABLE} MATCHES "NOTFOUND") if(${FIND_VARIABLE} MATCHES "NOTFOUND")
unset(${CMD_VARIABLE} PARENT_SCOPE) unset(${FIND_VARIABLE} PARENT_SCOPE)
else() else()
setx(${CMD_VARIABLE} ${${CMD_VARIABLE}} PARENT_SCOPE) setx(${FIND_VARIABLE} ${${FIND_VARIABLE}} PARENT_SCOPE)
endif() endif()
endfunction() endfunction()

View File

@@ -3,6 +3,8 @@
find_command( find_command(
VARIABLE VARIABLE
CLANG_FORMAT_PROGRAM CLANG_FORMAT_PROGRAM
VERSION_VARIABLE
LLVM_VERSION
COMMAND COMMAND
clang-format clang-format
REQUIRED REQUIRED
@@ -11,17 +13,6 @@ find_command(
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES}) set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES})
register_command(
TARGET
clang-format-version
COMMENT
"Print clang-format version"
COMMAND
${CLANG_FORMAT_PROGRAM}
--version
ALWAYS_RUN
)
register_command( register_command(
TARGET TARGET
clang-format-check clang-format-check

View File

@@ -3,10 +3,10 @@
find_command( find_command(
VARIABLE VARIABLE
CLANG_TIDY_PROGRAM CLANG_TIDY_PROGRAM
VERSION_VARIABLE
LLVM_VERSION
COMMAND COMMAND
clang-tidy clang-tidy
VERSION
${LLVM_VERSION}
REQUIRED REQUIRED
OFF OFF
) )

View File

@@ -35,6 +35,7 @@ set(LLVM_PATH ${LLVM_PREFIX}/bin)
macro(find_llvm_command VARIABLE COMMAND) macro(find_llvm_command VARIABLE COMMAND)
find_command( find_command(
VARIABLE ${VARIABLE} VARIABLE ${VARIABLE}
VERSION_VARIABLE LLVM_VERSION
COMMAND ${COMMAND} ${COMMAND}-${LLVM_VERSION_MAJOR} COMMAND ${COMMAND} ${COMMAND}-${LLVM_VERSION_MAJOR}
PATHS ${LLVM_PATH} PATHS ${LLVM_PATH}
VERSION ${LLVM_VERSION} VERSION ${LLVM_VERSION}
@@ -45,6 +46,7 @@ endmacro()
macro(find_llvm_command_no_version VARIABLE COMMAND) macro(find_llvm_command_no_version VARIABLE COMMAND)
find_command( find_command(
VARIABLE ${VARIABLE} VARIABLE ${VARIABLE}
VERSION_VARIABLE LLVM_VERSION
COMMAND ${COMMAND} ${COMMAND}-${LLVM_VERSION_MAJOR} COMMAND ${COMMAND} ${COMMAND}-${LLVM_VERSION_MAJOR}
PATHS ${LLVM_PATH} PATHS ${LLVM_PATH}
REQUIRED ON REQUIRED ON

View File

@@ -58,9 +58,8 @@
"zig:check": "bun run zig build check --summary new", "zig:check": "bun run zig build check --summary new",
"zig:check-all": "bun run zig build check-all --summary new", "zig:check-all": "bun run zig build check-all --summary new",
"zig:check-windows": "bun run zig build check-windows --summary new", "zig:check-windows": "bun run zig build check-windows --summary new",
"cmake": "bun ./scripts/build.mjs -DCMAKE_BUILD_TYPE=Debug -B build/debug", "cmake": "bun ./scripts/build.mjs -DCMAKE_BUILD_TYPE=Debug -DENABLE_ANALYSIS=ON -B build/debug",
"clang-format": "bun run cmake --target clang-format", "clang-format": "bun run cmake --target clang-format",
"clang-format:version": "bun run cmake --target clang-format-version",
"clang-format:check": "bun run cmake --target clang-format-check", "clang-format:check": "bun run cmake --target clang-format-check",
"clang-format:diff": "bun run cmake --target clang-format-diff", "clang-format:diff": "bun run cmake --target clang-format-diff",
"clang-tidy": "bun run cmake --target clang-tidy", "clang-tidy": "bun run cmake --target clang-tidy",
@@ -69,9 +68,9 @@
"zig-format": "bun run cmake --target zig-format", "zig-format": "bun run cmake --target zig-format",
"zig-format:check": "bun run cmake --target zig-format-check", "zig-format:check": "bun run cmake --target zig-format-check",
"zig-format:diff": "bun run cmake --target zig-format-diff", "zig-format:diff": "bun run cmake --target zig-format-diff",
"prettier": "bun run cmake -DENABLE_PRETTIER=ON --target prettier", "prettier": "bun run cmake --target prettier",
"prettier:check": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-check", "prettier:check": "bun run cmake --target prettier-check",
"prettier:extra": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-extra", "prettier:extra": "bun run cmake --target prettier-extra",
"prettier:diff": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-diff" "prettier:diff": "bun run cmake --target prettier-diff"
} }
} }