1 # Copyright (c) 2021-2022 Huawei Device Co., Ltd. 2 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # you may not use this file except in compliance with the License. 4 # You may obtain a copy of the License at 5 # 6 # http://www.apache.org/licenses/LICENSE-2.0 7 # 8 # Unless required by applicable law or agreed to in writing, software 9 # distributed under the License is distributed on an "AS IS" BASIS, 10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 # See the License for the specific language governing permissions and 12 # limitations under the License. 13 14 # Add a panda assembly to the project using the specified source file 15 # 16 # Example usage: 17 # 18 # add_panda_assembly(TARGET <name> SOURCE <source> INDIR <input directory> OUTDIR <output directory> TARGETNAME <target file name>) 19 # 20 # Adds a panda assembly target called <name> to be build from <source> file 21 # listed in the command invocation. 22 function(add_panda_assembly) 23 set(prefix ARG) 24 set(noValues) 25 set(singleValues TARGET SOURCE INDIR OUTDIR TARGETNAME) 26 set(multiValues) 27 cmake_parse_arguments(${prefix} 28 "${noValues}" 29 "${singleValues}" 30 "${multiValues}" 31 ${ARGN}) 32 if (NOT DEFINED ARG_TARGET) 33 message(FATAL_ERROR "Mandatory TARGET argument is not defined.") 34 endif() 35 36 if (NOT DEFINED ARG_SOURCE) 37 message(FATAL_ERROR "Mandatory SOURCE argument is not defined.") 38 endif() 39 40 set(source_file_dir "${CMAKE_CURRENT_SOURCE_DIR}") 41 42 if (DEFINED ARG_INDIR) 43 set(source_file_dir "${ARG_INDIR}") 44 endif() 45 46 set(binary_file_dir "${CMAKE_CURRENT_BINARY_DIR}") 47 48 if (DEFINED ARG_OUTDIR) 49 set(binary_file_dir "${ARG_OUTDIR}") 50 endif() 51 52 set(target_file_name "${ARG_TARGET}") 53 54 if (DEFINED ARG_TARGETNAME) 55 set(target_file_name "${ARG_TARGETNAME}") 56 endif() 57 58 if (TARGET ARG_TARGET) 59 message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") 60 endif() 61 62 set(source_file "${source_file_dir}/${ARG_SOURCE}") 63 set(binary_file "${binary_file_dir}/${target_file_name}.abc") 64 65 if(CMAKE_CROSSCOMPILING) 66 ExternalProject_Get_Property(panda_host_tools binary_dir) 67 set(assembler_target panda_host_tools-build) 68 set(assembler_bin "${binary_dir}/assembler/ark_asm") 69 else() 70 set(assembler_target ark_asm) 71 set(assembler_bin $<TARGET_FILE:${assembler_target}>) 72 endif() 73 74 add_custom_command(OUTPUT "${binary_file}" 75 COMMENT "Building ${ARG_TARGET}" 76 COMMAND "${assembler_bin}" "${source_file}" "${binary_file}" 77 DEPENDS ${assembler_target} "${source_file}") 78 79 add_custom_target(${ARG_TARGET} DEPENDS "${binary_file}") 80 set_target_properties(${ARG_TARGET} PROPERTIES FILE "${binary_file}") 81 endfunction() 82 83 # Use `mkdir` instead of `file(MAKE_DIRECTORY)` to create dependency on the directory existence: 84 set(COMPILER_STATS_DIR "${CMAKE_BINARY_DIR}/compiler/stats/csv") 85 add_custom_target(compiler_stats_dir 86 COMMAND mkdir -p "${COMPILER_STATS_DIR}") 87 88 # Add a single buildable and runnable Panda Assembly file to the build tree. 89 # 90 # Usage: 91 # 92 # panda_add_asm_file( 93 # FILE <source> 94 # TARGET <target> 95 # [ENTRY <entry_point>] 96 # [SUBDIR <subdir>] 97 # [OUTPUT_FILE_VARIABLE <variable>] 98 # [ERROR_FILE_VARIABLE <variable>] 99 # [SKIP_BUILD TRUE|FALSE] 100 # [AOT_MODE TRUE|FALSE] 101 # [AOT_STATS TRUE|FALSE] 102 # [AOT_COMPILER aot|llvm] 103 # [DEPENDS <dependency>...] 104 # [RUNTIME_OPTIONS <option>...] 105 # [RUNTIME_FAIL_TEST] 106 # [COMPILER_OPTIONS <option>...] 107 # [AOT_GC_OPTION <option>] 108 # [ENTRY_ARGUMENTS <argument>...] 109 # [TIMEOUT <timeout>] 110 # [LANGUAGE_CONTEXT <language>] 111 # ) 112 # 113 # Adds a target <target> which assembles the assembly file <source> 114 # with Panda assembler and runs it with Panda interpreter. 115 # 116 # Options: 117 # 118 # ENTRY 119 # Entry point to execute in format <Class>::<method>. By default _GLOBAL::main is used 120 # 121 # SUBDIR 122 # Subdirectory in the current binary directory that is used to store build artifacts. 123 # Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target> 124 # 125 # OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE 126 # The variable named will be set with the paths to files with contents of the stdout and 127 # stderr of the program respectively 128 # 129 # SKIP_BUILD 130 # Do not run assembly 131 # 132 # AOT_MODE 133 # Run test in AOT mode 134 # 135 # AOT_STATS 136 # Creates additional independent target `${TARGET}-stats`. 137 # `stats`-target dumps AOT compiler statistics in `${COMPILER_STATS_DIR}/${TARGET}.csv` 138 # 139 # DEPENDS 140 # List of additional dependences (exclude assembler and interpreter) 141 # 142 # RUNTIME_OPTIONS 143 # Runtime options 144 # 145 # RUNTIME_FAIL_TEST 146 # runtime is expected to fail 147 # 148 # COMPILER_OPTIONS 149 # Options for compiler, given both to panda and paoc 150 # 151 # ASSEMBLER_OPTIONS 152 # Options for assembler 153 # 154 # AOT_GC_OPTION 155 # Type of a gc 156 # 157 # ENTRY_ARGUMENTS 158 # List of arguments that will be passed to program's entry point 159 # 160 # TIMEOUT 161 # If specified, the program will be run and terminated with the signal 10 (corresponds 162 # to SIGUSR1 on most platforms) after the given timeout. The format of the value 163 # must match the `timeout` command. The run will be considered successful if the program 164 # exits before the timeout with the successful exit code or if it is terminated 165 # after the timeout with the signal 10. 166 # 167 # LANGUAGE_CONTEXT 168 # Set the language-dependent semantics for the code. Possible values: core, java. 169 # 170 function(panda_add_asm_file) 171 set(prefix ARG) 172 set(noValues RUNTIME_FAIL_TEST) 173 set(singleValues FILE ENTRY TARGET SUBDIR OUTPUT_FILE_VARIABLE ERROR_FILE_VARIABLE SKIP_BUILD AOT_MODE AOT_STATS AOT_COMPILER TIMEOUT LANGUAGE_CONTEXT AOT_GC_OPTION) 174 set(multiValues DEPENDS RUNTIME_OPTIONS COMPILER_OPTIONS ENTRY_ARGUMENTS PRLIMIT_OPTIONS ADDITIONAL_STDLIBS LLVMAOT_OPTIONS ASSEMBLER_OPTIONS) 175 cmake_parse_arguments(${prefix} 176 "${noValues}" 177 "${singleValues}" 178 "${multiValues}" 179 ${ARGN}) 180 181 if (NOT DEFINED ARG_FILE) 182 message(FATAL_ERROR "Mandatory FILE argument is not defined.") 183 endif() 184 185 if (NOT DEFINED ARG_TARGET) 186 message(FATAL_ERROR "Mandatory TARGET argument is not defined.") 187 endif() 188 189 if (TARGET ARG_TARGET) 190 message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") 191 endif() 192 193 set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}") 194 set(build_log "${build_dir}/build.log") 195 set(build_out "${build_dir}/build.out") 196 set(build_err "${build_dir}/build.err") 197 set(binary_file "${build_dir}/test.abc") 198 set(launch_file "${build_dir}/launch.sh") 199 set(output_file "${build_dir}/run.out") 200 set(error_file "${build_dir}/run.err") 201 202 file(MAKE_DIRECTORY "${build_dir}") 203 204 if (DEFINED ARG_OUTPUT_FILE_VARIABLE) 205 set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE) 206 endif() 207 208 if (DEFINED ARG_ERROR_FILE_VARIABLE) 209 set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE) 210 endif() 211 212 if (ARG_SKIP_BUILD) 213 set(binary_file "${ARG_FILE}") 214 else() 215 set(assembler ark_asm) 216 add_custom_command(OUTPUT "${binary_file}" 217 COMMENT "Building ${ARG_TARGET}" 218 COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> ${ARG_ASSEMBLER_OPTIONS} --verbose --log-file "${build_log}" "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}" 219 DEPENDS ${assembler} "${ARG_FILE}") 220 endif() 221 222 if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "") 223 set(timeout_signal 10) 224 set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}") 225 set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]") 226 else() 227 set(timeout_prefix "") 228 set(timeout_suffix "") 229 endif() 230 231 if (NOT DEFINED ARG_ENTRY) 232 set(ARG_ENTRY "_GLOBAL::main") 233 endif() 234 235 set(panda_stdlib arkstdlib) 236 set(panda_cli ark) 237 set(context "${ARG_LANGUAGE_CONTEXT}") 238 set(stdlibs) 239 240 if ("${context}" STREQUAL "core") 241 list(APPEND stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc") 242 endif() 243 if (DEFINED ARG_ADDITIONAL_STDLIBS) 244 list(APPEND stdlibs ${ARG_ADDITIONAL_STDLIBS}) 245 endif() 246 string(REPLACE ";" ":" boot_stdlibs "${stdlibs}") 247 248 if (ARG_AOT_MODE) 249 set(aot_compiler ark_aot) 250 set(backend_compiler "aot") 251 if (DEFINED ARG_AOT_COMPILER) 252 set(backend_compiler ${ARG_AOT_COMPILER}) 253 endif() 254 set(launch_aot_file "${build_dir}/launch_aot.sh") 255 set(aot_file "${build_dir}/test.an") 256 set(aot_file_stats "${build_dir}/test_stats.an") 257 set(launcher_aot 258 "${PANDA_RUN_PREFIX}" 259 "$<TARGET_FILE:${aot_compiler}>" 260 "--paoc-mode=${backend_compiler}" 261 "--boot-panda-files \"${boot_stdlibs}\"" 262 "--load-runtimes=${context}" 263 "--paoc-panda-files \"${binary_file}\"" 264 "--paoc-output \"${aot_file}\"" 265 "--compiler-ignore-failures=false" 266 "${ARG_COMPILER_OPTIONS}" 267 "${ARG_LLVMAOT_OPTIONS}" 268 "${ARG_AOT_GC_OPTION}" 269 "1>>\"${build_out}\"" 270 "2>>\"${build_err}\"" 271 ) 272 string(REPLACE ";" " " launcher_aot "${launcher_aot}") 273 file(GENERATE OUTPUT ${launch_aot_file} CONTENT "${launcher_aot}") 274 275 # TODO(msherstennikov): enable for arm64 276 # Problem in arm64 is that ark_aotdump cannot open aot elf file with error: "undefined symbol: aot" 277 if (NOT PANDA_MINIMAL_VIXL AND PANDA_TARGET_AMD64) 278 set(aotdump_command 279 "${PANDA_RUN_PREFIX}" 280 "$<TARGET_FILE:ark_aotdump>" 281 "--output-file=/dev/null" 282 "--show-code" "disasm" 283 "${aot_file}") 284 endif() 285 286 set(aot_compile_depends "${aot_compiler}" "${binary_file}") 287 if (NOT PANDA_MINIMAL_VIXL) 288 list(APPEND aot_compile_depends "ark_aotdump") 289 endif() 290 291 add_custom_command(OUTPUT "${aot_file}" 292 COMMENT "Running aot compiler for ${ARG_TARGET}" 293 COMMAND . ${launch_aot_file} || (cat ${build_err} && echo "Command: " && cat ${launch_aot_file} && false) 294 COMMAND ${aotdump_command} 295 DEPENDS ${aot_compile_depends}) 296 list(APPEND ARG_RUNTIME_OPTIONS "--aot-file=${aot_file}") 297 298 if (ARG_AOT_STATS) 299 set(launch_aot_stats_file "${build_dir}/launch_aot_stats.sh") 300 set(launcher_aot_stats 301 "${PANDA_RUN_PREFIX}" 302 "$<TARGET_FILE:${aot_compiler}>" 303 "--boot-panda-files \"${boot_stdlibs}\"" 304 "--load-runtimes=${context}" 305 "--paoc-panda-files \"${binary_file}\"" 306 "--paoc-output \"${aot_file_stats}\"" 307 "--compiler-ignore-failures=false" 308 "--compiler-dump-stats-csv=\"${COMPILER_STATS_DIR}/${ARG_TARGET}.csv\"" 309 "${ARG_COMPILER_OPTIONS}" 310 "${ARG_AOT_GC_OPTION}" 311 "1>>\"${build_out}\"" 312 "2>>\"${build_err}\"" 313 ) 314 string(REPLACE ";" " " launcher_aot_stats "${launcher_aot_stats}") 315 file(GENERATE OUTPUT ${launch_aot_stats_file} CONTENT "${launcher_aot_stats}") 316 add_custom_target(${ARG_TARGET}-stats 317 COMMENT "Gathering AOT-statistics for ${ARG_TARGET}" 318 COMMAND . ${launch_aot_stats_file} 319 DEPENDS ${aot_compiler} "${binary_file}" compiler_stats_dir) 320 endif() 321 endif() 322 323 # NB! The lines below imply that we cannot handle ";" properly 324 # in both Panda's own options and the runned program's options. 325 # TODO: Fix this once this becomes an issue. 326 string(REPLACE ";" " " runtime_options "${ARG_COMPILER_OPTIONS} ${ARG_RUNTIME_OPTIONS}") 327 string(REPLACE ";" " " entry_arguments "${ARG_ENTRY_ARGUMENTS}") 328 329 set(prlimit_cmd "") 330 if (DEFINED ARG_PRLIMIT_OPTIONS) 331 set(prlimit_cmd "prlimit ${ARG_PRLIMIT_OPTIONS}") 332 string(REPLACE ";" " " prlimit_cmd "${prlimit_cmd}") 333 endif() 334 335 if (${runtime_options} MATCHES ".*events-output=csv.*") 336 set(runtime_options "${runtime_options} --events-file=${build_dir}/events.csv") 337 endif() 338 339 set(launcher 340 "${timeout_prefix}" 341 "${prlimit_cmd}" 342 "${PANDA_RUN_PREFIX}" 343 $<TARGET_FILE:${panda_cli}> 344 "--boot-panda-files \"${boot_stdlibs}\"" 345 "--load-runtimes=${context}" 346 "--compiler-ignore-failures=false" 347 "${runtime_options}" 348 "\"${binary_file}\"" 349 "\"${ARG_ENTRY}\"" 350 "${entry_arguments}" 351 "1>\"${output_file}\"" 352 "2>\"${error_file}\"" 353 "${timeout_suffix}" 354 ) 355 string(REPLACE ";" " " launcher "${launcher}") 356 if (ARG_RUNTIME_FAIL_TEST) 357 string(APPEND launcher " || (exit 0)") 358 endif() 359 file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher}") 360 361 add_custom_target(${ARG_TARGET} 362 COMMENT "Running ${ARG_TARGET}" 363 COMMAND . ${launch_file} || (cat ${error_file} && false) 364 DEPENDS ${panda_cli} "${binary_file}" ${aot_file}) 365 366 if (DEFINED ARG_DEPENDS) 367 add_dependencies(${ARG_TARGET} ${ARG_DEPENDS}) 368 endif() 369 if ("${context}" STREQUAL "core") 370 add_dependencies(${ARG_TARGET} ${panda_stdlib}) 371 endif() 372 373 endfunction() 374 375 # Add a single buildable and verifiable Panda Assembly file to the build tree. 376 # 377 # Usage: 378 # 379 # verifier_add_asm_file( 380 # FILE <source> 381 # TARGET <target> 382 # [RUNTIME_OPTIONS <runtime options>] 383 # [VERIFIER_OPTIONS <verifier options>] 384 # [SUBDIR <subdir>] 385 # [OUTPUT_FILE_VARIABLE <variable>] 386 # [ERROR_FILE_VARIABLE <variable>] 387 # [DEPENDS <dependency>...] 388 # [TIMEOUT <timeout>] 389 # [LANGUAGE_CONTEXT <language>] 390 # ) 391 # 392 # Adds a target <target> which assembles the assembly file <source> 393 # with Panda assembler and verifies it with verifier. 394 # 395 # Options: 396 # 397 # SUBDIR 398 # Subdirectory in the current binary directory that is used to store build artifacts. 399 # Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target> 400 # 401 # OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE 402 # The variable named will be set with the paths to files with contents of the stdout and 403 # stderr of the program respectively 404 # 405 # DEPENDS 406 # List of additional dependences (exclude assembler and interpreter) 407 # 408 # RUNTIME_OPTIONS 409 # Runtime initialization options 410 # 411 # VERIFIER_OPTIONS 412 # Verifier CLI options 413 # 414 # VERIFIER_FAIL_TEST 415 # If true, verifier is allowed to exit with non-0 exit code 416 # 417 # TIMEOUT 418 # If specified, the program will be run and terminated with the signal 10 (corresponds 419 # to SIGUSR1 on most platforms) after the given timeout. The format of the value 420 # must match the `timeout` command. The run will be considered successful if the program 421 # exits before the timeout with the successful exit code or if it is terminated 422 # after the timeout with the signal 10. 423 # 424 # LANGUAGE_CONTEXT 425 # Set the language-dependent semantics for the code. Possible values: core, java. 426 # 427 function(verifier_add_asm_file) 428 set(prefix ARG) 429 set(noValues VERIFIER_FAIL_TEST) 430 set(singleValues 431 FILE 432 TARGET 433 SUBDIR 434 OUTPUT_FILE_VARIABLE 435 ERROR_FILE_VARIABLE 436 TIMEOUT 437 LANGUAGE_CONTEXT) 438 set(multiValues DEPENDS RUNTIME_OPTIONS VERIFIER_OPTIONS STDLIBS) 439 cmake_parse_arguments(${prefix} 440 "${noValues}" 441 "${singleValues}" 442 "${multiValues}" 443 ${ARGN}) 444 445 if (NOT DEFINED ARG_FILE) 446 message(FATAL_ERROR "Mandatory FILE argument is not defined.") 447 endif() 448 449 if (NOT DEFINED ARG_TARGET) 450 message(FATAL_ERROR "Mandatory TARGET argument is not defined.") 451 endif() 452 453 if (TARGET ARG_TARGET) 454 message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") 455 endif() 456 457 set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}") 458 set(build_out "${build_dir}/build.out") 459 set(build_err "${build_dir}/build.err") 460 set(binary_file "${build_dir}/test.abc") 461 set(launch_file "${build_dir}/verifier_launch.sh") 462 set(output_file "${build_dir}/verify.out") 463 set(error_file "${build_dir}/verify.err") 464 465 file(MAKE_DIRECTORY "${build_dir}") 466 467 if (DEFINED ARG_OUTPUT_FILE_VARIABLE) 468 set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE) 469 endif() 470 471 if (DEFINED ARG_ERROR_FILE_VARIABLE) 472 set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE) 473 endif() 474 475 set(assembler ark_asm) 476 add_custom_command(OUTPUT "${binary_file}" 477 COMMENT "Building ${ARG_TARGET}" 478 COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}" 479 DEPENDS ${assembler} "${ARG_FILE}") 480 481 if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "") 482 set(timeout_signal 10) 483 set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}") 484 set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]") 485 else() 486 set(timeout_prefix "") 487 set(timeout_suffix "") 488 endif() 489 490 set(panda_stdlib arkstdlib) 491 set(verifier_cli verifier) 492 493 set(spaces "core") 494 if (NOT "core" STREQUAL "${ARG_LANGUAGE_CONTEXT}") 495 set(spaces "${ARG_LANGUAGE_CONTEXT}") 496 else() 497 set(stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc") 498 endif() 499 500 list(APPEND stdlibs ${ARG_STDLIBS}) 501 502 string(REPLACE ";" ":" boot_stdlibs "${stdlibs}") 503 string(REPLACE ";" ":" boot_spaces "${spaces}") 504 505 set(launcher_verifier 506 "${PANDA_RUN_PREFIX}" 507 $<TARGET_FILE:${verifier_cli}> 508 "${ARG_VERIFIER_OPTIONS}" 509 "${ARG_RUNTIME_OPTIONS}" 510 "--boot-panda-files=\"${boot_stdlibs}\"" 511 "--load-runtimes=${boot_spaces}" 512 "\"${binary_file}\"" 513 "1>\"${output_file}\"" 514 "2>\"${error_file}\"" 515 ) 516 string(REPLACE ";" " " launcher_verifier "${launcher_verifier}") 517 if (ARG_VERIFIER_FAIL_TEST) 518 string(APPEND launcher_verifier " || (exit 0)") 519 endif() 520 521 file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher_verifier}") 522 523 add_custom_target(${ARG_TARGET} 524 COMMENT "Verifying ${ARG_TARGET}" 525 COMMAND . ${launch_file} 526 DEPENDS ${verifier_cli} "${binary_file}") 527 528 if (DEFINED ARG_DEPENDS) 529 add_dependencies(${ARG_TARGET} ${ARG_DEPENDS}) 530 endif() 531 532 endfunction() 533