1# Copyright (c) 2021 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_target(${ARG_TARGET} 75 COMMENT "Building ${ARG_TARGET}" 76 COMMAND "${assembler_bin}" "${source_file}" "${binary_file}" 77 DEPENDS ${assembler_target} "${source_file}") 78endfunction() 79 80# Add a single buildable and runnable Panda Assembly file to the build tree. 81# 82# Usage: 83# 84# panda_add_asm_file( 85# FILE <source> 86# TARGET <target> 87# [ENTRY <entry_point>] 88# [SUBDIR <subdir>] 89# [OUTPUT_FILE_VARIABLE <variable>] 90# [ERROR_FILE_VARIABLE <variable>] 91# [SKIP_BUILD TRUE|FALSE] 92# [AOT_MODE TRUE|FALSE] 93# [DEPENDS <dependency>...] 94# [RUNTIME_OPTIONS <option>...] 95# [COMPILER_OPTIONS <option>...] 96# [GC_OPTIONS <option>] 97# [ENTRY_ARGUMENTS <argument>...] 98# [TIMEOUT <timeout>] 99# [LANGUAGE_CONTEXT <language>] 100# ) 101# 102# Adds a target <target> which assembles the assembly file <source> 103# with Panda assembler and runs it with Panda interpreter. 104# 105# Options: 106# 107# ENTRY 108# Entry point to execute in format <Class>::<method>. By default _GLOBAL::main is used 109# 110# SUBDIR 111# Subdirectory in the current binary directory that is used to store build artifacts. 112# Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target> 113# 114# OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE 115# The variable named will be set with the paths to files with contents of the stdout and 116# stderr of the program respectively 117# 118# DEPENDS 119# List of additional dependences (exclude assembler and interpreter) 120# 121# RUNTIME_OPTIONS 122# Runtime options 123# 124# COMPILER_OPTIONS 125# Options for compiler, given both to panda and paoc 126# 127# GC_OPTIONS 128# Type of a gc 129# 130# ENTRY_ARGUMENTS 131# List of arguments that will be passed to program's entry point 132# 133# TIMEOUT 134# If specified, the program will be run and terminated with the signal 10 (corresponds 135# to SIGUSR1 on most platforms) after the given timeout. The format of the value 136# must match the `timeout` command. The run will be considered successful if the program 137# exits before the timeout with the successful exit code or if it is terminated 138# after the timeout with the signal 10. 139# 140# LANGUAGE_CONTEXT 141# Set the language-dependent semantics for the code. Possible values: panda-assembly. 142# 143function(panda_add_asm_file) 144 set(prefix ARG) 145 set(noValues) 146 set(singleValues FILE ENTRY TARGET SUBDIR OUTPUT_FILE_VARIABLE ERROR_FILE_VARIABLE SKIP_BUILD AOT_MODE TIMEOUT LANGUAGE_CONTEXT GC_OPTIONS) 147 set(multiValues DEPENDS RUNTIME_OPTIONS COMPILER_OPTIONS ENTRY_ARGUMENTS PRLIMIT_OPTIONS ADDITIONAL_STDLIBS) 148 cmake_parse_arguments(${prefix} 149 "${noValues}" 150 "${singleValues}" 151 "${multiValues}" 152 ${ARGN}) 153 154 if (NOT DEFINED ARG_FILE) 155 message(FATAL_ERROR "Mandatory FILE argument is not defined.") 156 endif() 157 158 if (NOT DEFINED ARG_TARGET) 159 message(FATAL_ERROR "Mandatory TARGET argument is not defined.") 160 endif() 161 162 if (TARGET ARG_TARGET) 163 message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") 164 endif() 165 166 set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}") 167 set(build_log "${build_dir}/build.log") 168 set(build_out "${build_dir}/build.out") 169 set(build_err "${build_dir}/build.err") 170 set(binary_file "${build_dir}/test.abc") 171 set(launch_file "${build_dir}/launch.sh") 172 set(output_file "${build_dir}/run.out") 173 set(error_file "${build_dir}/run.err") 174 175 file(MAKE_DIRECTORY "${build_dir}") 176 177 if (DEFINED ARG_OUTPUT_FILE_VARIABLE) 178 set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE) 179 endif() 180 181 if (DEFINED ARG_ERROR_FILE_VARIABLE) 182 set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE) 183 endif() 184 185 if (ARG_SKIP_BUILD) 186 set(binary_file "${ARG_FILE}") 187 else() 188 set(assembler ark_asm) 189 add_custom_command(OUTPUT "${binary_file}" 190 COMMENT "Building ${ARG_TARGET}" 191 COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> --verbose --log-file "${build_log}" "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}" 192 DEPENDS ${assembler} "${ARG_FILE}") 193 endif() 194 195 if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "") 196 set(timeout_signal 10) 197 set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}") 198 set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]") 199 else() 200 set(timeout_prefix "") 201 set(timeout_suffix "") 202 endif() 203 204 if (NOT DEFINED ARG_ENTRY) 205 set(ARG_ENTRY "_GLOBAL::main") 206 endif() 207 208 set(panda_stdlib arkstdlib) 209 set(panda_cli ark) 210 set(panda_verifier verifier) 211 212 set(stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc") 213 if (DEFINED ARG_ADDITIONAL_STDLIBS) 214 list(APPEND stdlibs ${ARG_ADDITIONAL_STDLIBS}) 215 endif() 216 217 set(spaces "core") 218 set(runtime_type "core") 219 if (DEFINED ARG_LANGUAGE_CONTEXT AND NOT "${ARG_LANGUAGE_CONTEXT}" STREQUAL "panda-assembly") 220 list(APPEND spaces "${ARG_LANGUAGE_CONTEXT}") 221 set(runtime_type "${ARG_LANGUAGE_CONTEXT}") 222 endif() 223 224 string(REPLACE ";" ":" boot_stdlibs "${stdlibs}") 225 string(REPLACE ";" ":" boot_spaces "${spaces}") 226 227 # Note well! The lines below imply that we cannot handle ";" properly 228 # in both Panda's own options and the running program's options. 229 string(REPLACE ";" " " runtime_options "${ARG_COMPILER_OPTIONS} ${ARG_RUNTIME_OPTIONS}") 230 string(REPLACE ";" " " entry_arguments "${ARG_ENTRY_ARGUMENTS}") 231 232 set(prlimit_cmd "") 233 if (DEFINED ARG_PRLIMIT_OPTIONS) 234 set(prlimit_cmd "prlimit ${ARG_PRLIMIT_OPTIONS}") 235 string(REPLACE ";" " " prlimit_cmd "${prlimit_cmd}") 236 endif() 237 238 if (${runtime_options} MATCHES ".*events-output=csv.*") 239 set(runtime_options "${runtime_options} --events-file=${build_dir}/events.csv") 240 endif() 241 242 set(launcher 243 "${timeout_prefix}" 244 "${prlimit_cmd}" 245 "${PANDA_RUN_PREFIX}" 246 $<TARGET_FILE:${panda_cli}> 247 "--boot-panda-files \"${boot_stdlibs}\"" 248 "--boot-intrinsic-spaces=${boot_spaces}" 249 "--boot-class-spaces=${boot_spaces}" 250 "--runtime-type=${runtime_type}" 251 "${runtime_options}" 252 "\"${binary_file}\"" 253 "\"${ARG_ENTRY}\"" 254 "${entry_arguments}" 255 "1>\"${output_file}\"" 256 "2>\"${error_file}\"" 257 "${timeout_suffix}" 258 ) 259 string(REPLACE ";" " " launcher "${launcher}") 260 file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher}") 261 262 add_custom_target(${ARG_TARGET} 263 COMMENT "Running ${ARG_TARGET}" 264 COMMAND . ${launch_file} || (cat ${error_file} && false) 265 DEPENDS ${panda_cli} ${panda_stdlib} "${binary_file}" ${aot_file}) 266 267 if (DEFINED ARG_DEPENDS) 268 add_dependencies(${ARG_TARGET} ${ARG_DEPENDS}) 269 endif() 270 271 272endfunction() 273 274# Add a single buildable and verifiable Panda Assembly file to the build tree. 275# 276# Usage: 277# 278# verifier_add_asm_file( 279# FILE <source> 280# TARGET <target> 281# [ENTRY <entry_point>] 282# [RUNTIME_OPTIONS <runtime options>] 283# [VERIFIER_OPTIONS <verifier options>] 284# [SUBDIR <subdir>] 285# [OUTPUT_FILE_VARIABLE <variable>] 286# [ERROR_FILE_VARIABLE <variable>] 287# [DEPENDS <dependency>...] 288# [TIMEOUT <timeout>] 289# [LANGUAGE_CONTEXT <language>] 290# ) 291# 292# Adds a target <target> which assembles the assembly file <source> 293# with Panda assembler and verifies it with verifier. 294# 295# Options: 296# 297# ENTRY 298# Entry point to execute in format <Class>::<method>. By default _GLOBAL::main is used 299# 300# SUBDIR 301# Subdirectory in the current binary directory that is used to store build artifacts. 302# Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target> 303# 304# OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE 305# The variable named will be set with the paths to files with contents of the stdout and 306# stderr of the program respectively 307# 308# DEPENDS 309# List of additional dependences (exclude assembler and interpreter) 310# 311# RUNTIME_OPTIONS 312# Runtime initialization options 313# 314# VERIFIER_OPTIONS 315# Verifier CLI options 316# 317# TIMEOUT 318# If specified, the program will be run and terminated with the signal 10 (corresponds 319# to SIGUSR1 on most platforms) after the given timeout. The format of the value 320# must match the `timeout` command. The run will be considered successful if the program 321# exits before the timeout with the successful exit code or if it is terminated 322# after the timeout with the signal 10. 323# 324# LANGUAGE_CONTEXT 325# Set the language-dependent semantics for the code. Possible values: panda-assembly. 326# 327function(verifier_add_asm_file) 328 set(prefix ARG) 329 set(noValues) 330 set(singleValues FILE ENTRY TARGET SUBDIR OUTPUT_FILE_VARIABLE ERROR_FILE_VARIABLE TIMEOUT LANGUAGE_CONTEXT) 331 set(multiValues DEPENDS RUNTIME_OPTIONS VERIFIER_OPTIONS) 332 cmake_parse_arguments(${prefix} 333 "${noValues}" 334 "${singleValues}" 335 "${multiValues}" 336 ${ARGN}) 337 338 if (NOT DEFINED ARG_FILE) 339 message(FATAL_ERROR "Mandatory FILE argument is not defined.") 340 endif() 341 342 if (NOT DEFINED ARG_TARGET) 343 message(FATAL_ERROR "Mandatory TARGET argument is not defined.") 344 endif() 345 346 if (TARGET ARG_TARGET) 347 message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") 348 endif() 349 350 set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}") 351 set(build_out "${build_dir}/build.out") 352 set(build_err "${build_dir}/build.err") 353 set(binary_file "${build_dir}/test.abc") 354 set(launch_file "${build_dir}/verifier_launch.sh") 355 set(output_file "${build_dir}/verify.out") 356 set(error_file "${build_dir}/verify.err") 357 358 file(MAKE_DIRECTORY "${build_dir}") 359 360 if (DEFINED ARG_OUTPUT_FILE_VARIABLE) 361 set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE) 362 endif() 363 364 if (DEFINED ARG_ERROR_FILE_VARIABLE) 365 set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE) 366 endif() 367 368 set(assembler ark_asm) 369 add_custom_command(OUTPUT "${binary_file}" 370 COMMENT "Building ${ARG_TARGET}" 371 COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}" 372 DEPENDS ${assembler} "${ARG_FILE}") 373 374 if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "") 375 set(timeout_signal 10) 376 set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}") 377 set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]") 378 else() 379 set(timeout_prefix "") 380 set(timeout_suffix "") 381 endif() 382 383 if (NOT DEFINED ARG_ENTRY) 384 set(ARG_ENTRY "_GLOBAL::main") 385 endif() 386 387 set(panda_stdlib arkstdlib) 388 set(verifier_cli ark) 389 390 set(stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc") 391 set(spaces "core") 392 set(runtime_type "core") 393 if (NOT DEFINED ARG_LANGUAGE_CONTEXT) 394 set(ARG_LANGUAGE_CONTEXT "panda-assembly") 395 endif() 396 397 string(REPLACE ";" ":" boot_stdlibs "${stdlibs}") 398 string(REPLACE ";" ":" boot_spaces "${spaces}") 399 400 if(NOT "${ARG_VERIFIER_OPTIONS}" STREQUAL "") 401 set(ARG_VERIFIER_OPTIONS ",${ARG_VERIFIER_OPTIONS}") 402 endif() 403 404 set(launcher_verifier 405 "${PANDA_RUN_PREFIX}" 406 $<TARGET_FILE:${verifier_cli}> 407 "--verification-enabled" 408 "--verification-options only-verify${ARG_VERIFIER_OPTIONS}" 409 "${ARG_RUNTIME_OPTIONS}" 410 "--boot-panda-files \"${boot_stdlibs}\"" 411 "--boot-intrinsic-spaces=${boot_spaces}" 412 "--boot-class-spaces=${boot_spaces}" 413 "--runtime-type=${runtime_type}" 414 "\"${binary_file}\"" 415 "\"${ARG_ENTRY}\"" 416 "1>\"${output_file}\"" 417 "2>\"${error_file}\"" 418 ) 419 string(REPLACE ";" " " launcher_verifier "${launcher_verifier}") 420 file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher_verifier}") 421 422 add_custom_target(${ARG_TARGET} 423 COMMENT "Verifying ${ARG_TARGET}" 424 COMMAND . ${launch_file} 425 DEPENDS ${verifier_cli} "${binary_file}") 426 427 if (DEFINED ARG_DEPENDS) 428 add_dependencies(${ARG_TARGET} ${ARG_DEPENDS}) 429 endif() 430 431endfunction() 432