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