diff options
Diffstat (limited to 'build')
| -rwxr-xr-x | build | 475 |
1 files changed, 0 insertions, 475 deletions
| @@ -1,475 +0,0 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # Build system for nissy, run './build help' for info on how to use this. | ||
| 4 | |||
| 5 | # The variables below can be used to personalize the build system. For example, | ||
| 6 | # to compile with clang instead of the default cc one can use: | ||
| 7 | # | ||
| 8 | # CC=clang ./build | ||
| 9 | # | ||
| 10 | # Each variable also has a counterpart that starts with NISSY_BUILD_*. These | ||
| 11 | # other variables can be set, for example, in your shell configuration file | ||
| 12 | # to change the default build options. They are still overwritten by the values | ||
| 13 | # of the non-NISSY_BUILD_* variables, if set. | ||
| 14 | # For example, on a system that supports the addressed and undefined behavior | ||
| 15 | # sanitizers, one can set | ||
| 16 | # | ||
| 17 | # export NISSY_BUILD_SANITIZE="address,undefined" | ||
| 18 | # | ||
| 19 | # so that these sanitizers will be enabled when building nissy in debug mode. | ||
| 20 | # If later the same user wants to build a debug version without sanitizers, | ||
| 21 | # they may use | ||
| 22 | # | ||
| 23 | # SANITIZE="" ./build debug | ||
| 24 | # | ||
| 25 | # And the empty string value will take precedence. | ||
| 26 | |||
| 27 | # Specify the C compiler to use. | ||
| 28 | CC=${CC-${NISSY_BUILD_CC:-"cc"}} | ||
| 29 | |||
| 30 | # Specify the C++ compiler for the C++ examples. | ||
| 31 | CXX=${CXX-${NISSY_BUILD_CXX:-"c++"}} | ||
| 32 | |||
| 33 | # Specify the compiler to use when building for WASM. | ||
| 34 | EMCC=${EMCC-${NISSY_BUILD_EMCC:-"emcc"}} | ||
| 35 | |||
| 36 | # Specify the nodejs command for running tests for WASM. | ||
| 37 | NODE=${NODE-${NISSY_BUILD_NODE:-"node"}} | ||
| 38 | |||
| 39 | # The maximum number of threads to use for multi-threaded operations. | ||
| 40 | # This is also used as default value in case an operation allows | ||
| 41 | # specifying how many threads to use. | ||
| 42 | # The number n must be between 1 and 128. | ||
| 43 | # The default value is 16. | ||
| 44 | THREADS=${THREADS-${NISSY_BUILD_THREADS}} | ||
| 45 | |||
| 46 | detectthreads() { | ||
| 47 | # TODO: detect based on system | ||
| 48 | # Is 'getconf NPROCESSORD_ONLN' portable? Is it threads or cores? | ||
| 49 | echo "16" | ||
| 50 | } | ||
| 51 | |||
| 52 | [ -z "$THREADS" ] && THREADS="$(detectthreads)" | ||
| 53 | |||
| 54 | # You can use this variable to build for a different architecture, for example | ||
| 55 | # if you want to cross-compile or to use the portable version. | ||
| 56 | # The value must be one of "AVX2", "NEON", "PORTABLE". If the value is not | ||
| 57 | # specified, the script will automatically detect the best architecture for the | ||
| 58 | # system. The architecture "PORTABLE" will work on any system. | ||
| 59 | ARCH=${ARCH-${NISSY_BUILD_ARCH}} | ||
| 60 | |||
| 61 | greparch() { | ||
| 62 | $CC -march=native -dM -E - </dev/null 2>/dev/null | grep "$1" | ||
| 63 | } | ||
| 64 | |||
| 65 | detectarch() { | ||
| 66 | [ -n "$(greparch __AVX2__)" ] && detected="AVX2" | ||
| 67 | [ -n "$(greparch __ARM_NEON)" ] && detected="NEON" | ||
| 68 | [ -z "$detected" ] && detected="PORTABLE" | ||
| 69 | echo "$detected" | ||
| 70 | } | ||
| 71 | |||
| 72 | [ -z "$ARCH" ] && ARCH="$(detectarch)" | ||
| 73 | |||
| 74 | # SANITIZE="option1,option2,..." adds the options "-fsanitize=option1", | ||
| 75 | # "-fsanitize=option2", ... to the C compiler command in debug mode. | ||
| 76 | # By default none is used because these options are not available on all | ||
| 77 | # systems. It is advisable to set the NISSY_BUILD_SANITIZE options in your | ||
| 78 | # shell's configuration file if your system does support them. | ||
| 79 | SANITIZE=${SANITIZE-${NISSY_BUILD_SANITIZE:-""}} | ||
| 80 | |||
| 81 | # Optimization flags. | ||
| 82 | OPTIMIZE=${OPTIMIZE-${NISSY_BUILD_OPTIMIZE:-"-O3"}} | ||
| 83 | |||
| 84 | validate_command() { | ||
| 85 | command="$1" | ||
| 86 | if ! (command -v "$command" >/dev/null 2>&1) ; then | ||
| 87 | echo "Error: command '$command' not found" | ||
| 88 | exit 1 | ||
| 89 | fi | ||
| 90 | } | ||
| 91 | |||
| 92 | validate_threads() { | ||
| 93 | threads="$1" | ||
| 94 | if [ "$threads" -le 0 ] || [ "$threads" -gt 128 ]; then | ||
| 95 | echo "Error: number of threads must be between 1 and 128" | ||
| 96 | exit 1 | ||
| 97 | fi | ||
| 98 | } | ||
| 99 | |||
| 100 | validate_arch() { | ||
| 101 | arch="$1" | ||
| 102 | case "$arch" in | ||
| 103 | AVX2|NEON|PORTABLE) | ||
| 104 | ;; | ||
| 105 | *) | ||
| 106 | echo "Error: architecture '$arch' not supported" | ||
| 107 | echo "Supported architectures: AVX2, NEON, PORTABLE" | ||
| 108 | exit 1 | ||
| 109 | ;; | ||
| 110 | esac | ||
| 111 | } | ||
| 112 | |||
| 113 | parsesanitize() { | ||
| 114 | # Use the user-specified comma-separated sanitizers | ||
| 115 | for opt in $(echo "$1" | tr ',' '\n'); do | ||
| 116 | printf -- '-fsanitize=%s ' "$opt" | ||
| 117 | done | ||
| 118 | } | ||
| 119 | |||
| 120 | maybe_pthread() { | ||
| 121 | if [ "$THREADS" -gt 1 ]; then | ||
| 122 | echo "-pthread" | ||
| 123 | else | ||
| 124 | echo "" | ||
| 125 | fi | ||
| 126 | } | ||
| 127 | |||
| 128 | # Build flags | ||
| 129 | CFLAGS="-std=c11 -fPIC -D_POSIX_C_SOURCE=199309L $(maybe_pthread)" | ||
| 130 | PYCFLAGS="-std=c11 -fPIC $(maybe_pthread)" | ||
| 131 | [ "$ARCH" = "AVX2" ] && CFLAGS="$CFLAGS -mavx2" | ||
| 132 | WFLAGS="-pedantic -Wall -Wextra -Wno-unused-parameter -Wno-unused-function" | ||
| 133 | OFLAGS="$OPTIMIZE" | ||
| 134 | DFLAGS="-DDEBUG -g3 $(parsesanitize "$SANITIZE")" | ||
| 135 | MFLAGS="-DTHREADS=$THREADS -D$ARCH" | ||
| 136 | CPPFLAGS="-std=c++20 $(maybe_pthread)" | ||
| 137 | |||
| 138 | # TODO: | ||
| 139 | # MEMORY64 is supported on Firefox (from version 134) and Chrome (from 133), | ||
| 140 | # but not on Safari (nor on e.g. Firefox 128 ESR, current default on Debian). | ||
| 141 | # See also https://webassembly.org/features | ||
| 142 | # When it becomes widely available, we can support it by adding -sMEMORY64 | ||
| 143 | # to the WASMCFLAGS, WASMCPPFLAGS and WASMLINKFLAGS variables below, and | ||
| 144 | # -sMAXIMUM_MEMORY=10737418240 to WASMLINKFLAGS. This way we can enable | ||
| 145 | # solvers larger than h48h6k2 in the web version. | ||
| 146 | |||
| 147 | # TODO: | ||
| 148 | # The options below have to be adjusted when native WASM_SIMD is implemented. | ||
| 149 | |||
| 150 | # Build flags for emscripten (WASM target) | ||
| 151 | WASMCFLAGS="-std=c11 -fPIC -D_POSIX_C_SOURCE=199309L $(maybe_pthread) | ||
| 152 | -mfpu=neon -mrelaxed-simd" | ||
| 153 | WASMCPPFLAGS="-std=c++20 $(maybe_pthread)" | ||
| 154 | WASMDBGFLAGS="-sASSERTIONS" | ||
| 155 | WASMMFLAGS="-DTHREADS=$THREADS -DNEON" | ||
| 156 | WASMLINKFLAGS="--no-entry -sEXPORT_NAME='Nissy' -sMODULARIZE | ||
| 157 | -sEXPORTED_RUNTIME_METHODS=addFunction,UTF8ToString | ||
| 158 | -sALLOW_TABLE_GROWTH | ||
| 159 | -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=5MB -sPTHREAD_POOL_SIZE=$THREADS | ||
| 160 | -sFETCH -sASYNCIFY -sLINKABLE -sEXPORT_ALL" | ||
| 161 | |||
| 162 | if (command -v "python3-config" >/dev/null 2>&1) ; then | ||
| 163 | PYTHON3_INCLUDES="$(python3-config --includes)" | ||
| 164 | PYTHON3="version $(echo "$PYTHON3_INCLUDES" | sed 's/.*3\./3./')" | ||
| 165 | else | ||
| 166 | PYTHON3_INCLUDES="" | ||
| 167 | PYTHON3="Not found, Python shell won't be available" | ||
| 168 | fi | ||
| 169 | |||
| 170 | build_help() { | ||
| 171 | echo "Build system for nissy. Usage:" | ||
| 172 | echo "" | ||
| 173 | echo "$0 [-d] TARGET # build the given TARGET" | ||
| 174 | echo "$0 [-d] # same as '$0 nissy [-d]'" | ||
| 175 | echo "$0 test [PATTERN] # run unit tests (matching PATTERN)" | ||
| 176 | echo "$0 webtest [PATTERN] # same as test, but for WASM build" | ||
| 177 | echo "$0 [-d] tool PATTERN # run the tool matching PATTERN" | ||
| 178 | echo "" | ||
| 179 | echo "targets:" | ||
| 180 | echo "" | ||
| 181 | echo "nissy Build the nissy.o object file" | ||
| 182 | echo "lib Build the static library libnissy.a" | ||
| 183 | echo "sharedlib Build the shared library libnissy.so" | ||
| 184 | echo "python Build the Python module for nissy" | ||
| 185 | echo "shell Build a basic nissy shell (./run)" | ||
| 186 | echo "web Build the WebAssembly / JavaScript module for nissy" | ||
| 187 | echo "cpp FILES Build and run the given FILES including cpp/nissy.h" | ||
| 188 | echo "solvetest Build nissy and run the tests for solvers (tools)" | ||
| 189 | echo "" | ||
| 190 | echo "help Show this help message" | ||
| 191 | echo "config Show build configuration and exit" | ||
| 192 | echo "clean Remove all build files" | ||
| 193 | echo "" | ||
| 194 | echo "The -d option activates debug mode (slower, used for testing)." | ||
| 195 | echo "Tests are automatically built in debug mode even without -d." | ||
| 196 | echo "For more on build configurations, see the comments in ./build" | ||
| 197 | } | ||
| 198 | |||
| 199 | build_config() { | ||
| 200 | echo "Compiler: $CC" | ||
| 201 | echo "Architecture: $ARCH" | ||
| 202 | echo "Max threads: $THREADS" | ||
| 203 | echo "Optimization options: $OFLAGS" | ||
| 204 | echo "Debug flags: $DFLAGS" | ||
| 205 | echo "" | ||
| 206 | |||
| 207 | echo "Optional features:" | ||
| 208 | |||
| 209 | printf '%s' "WASM compiler: " | ||
| 210 | if (validate_command "$EMCC" >/dev/null); then | ||
| 211 | echo "$EMCC" | ||
| 212 | else | ||
| 213 | echo "Not found, web target won't be available" | ||
| 214 | fi | ||
| 215 | |||
| 216 | printf '%s' "nodejs executable: " | ||
| 217 | if (validate_command "$NODE" >/dev/null); then | ||
| 218 | echo "$NODE" | ||
| 219 | else | ||
| 220 | echo "Not found, unit tests won't be available for web target" | ||
| 221 | fi | ||
| 222 | |||
| 223 | echo "Python bindings: $PYTHON3" | ||
| 224 | } | ||
| 225 | |||
| 226 | run() { | ||
| 227 | echo "$@" | ||
| 228 | $@ | ||
| 229 | } | ||
| 230 | |||
| 231 | odflags() { | ||
| 232 | if [ "$debug" = "yes" ]; then | ||
| 233 | echo "$DFLAGS" | ||
| 234 | else | ||
| 235 | echo "$OFLAGS" | ||
| 236 | fi | ||
| 237 | } | ||
| 238 | |||
| 239 | build_clean() { | ||
| 240 | run rm -rf -- *.o *.so *.a run runtest runtool runcpp \ | ||
| 241 | web/nissy_web_module.* web/http/nissy_web_module.* | ||
| 242 | } | ||
| 243 | |||
| 244 | build_nissy() { | ||
| 245 | validate_command "$CC" | ||
| 246 | validate_threads "$THREADS" | ||
| 247 | validate_arch "$ARCH" | ||
| 248 | |||
| 249 | run $CC $CFLAGS $WFLAGS $MFLAGS $(odflags) -c -o nissy.o src/nissy.c | ||
| 250 | } | ||
| 251 | |||
| 252 | build_lib() { | ||
| 253 | build_nissy | ||
| 254 | run ar rcs libnissy.a nissy.o | ||
| 255 | } | ||
| 256 | |||
| 257 | build_sharedlib() { | ||
| 258 | validate_command "$CC" | ||
| 259 | validate_threads "$THREADS" | ||
| 260 | validate_arch "$ARCH" | ||
| 261 | |||
| 262 | run $CC $CFLAGS $WFLAGS $MFLAGS $(odflags) -shared -c -o nissy.o \ | ||
| 263 | src/nissy.c | ||
| 264 | } | ||
| 265 | |||
| 266 | build_shell() { | ||
| 267 | build_nissy || exit 1 | ||
| 268 | run $CC $CFLAGS $WFLAGS $(odflags) -o run nissy.o shell/shell.c | ||
| 269 | } | ||
| 270 | |||
| 271 | build_python() { | ||
| 272 | if [ -z "$PYTHON3_INCLUDES" ]; then | ||
| 273 | echo "Python3 development headers could not be located" | ||
| 274 | echo "Cannot build python module" | ||
| 275 | exit 1 | ||
| 276 | fi | ||
| 277 | if [ "$debug" = "yes" ]; then | ||
| 278 | echo "Cannot build Python library in debug mode" | ||
| 279 | exit 1 | ||
| 280 | fi | ||
| 281 | build_nissy || exit 1 | ||
| 282 | run $CC $PYCFLAGS $WFLAGS $PYTHON3_INCLUDES $OFLAGS -shared \ | ||
| 283 | -o python/nissy.so nissy.o python/nissy_module.c | ||
| 284 | } | ||
| 285 | |||
| 286 | build_cpp() { | ||
| 287 | validate_command "$CXX" | ||
| 288 | if [ -z "$@" ]; then | ||
| 289 | echo "Please provide one or more valid C++ source files" | ||
| 290 | echo "usage: ./build cpp FILES" | ||
| 291 | fi | ||
| 292 | |||
| 293 | build_nissy || exit 1 | ||
| 294 | run $CXX $(odflags) -std=c++20 -o runcpp cpp/nissy.cpp nissy.o $@ \ | ||
| 295 | || exit 1 | ||
| 296 | run ./runcpp | ||
| 297 | } | ||
| 298 | |||
| 299 | build_web() { | ||
| 300 | validate_command "$EMCC" | ||
| 301 | validate_threads "$THREADS" | ||
| 302 | validate_arch "$ARCH" | ||
| 303 | |||
| 304 | obj="nissy_web_module" | ||
| 305 | |||
| 306 | if [ "$debug" = "yes" ]; then | ||
| 307 | ODFLAGS="$DFLAGS -sASSERTIONS" | ||
| 308 | else | ||
| 309 | ODFLAGS="$OFLAGS" | ||
| 310 | fi | ||
| 311 | |||
| 312 | run $EMCC $WASMCFLAGS $WFLAGS $WASMMFLAGS $ODFLAGS -c \ | ||
| 313 | -o nissy.o src/nissy.c || exit 1 | ||
| 314 | run $EMCC -lembind -lidbfs.js \ | ||
| 315 | $WASMCPPFLAGS $ODFLAGS $WASMLINKFLAGS -o web/"$obj".mjs \ | ||
| 316 | cpp/nissy.cpp web/storage.cpp web/adapter.cpp nissy.o || exit 1 | ||
| 317 | cp web/"$obj".mjs web/http/ | ||
| 318 | cp web/"$obj".wasm web/http/ | ||
| 319 | } | ||
| 320 | |||
| 321 | dotest() { | ||
| 322 | testout="test/last.out" | ||
| 323 | testerr="test/last.err" | ||
| 324 | |||
| 325 | # Verify that $t is a directory and it starts with three digits | ||
| 326 | if [ ! -d "$t" ] || ! (basename "$t" | grep -Eq '^[0-9]{3}'); then | ||
| 327 | return 0 | ||
| 328 | fi | ||
| 329 | |||
| 330 | # Verify that the test is selected by the given pattern | ||
| 331 | if [ -n "$pattern" ] && ! (echo "$t" | grep -q "$pattern"); then | ||
| 332 | return 0 | ||
| 333 | fi | ||
| 334 | |||
| 335 | $testbuild "$t"/*.c nissy.o || exit 1 | ||
| 336 | for cin in "$t"/*.in; do | ||
| 337 | c="$(echo "$cin" | sed 's/\.in//')" | ||
| 338 | cout="$c.out" | ||
| 339 | printf '%s: ' "$c" | ||
| 340 | $testrun < "$cin" > "$testout" 2> "$testerr" | ||
| 341 | if diff "$cout" "$testout"; then | ||
| 342 | printf "OK\n" | ||
| 343 | else | ||
| 344 | printf "Test failed! stderr:\n" | ||
| 345 | cat "$testerr" | ||
| 346 | exit 1 | ||
| 347 | fi | ||
| 348 | done | ||
| 349 | } | ||
| 350 | |||
| 351 | build_test_generic() { | ||
| 352 | if [ -n "$1" ]; then | ||
| 353 | pattern="$1" | ||
| 354 | shift | ||
| 355 | fi | ||
| 356 | debug="yes" | ||
| 357 | build_$obj || exit 1 | ||
| 358 | for t in test/*; do | ||
| 359 | dotest || exit 1 | ||
| 360 | done | ||
| 361 | echo "All tests passed!" | ||
| 362 | } | ||
| 363 | |||
| 364 | build_test() { | ||
| 365 | obj="nissy" | ||
| 366 | testobj="runtest" | ||
| 367 | testbuild="$CC $CFLAGS $WFLAGS $DFLAGS $MFLAGS -o $testobj" | ||
| 368 | testrun="./$testobj" | ||
| 369 | build_test_generic $@ | ||
| 370 | rm -f runtest | ||
| 371 | } | ||
| 372 | |||
| 373 | build_webtest() { | ||
| 374 | obj="web" | ||
| 375 | testobj="runtest.js" | ||
| 376 | testbuild="$EMCC $WASMCFLAGS $WFLAGS $WASMMFLAGS $DFLAGS \ | ||
| 377 | -sSTACK_SIZE=5MB -o $testobj" | ||
| 378 | testrun="$NODE $testobj" | ||
| 379 | build_test_generic $@ | ||
| 380 | rm -f runtest.js runtest.wasm | ||
| 381 | } | ||
| 382 | |||
| 383 | run_single_tool() { | ||
| 384 | results="tools/results" | ||
| 385 | last="$results/last.out" | ||
| 386 | date="$(date +'%Y-%m-%d-%H-%M-%S')" | ||
| 387 | file="$results/$toolname-$date.txt" | ||
| 388 | failed="tools/failed" | ||
| 389 | |||
| 390 | $CC $CFLAGS $WFLAGS $MFLAGS $(odflags) -o runtool "$t"/*.c nissy.o \ | ||
| 391 | || exit 1 | ||
| 392 | |||
| 393 | ( | ||
| 394 | date +'%Y-%m-%d %H:%M' | ||
| 395 | echo "" | ||
| 396 | echo "=========== Running tool ===========" | ||
| 397 | echo "tool name: $toolname" | ||
| 398 | echo "" | ||
| 399 | echo "======== nissy build command ========" | ||
| 400 | echo "$CC $CFLAGS $WFLAGS $MFLAGS $(odflags)" | ||
| 401 | echo "" | ||
| 402 | echo "======== tool build command ========" | ||
| 403 | echo "$CC $CFLAGS $WFLAGS $MFLAGS $(odflags)" | ||
| 404 | echo "" | ||
| 405 | echo "============ tool output ============" | ||
| 406 | ./runtool $@ || touch "$failed" | ||
| 407 | ) | tee "$file" "$last" | ||
| 408 | |||
| 409 | rm -f runtool | ||
| 410 | if [ -f "$failed" ]; then | ||
| 411 | rm "$failed" | ||
| 412 | exit 1 | ||
| 413 | fi | ||
| 414 | } | ||
| 415 | |||
| 416 | build_tool() { | ||
| 417 | pattern="$1" | ||
| 418 | |||
| 419 | if [ -z "$pattern" ]; then | ||
| 420 | echo "Please provide a valid PATTERN to select a tool" | ||
| 421 | echo "usage: ./build tool PATTERN" | ||
| 422 | exit 1 | ||
| 423 | fi | ||
| 424 | shift | ||
| 425 | |||
| 426 | # Select a single tool matched by the given pattern | ||
| 427 | for t in tools/*; do | ||
| 428 | if [ -d "$t" ] && (echo "$t" | grep -q "$pattern"); then | ||
| 429 | toolname="$(basename "$t" .c)" | ||
| 430 | break | ||
| 431 | fi | ||
| 432 | done | ||
| 433 | if [ -z "$toolname" ]; then | ||
| 434 | echo "pattern '$pattern' does not match any tool" | ||
| 435 | exit 1 | ||
| 436 | fi | ||
| 437 | |||
| 438 | build_nissy || exit 1 | ||
| 439 | run_single_tool $@ | ||
| 440 | } | ||
| 441 | |||
| 442 | build_solvetest() { | ||
| 443 | build_nissy || exit 1 | ||
| 444 | for t in tools/*; do | ||
| 445 | if [ -d "$t" ] && (echo "$t" | grep -q "solvetest"); then | ||
| 446 | toolname="$(basename "$t" .c)" | ||
| 447 | run_single_tool || exit 1 | ||
| 448 | fi | ||
| 449 | done | ||
| 450 | } | ||
| 451 | |||
| 452 | if [ "$1" = "-d" ]; then | ||
| 453 | debug="yes" | ||
| 454 | shift | ||
| 455 | fi | ||
| 456 | |||
| 457 | target="$1" | ||
| 458 | if [ -z "$target" ]; then | ||
| 459 | target="nissy" | ||
| 460 | else | ||
| 461 | shift | ||
| 462 | fi | ||
| 463 | |||
| 464 | case "$target" in | ||
| 465 | help|config|clean|\ | ||
| 466 | nissy|lib|sharedlib|shell|python|cpp|web|test|webtest|tool|solvetest) | ||
| 467 | mkdir -p tables tools/results | ||
| 468 | (build_"$target" $@) || exit 1 | ||
| 469 | exit 0 | ||
| 470 | ;; | ||
| 471 | *) | ||
| 472 | echo "Target '$target' unavailable, run '$0 help' for info" | ||
| 473 | exit 1 | ||
| 474 | ;; | ||
| 475 | esac | ||
