• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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